Compare commits

..

1 Commits

Author SHA1 Message Date
Egutierrez 8917105184 chore(infra): audit_uses_functions detecta mejor simbolos Go con abreviaturas (issue 0057)
Reduce falsos positivos en la deteccion de simbolos Go del auditor
uses_functions, por dos vias complementarias.

Fase 1 — commonAbbrevs ampliado: anade abreviaturas verificadas contra los
nombres reales de las funciones Go del registry (OHLCV, DuckDB, ClickHouse,
NordVPN, SHA256, MD5, ANSI, CIDR, AEAD, PTY, VPS, WG, VT, FFT, EMA, RSI, SMA,
VWAP, AX, E2E, URLs). El analisis empirico mostro que reduce los mismatches
PascalCase-vs-real de 76 a 40 sin romper ninguna funcion. Se documenta por que
NO se mapean "cdp" (el registry usa Cdp: CdpGetHTML, CdpNavigate) ni "pdf"
(inconsistente: CdpPrintPDF vs PdfSimpleReport) — anadirlos generaria mas
falsos positivos de los que arregla.

Fase 2 — fallback a lectura del .go: cuando ni la signature ni PascalCase(name)
localizan el simbolo, se lee el .go de la funcion del registry y se extrae el
primer func exportado top-level (cache por ejecucion para no reabrir archivos).
El fallback esta GATEADO a signature vacia: cuando la signature ya aporta un
`func <Name>` es la fuente de verdad y no se sobreescribe. Esto evita la
mis-atribucion en archivos .go compartidos por varias funciones (patron "TU
adicional", p.ej. cdp_new_tab vive en cdp_list_tabs.go): sin el gate, el primer
func del archivo (CdpListTabs) se atribuiria a cada hermano y suprimiria
hallazgos reales de "unused".

Verificacion (DoD):
- go build -tags fts5 + go vet limpios.
- Tests nuevos: TestSnakeToPascal_HandlesAbbreviations (golden + non-mappings
  cdp/pdf), TestAuditUsesFunctions_GoFileFallback (golden + error sin archivo),
  TestAuditUsesFunctions_SharedGoFileNotMisattributed (regresion del archivo
  compartido), TestGoRealExportedName (top-level/generic/missing/empty).
- A/B contra el registry real (fn doctor uses-functions): baseline 69 unused vs
  nuevo 69, cero regresion; cdp_get_html_go_browser sigue sin marcarse unused en
  script_navegador (Fase 3.1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 13:14:27 +02:00
233 changed files with 639 additions and 19082 deletions
+10 -20
View File
@@ -25,10 +25,9 @@ Página madre del grupo: `docs/capabilities/eda.md` (léela primero para cargar
- `--models``run_models=True` (PCA/KMeans/IsolationForest/normalidad).
- `--llm``run_llm=True` (1 call LLM sobre el perfil agregado).
- `--series``run_series=True` (estacionariedad ADF+KPSS, ACF/PACF, STL, retornos por columna numérica).
- `--pdf``emit_pdf=True` (PDF A5 legacy de `render_eda_pdf`, legible en móvil).
- `--legacy-only` → emite SOLO el PDF legacy (sin AutomaticEDA), para casos en que solo se quiera el PDF rápido.
- `--pdf``emit_pdf=True` (PDF A5 vertical legible en móvil).
Por defecto, **un EDA completo emite SIEMPRE el informe AutomaticEDA en sus dos formatos: PDF (A5 móvil) Y PPTX (16:9 para compartir)** con los 11 capítulos poblados (portada, overview, distribuciones, calidad, correlaciones, modelos, series, geoespacial, agregación, interpretación LLM). Usa el pipeline `render_automatic_eda` (o `profile_table(emit_automatic=True)`), que activa `run_models` y `run_series` para que los capítulos de modelos/series/geoespacial/agregación salgan poblados. Deja `run_llm` para cuando el usuario lo pida o interese la interpretación semántica + narrativa por capítulo (es la única parte que gasta tokens del modelo).
Por defecto, para un EDA "completo" cuando el usuario no especifica, activa `run_models`, `run_series` y `emit_pdf`; deja `run_llm` para cuando lo pida o cuando interese la interpretación semántica (es la única parte que gasta tokens del modelo).
## Reglas duras
@@ -36,7 +35,7 @@ Por defecto, **un EDA completo emite SIEMPRE el informe AutomaticEDA en sus dos
2. **CSV/Parquet/Excel** entran cargándolos antes a DuckDB (`read_csv_auto`/`read_parquet`/`read_xlsx`) — DuckDB es el motor por defecto. No traigas la tabla entera a RAM.
3. **Secretos**: si la fuente es un DSN PostgreSQL con credenciales, NO las imprimas en los reports ni en el notebook; resuélvelas vía `resolve_pg_dsn`/`pass` cuando aplique.
4. **El report es un artefacto local**: vive en `reports/` (gitignored), no se sube a Gitea ni se versiona. Compartir = pasar la ruta (regla `reports.md`).
5. **Entrega las salidas**: el informe **AutomaticEDA PDF + PPTX** (siempre, con `render_automatic_eda` / `emit_automatic=True`) + (opcional) JSON sidecar + Markdown + PDF legacy + **notebook Jupyter colaborativo ejecutado en vivo**. Comparte las rutas de PDF y PPTX.
5. **Entrega las 4 salidas**: JSON sidecar + Markdown + **PDF móvil** + **notebook Jupyter colaborativo ejecutado en vivo**.
## Paso 1 — Perfilar y escribir los reports
@@ -44,26 +43,18 @@ Una tabla (caso normal):
```bash
PYTHONPATH=python/functions python/.venv/bin/python3 - <<'PYEOF'
from pipelines.render_automatic_eda import render_automatic_eda
# Informe AutomaticEDA COMPLETO one-shot: perfil + ctx (datos crudos) + PDF + PPTX
# con los 11 capítulos poblados (clusters pintados, evolución temporal, mapa,
# tablas de agregación). run_llm=True añade la narrativa LLM por capítulo.
r = render_automatic_eda(
from pipelines.profile_table import profile_table
r = profile_table(
"/ruta/datos.duckdb", "ventas",
run_models=True, run_series=True, run_llm=False, out_dir="reports",
run_models=True, run_series=True, emit_pdf=True, run_llm=False,
)
print("status:", r["status"])
print("pdf: ", r["pdf_path"], "(", r["n_pages"], "págs )")
print("pptx: ", r["pptx_path"], "(", r["n_slides"], "slides )")
print("manifest:", r["manifest_path"])
print("md: ", r["report_md_path"])
print("json: ", r["report_json_path"])
print("pdf: ", r["pdf_path"])
PYEOF
```
Si además quieres el report Markdown + JSON sidecar y/o el PDF legacy junto al
AutomaticEDA, usa `profile_table(emit_automatic=True, emit_pdf=True, write_report=True)`:
emite todo a la vez (`report_md_path`, `report_json_path`, `pdf_path` legacy,
`aeda_pdf_path`, `aeda_pptx_path`, `aeda_manifest_path`).
Una base entera (todas las tablas + relaciones FK):
```bash
@@ -99,7 +90,6 @@ Sigue la memoria `eda-workflow-registry` y la regla `notebook_collaboration.md`:
## Notas
- El `TableProfile` lleva ahora, además del perfilado base y las correlaciones con FDR: `series` (por columna numérica, con `run_series`), `reexpression` por columna numérica (escalera de Tukey) y `caveats` (siempre, avisos exploratorios). El Markdown y el PDF renderizan estas secciones automáticamente cuando están presentes.
- El informe **AutomaticEDA** (`render_automatic_eda` / `emit_automatic=True`) emite el MISMO documento por capítulos a **PDF (A5 móvil)** y **PPTX (16:9)** con garantía de no-corte (texto envuelto, tablas partidas repitiendo cabecera, figuras escaladas) y negrita real (`**texto**`). Escribe `automatic_eda_manifest.json` con la versión de cada capítulo. Los capítulos modelos/series/geoespacial/agregación se pueblan con los datos crudos que `build_eda_render_ctx` muestrea de la base (no se traen tablas enteras a RAM).
- El PDF legacy (`emit_pdf`, `render_eda_pdf`) sigue disponible y es independiente del AutomaticEDA (A5 vertical, gráficos Tufte). Se escribe junto al Markdown en `reports/`.
- El PDF (`emit_pdf`) está pensado para leerse en el móvil (A5 vertical, tipografía grande, gráficos Tufte). Se escribe junto al Markdown en `reports/`.
- `run_series` ordena por la primera columna datetime si existe; si no, por el orden físico de filas. Necesita ≥8 puntos válidos por columna.
- Fuentes: DuckDB (CSV/Parquet/Excel cargados antes) y PostgreSQL (`backend="postgres"`). `profile_database` (multi-tabla + FK) es solo DuckDB por ahora.
+2 -3
View File
@@ -31,13 +31,12 @@ Diferencia con `dev/flows/`:
**Fase 1 (manual via Claude):**
El agente lee `dev/issues/**/*.md` (recursivo: incluye subcarpetas por dominio como `dev/issues/kanban/`, `dev/issues/cpp/`, ... excluyendo `completed/`), parsea frontmatter YAML con `yaml.safe_load`, aplica el filtro, imprime tabla.
El agente lee `dev/issues/*.md`, parsea frontmatter YAML con `yaml.safe_load`, aplica el filtro, imprime tabla.
```python
import yaml, pathlib, re
issues = []
for f in pathlib.Path("dev/issues").glob("**/*.md"):
if f.parent.name == "completed": continue
for f in pathlib.Path("dev/issues").glob("*.md"):
if f.name in {"README.md", "template.md"}: continue
txt = f.read_text()
m = re.match(r"^---\n(.*?)\n---", txt, re.S)
+1 -3
View File
@@ -9,9 +9,7 @@
"enabledMcpjsonServers": [
"registry",
"jupyter",
"orchestrator",
"godot",
"ardour"
"orchestrator"
],
"hooks": {
"PreToolUse": [
+14 -35
View File
@@ -3,11 +3,11 @@ name: launch_fleetclaude
kind: function
lang: bash
domain: infra
version: "1.6.0"
version: "1.5.0"
purity: impure
signature: "launch_fleetclaude [--cwd <dir>] [--bin <path>] [--session <name>] [--reuse] [--cols <n>]"
description: "Entrypoint de FleetView: abre una ventana de terminal con una sesion tmux (socket aislado por perfil) de dos panes (TUI fleetview a la izquierda, claude --dangerously-skip-permissions a la derecha) para centralizar la flota de Claudes. La terminal se AUTO-DETECTA sin config por PC: kitty si esta instalado y hay display ($DISPLAY/$WAYLAND_DISPLAY), si no Windows Terminal (wt.exe) en WSL adjuntando via wsl.exe. El pane de la TUI corre dentro del bucle supervisor supervise_fleetview_tui, que la relanza si muere (crash/panic/kill), asi el panel de control NUNCA se pierde. Soporta PERFILES multiples: sin --session/--reuse cada invocacion abre un perfil nuevo (fleet, fleet2, fleet3, ...) con su propia flota; inyecta FLEET_SOCKET/FLEET_SESSION a la TUI para que cada panel vea solo sus Claudes. Instala atajos alt+flechas/alt+enter/alt+n que controlan la TUI desde cualquier pane, y fija el ancho del sidebar con hooks."
tags: [claude-fleet, infra, kitty, tmux, claude, fleetview, launcher, wsl, windows-terminal]
description: "Entrypoint de FleetView: abre una ventana kitty con una sesion tmux (socket aislado por perfil) de dos panes (TUI fleetview a la izquierda, claude --dangerously-skip-permissions a la derecha) para centralizar la flota de Claudes. El pane de la TUI corre dentro del bucle supervisor supervise_fleetview_tui, que la relanza si muere (crash/panic/kill), asi el panel de control NUNCA se pierde. Soporta PERFILES multiples: sin --session/--reuse cada invocacion abre un perfil nuevo (fleet, fleet2, fleet3, ...) con su propia flota; inyecta FLEET_SOCKET/FLEET_SESSION a la TUI para que cada panel vea solo sus Claudes. Instala atajos alt+flechas/alt+enter/alt+n que controlan la TUI desde cualquier pane, y fija el ancho del sidebar con hooks."
tags: [claude-fleet, infra, kitty, tmux, claude, fleetview, launcher]
params:
- name: --cwd
desc: "Directorio de trabajo de ambos panes tmux. Opcional. Default: raiz del repo fn_registry, derivada dinamicamente via git rev-parse desde la ubicacion del script (sin hardcodear paths de usuario)."
@@ -19,7 +19,7 @@ params:
desc: "Reattach al perfil principal 'fleet' en vez de abrir uno nuevo. Opcional. Recupera el comportamiento idempotente clasico (volver a invocar NO duplica la flota, reusa la existente)."
- name: --cols
desc: "Ancho en columnas del pane izquierdo (la TUI). Opcional. Default: 40."
output: "Crea/reutiliza una sesion tmux detached con dos panes y lanza una ventana de terminal 'FleetView' adjunta a ella (kitty o Windows Terminal segun auto-deteccion), desacoplada del shell padre. Imprime el estado por stdout. Sin valor de retorno; exit 0 en exito."
output: "Crea/reutiliza una sesion tmux detached con dos panes y lanza una ventana kitty 'FleetView' adjunta a ella, desacoplada del shell padre (setsid). Imprime el estado por stdout. Sin valor de retorno; exit 0 en exito."
uses_functions:
- supervise_fleetview_tui_bash_infra
uses_types: []
@@ -49,7 +49,7 @@ launch_fleetclaude --reuse
launch_fleetclaude --session trabajo --cols 50
```
Tras invocarlo aparece una ventana de terminal titulada `FleetView (<perfil>)` con dos
Tras invocarlo aparece una ventana kitty titulada `FleetView (<perfil>)` con dos
panes lado a lado: a la izquierda la TUI `fleetview`, a la derecha una sesion de
`claude --dangerously-skip-permissions`. Cada perfil es un socket+sesion tmux
aislados con su propia flota: puedes tener varias FleetView abiertas a la vez.
@@ -78,24 +78,12 @@ al retomar el trabajo en el repo `fn_registry`.
`respawn-pane` de alt+R y los Claude nuevos hereden el socket). `main.go` los
lee con fallback a `fleet`. Por eso cada panel ve SOLO los Claude de su perfil
(cruza la lista del sistema con los panes de su socket).
- **Auto-deteccion de terminal (sin config por PC)**: en la ruta ventana-nueva el
launcher elige terminal solo. (1) `kitty` instalado **y** display usable
(`$DISPLAY`/`$WAYLAND_DISPLAY`) → kitty (escritorio Linux nativo o WSLg con
kitty). (2) Si no, WSL con `wt.exe` en el PATH → Windows Terminal ejecutando
`wsl.exe [-d $WSL_DISTRO_NAME] -- bash -lic 'tmux -L <perfil> attach ...'`.
(3) Ninguna → error con las salidas posibles. Asi el MISMO `fleetclaude`
funciona en un PC con kitty y en otro WSL sin kitty, cada uno elige su
terminal. Causa raiz del sintoma "se lanza la flota pero no se ve": kitty no
instalado en WSL hacia que la sesion tmux se creara sin ventana que la mostrara.
- **Dentro de tmux abre ventana nueva**: si invocas `fleetclaude` desde dentro de
una sesion tmux (`$TMUX` definido), NO hace `attach` anidado (rompe / avisa de
nesting); cae a la ruta ventana-nueva (auto-deteccion de terminal). Fuera de
tmux y con TTY, reutiliza la terminal actual con `exec tmux attach`.
- **kitty detached (setsid)**: la ventana kitty se lanza con `setsid ... &` para
sobrevivir al cierre de la terminal que la invoco. La ventana de Windows
Terminal (wt.exe) ya es un proceso Windows independiente del arbol Linux, asi
que sobrevive sola (se lanza con `&`+`disown` desde un subshell con cwd `/mnt/c`
para evitar el warning de wt.exe por cwd UNC `\\wsl.localhost\...`).
nesting); cae a la ruta kitty y abre una ventana nueva. Fuera de tmux y con
TTY, reutiliza la terminal actual con `exec tmux attach`.
- **kitty detached (setsid)**: la ventana se lanza con `setsid ... &` para
sobrevivir al cierre de la terminal que la invoco. No bloquea al shell padre.
- **TUI bajo supervisor (auto-respawn)**: el pane izquierdo NO corre un
`exec fleetview` de una sola vida, sino `supervise_fleetview_tui` (bucle que
relanza la TUI si muere por crash/panic/kill). Asi el panel de control nunca se
@@ -128,23 +116,14 @@ al retomar el trabajo en el repo `fn_registry`.
- **Ancho del sidebar via hooks**: `client-resized` y `window-layout-changed`
re-fijan el pane 0 (TUI) a `--cols` columnas, porque el `attach` de kitty y el
conmutar de Claude redistribuyen el espacio.
- **tmux siempre; terminal (kitty/wt.exe) solo sin TTY**: `tmux` es obligatorio
(aborta != 0 si falta). Una terminal nueva (kitty o Windows Terminal) solo se
necesita en la ruta sin-TTY (dentro de tmux, atajo de escritorio, cron, script),
donde abre una ventana nueva. Invocado desde una terminal interactiva fuera de
tmux (el caso normal del alias `fleetclaude`), reutiliza la terminal actual con
`exec tmux attach` y no necesita ni kitty ni wt.exe.
- **tmux siempre, kitty solo sin TTY**: `tmux` es obligatorio (aborta != 0 si
falta). `kitty` solo se necesita en la ruta sin-TTY (atajo de escritorio, cron,
script), donde abre una ventana nueva. Invocado desde una terminal interactiva
(el caso normal del alias `fleetclaude`), reutiliza la terminal actual con
`exec tmux attach` y NO necesita kitty — util en WSL u hosts sin kitty.
## Capability growth log
- v1.6.0 (2026-06-29) — **auto-deteccion de terminal (kitty ↔ Windows Terminal)**.
La ruta ventana-nueva ya no asume kitty: elige terminal segun el host. kitty si
esta instalado y hay display (`$DISPLAY`/`$WAYLAND_DISPLAY`); si no, en WSL abre
Windows Terminal (`wt.exe`) ejecutando `wsl.exe [-d $WSL_DISTRO_NAME] -- bash
-lic 'tmux ... attach'`. Mismo `fleetclaude` en un PC con kitty y en otro WSL
sin kitty. Arregla el sintoma "se lanza la flota pero no se ve": en WSL sin
kitty la sesion tmux se creaba pero ninguna ventana la mostraba. wt.exe se
lanza desde un subshell con cwd `/mnt/c` para evitar el warning por cwd UNC.
- v1.5.0 (2026-06-24) — **auto-respawn de la TUI**. El pane izquierdo ya no corre
`exec fleetview` (una sola vida), sino el bucle supervisor
`supervise_fleetview_tui`, que relanza la TUI si muere (crash/panic/kill de su
+13 -43
View File
@@ -294,61 +294,31 @@ USAGE
$T set-hook -g window-layout-changed "resize-pane -t $left_pane -x $cols"
# -----------------------------------------------------------------------
# Adjuntar la sesion en una terminal, DESACOPLADA del shell padre para que
# no muera al cerrar la terminal invocadora.
# Lanzar kitty adjuntando la sesion, DESACOPLADA del shell padre con
# setsid, para que no muera al cerrar la terminal invocadora.
# (Mismo patron que reboot_all_claudes para relanzar terminales.)
# -----------------------------------------------------------------------
# Adjuntar la sesion:
# - Terminal interactiva y FUERA de tmux: convertir ESA terminal en el
# panel FleetView (exec reemplaza el proceso; al hacer detach vuelve la
# shell). Asi `fleetclaude` no abre otra ventana: usa la actual.
# - DENTRO de tmux (o sin TTY: atajo de escritorio, cron, script): abrir
# una ventana de terminal NUEVA desacoplada. No hacemos `attach`
# una ventana kitty nueva desacoplada (setsid). No hacemos `attach`
# anidado dentro de otra sesion tmux (rompe / da el warning de nesting).
if [ -t 0 ] && [ -t 1 ] && [ -z "${TMUX:-}" ]; then
exec tmux -L "$session" attach -t "$session"
fi
# -----------------------------------------------------------------------
# Ruta ventana-nueva: AUTO-DETECTAR la terminal disponible (sin config por
# PC). El mismo `fleetclaude` funciona en un escritorio Linux con kitty y en
# un WSL sin kitty pero con Windows Terminal.
# 1. kitty instalado + display usable ($DISPLAY/$WAYLAND_DISPLAY) -> kitty
# (escritorio Linux nativo, o WSLg con kitty instalado).
# 2. WSL con wt.exe alcanzable -> Windows Terminal ejecutando wsl.exe que
# adjunta la sesion tmux (PCs WSL sin kitty: la ventana kitty nunca
# aparece sin una terminal Linux real, por eso "se lanza pero no se ve").
# 3. Ninguna -> error claro con las dos salidas posibles.
# -----------------------------------------------------------------------
if command -v kitty >/dev/null 2>&1 && [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then
setsid kitty --title "FleetView ($session)" -e tmux -L "$session" attach -t "$session" </dev/null >/dev/null 2>&1 &
disown 2>/dev/null || true
echo "launch_fleetclaude: ventana kitty 'FleetView ($session)' adjunta al perfil '$session'."
return 0
# Ruta ventana-nueva: necesitamos kitty para abrirla.
if ! command -v kitty >/dev/null 2>&1; then
echo "launch_fleetclaude: kitty no esta instalado (necesario para abrir ventana nueva)." >&2
echo "launch_fleetclaude: lanzalo desde una terminal interactiva fuera de tmux, o instala kitty." >&2
return 1
fi
setsid kitty --title "FleetView ($session)" -e tmux -L "$session" attach -t "$session" </dev/null >/dev/null 2>&1 &
disown 2>/dev/null || true
if command -v wt.exe >/dev/null 2>&1; then
# bash -lic <attach> dentro de wsl.exe: login+interactive para que tmux y
# el PATH del perfil esten disponibles en la ventana de Windows Terminal.
local attach_cmd
attach_cmd="tmux -L $(printf '%q' "$session") attach -t $(printf '%q' "$session")"
local distro="${WSL_DISTRO_NAME:-}"
local wsl_args=(wsl.exe)
[[ -n "$distro" ]] && wsl_args+=(-d "$distro")
wsl_args+=(-- bash -lic "$attach_cmd")
# cd a una ruta Windows (/mnt/c) evita el warning de wt.exe por cwd UNC
# (\\wsl.localhost\...). El cwd real de los panes lo fija la sesion tmux.
( cd /mnt/c 2>/dev/null || cd /
wt.exe new-tab --title "FleetView ($session)" "${wsl_args[@]}" </dev/null >/dev/null 2>&1 &
disown 2>/dev/null || true )
echo "launch_fleetclaude: Windows Terminal 'FleetView ($session)' adjunta al perfil '$session' (WSL distro '${distro:-default}')."
return 0
fi
echo "launch_fleetclaude: no hay terminal para abrir una ventana nueva." >&2
echo "launch_fleetclaude: - escritorio Linux: instala kitty y exporta DISPLAY/WAYLAND_DISPLAY." >&2
echo "launch_fleetclaude: - WSL: usa Windows Terminal (wt.exe debe estar en el PATH)." >&2
echo "launch_fleetclaude: - o lanza fleetclaude desde una terminal interactiva fuera de tmux." >&2
return 1
echo "launch_fleetclaude: ventana kitty 'FleetView ($session)' adjunta al perfil '$session'."
return 0
}
# Permitir ejecutar el archivo directamente (no solo como funcion sourced).
+34 -50
View File
@@ -18,7 +18,6 @@ type pyParam struct {
Default string // empty if required
IsKwargs bool // **kwargs
IsRegistry bool // type is a registry type (needs factory)
KwOnly bool // declared after a bare "*" or "*args" — must be passed by keyword
}
// pyFactory links a registry type to the function that creates it.
@@ -46,21 +45,12 @@ func parsePySignature(sig string) []pyParam {
// Split by comma, respecting nested brackets
parts := splitParams(raw)
var params []pyParam
kwOnly := false
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" || part == "self" || part == "cls" {
continue
}
// A bare "*" (PEP 3102) or "*args" var-positional marks the start of
// keyword-only params. Neither maps cleanly to positional CLI args, so
// skip the marker itself and flag every following param as keyword-only.
if part == "*" || (strings.HasPrefix(part, "*") && !strings.HasPrefix(part, "**")) {
kwOnly = true
continue
}
p := parseSingleParam(part)
p.KwOnly = kwOnly
params = append(params, p)
}
return params
@@ -199,19 +189,11 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
// Classify params
var factoryImports []string // import lines for factories
var factorySetup []string // code to create factory objects
var bodyLines []string // code that fills _call_args / _call_kwargs
var argLines []string // code to parse CLI args
var callArgs []string // arguments to pass to the function
cliArgIdx := 0
// emitCall appends one param to _call_args (positional) or _call_kwargs
// (keyword-only). indent prefixes the line (for params read inside an `if`).
emitCall := func(p pyParam, indent string) string {
if p.KwOnly {
return fmt.Sprintf("%s_call_kwargs[%q] = %s", indent, p.Name, p.Name)
}
return fmt.Sprintf("%s_call_args.append(%s)", indent, p.Name)
}
for _, p := range params {
if p.IsKwargs {
// Skip **kwargs for now — can't auto-resolve from CLI
@@ -253,35 +235,27 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
fmt.Sprintf("%s = %s(%s)", p.Name, factory.FuncName,
strings.Join(factoryArgs, ", ")))
// Factory objects are always present (required).
bodyLines = append(bodyLines, emitCall(p, ""))
callArgs = append(callArgs, p.Name)
} else {
// Primitive type — from CLI args.
// Primitive type — from CLI args
if p.Default != "" {
// Optional: only pass when the CLI arg is present. When absent we
// DON'T replicate the signature default (it may reference a module
// constant that doesn't exist in this runner) — we simply omit the
// argument so the function applies its own native default.
bodyLines = append(bodyLines,
fmt.Sprintf("if len(_args) > %d:", cliArgIdx))
bodyLines = append(bodyLines,
fmt.Sprintf(" %s = _args[%d]", p.Name, cliArgIdx))
if conv := convertArg(p.Name, p.Type, true); conv != "" {
bodyLines = append(bodyLines, " "+conv)
}
bodyLines = append(bodyLines, emitCall(p, " "))
// Optional param with default
argLines = append(argLines,
fmt.Sprintf("%s = _args[%d] if len(_args) > %d else %s",
p.Name, cliArgIdx, cliArgIdx, convertDefault(p.Type, p.Default)))
argLines = append(argLines,
convertArg(p.Name, p.Type, true))
} else {
// Required param.
bodyLines = append(bodyLines,
// Required param
argLines = append(argLines,
fmt.Sprintf("if len(_args) <= %d: sys.exit('error: missing required arg: %s (%s)')",
cliArgIdx, p.Name, p.Type))
bodyLines = append(bodyLines,
argLines = append(argLines,
fmt.Sprintf("%s = _args[%d]", p.Name, cliArgIdx))
if conv := convertArg(p.Name, p.Type, false); conv != "" {
bodyLines = append(bodyLines, conv)
}
bodyLines = append(bodyLines, emitCall(p, ""))
argLines = append(argLines,
convertArg(p.Name, p.Type, false))
}
callArgs = append(callArgs, p.Name)
cliArgIdx++
}
}
@@ -315,18 +289,18 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
sb.WriteString("\n")
}
// Arg parsing — build the positional/keyword argument collections.
sb.WriteString("# --- parse CLI args ---\n")
sb.WriteString("_call_args = []\n")
sb.WriteString("_call_kwargs = {}\n")
for _, line := range bodyLines {
sb.WriteString(line + "\n")
// Arg parsing
if len(argLines) > 0 {
sb.WriteString("# --- parse CLI args ---\n")
for _, line := range argLines {
sb.WriteString(line + "\n")
}
sb.WriteString("\n")
}
sb.WriteString("\n")
// Call
sb.WriteString("# --- execute ---\n")
sb.WriteString(fmt.Sprintf("_result = %s(*_call_args, **_call_kwargs)\n", fn.Name))
sb.WriteString(fmt.Sprintf("_result = %s(%s)\n", fn.Name, strings.Join(callArgs, ", ")))
sb.WriteString("\n")
// Output
@@ -391,6 +365,16 @@ func convertArg(name, typ string, _ bool) string {
}
}
// convertDefault ensures the default value is valid Python for the given type.
func convertDefault(_, def string) string {
// Most defaults from the signature are already valid Python
// Just handle the None case for Optional types
if def == "None" || def == "" {
return "None"
}
return def
}
// pythonList creates a Python list literal from strings: ["a", "b", "c"]
func pythonList(items []string) string {
quoted := make([]string, len(items))
-141
View File
@@ -1,141 +0,0 @@
package main
import (
"os"
"os/exec"
"strings"
"testing"
"fn-registry/registry"
)
// Signature with a bare "*" (PEP 3102) separating positional from keyword-only
// params. This is the shape that used to make fn run emit "* = _args[3]".
const kwOnlySig = "def add_event_dav(summary: str, start: str, end: str = '', *, location: str = '', all_day: bool = False) -> dict"
func TestParsePySignatureBareStarKeywordOnly(t *testing.T) {
params := parsePySignature(kwOnlySig)
// The bare "*" marker must never surface as a real parameter.
for _, p := range params {
if p.Name == "*" {
t.Fatalf("bare '*' leaked as a param: %+v", params)
}
}
want := map[string]bool{ // name -> expected KwOnly
"summary": false,
"start": false,
"end": false,
"location": true,
"all_day": true,
}
if len(params) != len(want) {
t.Fatalf("got %d params, want %d: %+v", len(params), len(want), params)
}
for _, p := range params {
kw, ok := want[p.Name]
if !ok {
t.Errorf("unexpected param %q", p.Name)
continue
}
if p.KwOnly != kw {
t.Errorf("param %q KwOnly=%v, want %v", p.Name, p.KwOnly, kw)
}
}
}
func TestGeneratePyRunnerKeywordOnlyValid(t *testing.T) {
fn := &registry.Function{
Name: "add_event_dav",
Lang: "py",
FilePath: "python/functions/pipelines/add_event_dav.py",
Signature: kwOnlySig,
}
// All params are primitive, so no factory lookup happens and db is unused.
script, err := generatePyRunner(fn, nil, "")
if err != nil {
t.Fatalf("generatePyRunner: %v", err)
}
if strings.Contains(script, "* = _args") {
t.Fatalf("runner emitted invalid syntax '* = _args':\n%s", script)
}
// The signature default DEFAULT_BASE_URL (a module constant) must NOT be
// replicated into the runner — that NameErrors at runtime.
if strings.Contains(script, "DEFAULT_BASE_URL") {
t.Errorf("runner replicated non-literal default DEFAULT_BASE_URL:\n%s", script)
}
// Required positionals are appended; keyword-only optionals go to kwargs.
for _, want := range []string{
"_call_args.append(summary)",
"_call_args.append(start)",
`_call_kwargs["location"] = location`,
`_call_kwargs["all_day"] = all_day`,
"_result = add_event_dav(*_call_args, **_call_kwargs)",
} {
if !strings.Contains(script, want) {
t.Errorf("missing %q in generated runner:\n%s", want, script)
}
}
// The generated runner must itself be valid Python (compile, don't run).
mustCompilePython(t, script)
}
// mustCompilePython checks the script parses as valid Python via py_compile.
func mustCompilePython(t *testing.T, script string) {
t.Helper()
f, err := os.CreateTemp(t.TempDir(), "runner_*.py")
if err != nil {
t.Fatalf("temp file: %v", err)
}
if _, err := f.WriteString(script); err != nil {
t.Fatalf("write: %v", err)
}
f.Close()
py := pythonBinForTest()
out, err := exec.Command(py, "-m", "py_compile", f.Name()).CombinedOutput()
if err != nil {
t.Fatalf("generated runner is not valid Python (%s): %v\n%s", py, err, out)
}
}
// pythonBinForTest prefers the project venv, falling back to python3 on PATH.
func pythonBinForTest() string {
for _, c := range []string{"../../python/.venv/bin/python3", "python3"} {
if c == "python3" {
return c
}
if _, err := os.Stat(c); err == nil {
return c
}
}
return "python3"
}
// A "*args" var-positional marker must behave like the bare "*": skipped, and
// everything after it treated as keyword-only.
func TestParsePySignatureVarargsKeywordOnly(t *testing.T) {
sig := "def f(a: str, *args, b: int = 0) -> dict"
params := parsePySignature(sig)
for _, p := range params {
if strings.HasPrefix(p.Name, "*") {
t.Fatalf("'*args' marker leaked as a param: %+v", params)
}
}
if len(params) != 2 {
t.Fatalf("got %d params, want 2: %+v", len(params), params)
}
got := map[string]bool{}
for _, p := range params {
got[p.Name] = p.KwOnly
}
if got["a"] != false || got["b"] != true {
t.Errorf("KwOnly mismatch: a=%v (want false), b=%v (want true)", got["a"], got["b"])
}
}
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0033 — C++ http_inspector + websocket_client
@@ -11,7 +11,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0051 — Funciones pendientes del pipeline de extraccion (NER+RE+OpenIE)
@@ -13,7 +13,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0054 — deploy_server: refactor registry-first (SSH/systemd/rsync/health/docker-compose)
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0055 — docker_tui: refactor para usar funciones docker_* del registry
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0056 — audit_uses_functions: detectar imports Python anidados (`from pkg.subpkg import X`)
+1 -1
View File
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0057 — audit_uses_functions: mejorar deteccion de simbolos Go con abreviaturas
@@ -13,7 +13,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0058 — kanban: sync uses_functions cuando termine WIP en curso
@@ -1,7 +1,7 @@
---
id: "0059"
title: "Resolver doble tracking de `apps/*/app.md` (fn_registry + sub-repo)"
status: completado
status: pendiente
type: infra
domain:
- registry-quality
@@ -11,7 +11,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0060 — `fn doctor secrets`: scan de secrets en TODOS los repos
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0061 — Integrar `notify_telegram` en deploy_server + bucle reactivo
@@ -1,7 +1,7 @@
---
id: "55"
title: "Roadmap de prereqs — issues de osint_graph que odr_console necesita antes/durante MVP"
status: deferred
status: pendiente
type: epic
domain:
- osint
@@ -7,7 +7,8 @@ domain:
- registry-quality
scope: registry-only
priority: alta
depends: ["0071f"]
depends:
- "0071f"
blocks: []
related: []
created: 2026-05-10
+2 -1
View File
@@ -7,7 +7,8 @@ domain:
- registry-quality
scope: registry-only
priority: media
depends: ["0071f"]
depends:
- "0071f"
blocks: []
related: []
created: 2026-05-10
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-10
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Contexto
+1 -1
View File
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-10
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Contexto
@@ -13,7 +13,10 @@ blocks: []
related: []
created: 2026-05-10
updated: 2026-05-17
tags: [ausente-ready, gamedev, cpp, wasm]
tags:
- gamedev
- cpp
- wasm
---
## Objetivo
@@ -7,7 +7,8 @@ domain:
- gamedev
scope: multi-app
priority: alta
depends: ["0072a"]
depends:
- "0072a"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,8 @@ domain:
- gamedev
scope: multi-app
priority: alta
depends: ["0072b"]
depends:
- "0072b"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,9 @@ domain:
- gamedev
scope: multi-app
priority: alta
depends: ["0072a", "0072b"]
depends:
- "0072a"
- "0072b"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,9 @@ domain:
- gamedev
scope: multi-app
priority: alta
depends: ["0072a", "0072d"]
depends:
- "0072a"
- "0072d"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,8 @@ domain:
- gamedev
scope: multi-app
priority: media
depends: ["0072e"]
depends:
- "0072e"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,9 @@ domain:
- gamedev
scope: multi-app
priority: media
depends: ["0072b", "0072c"]
depends:
- "0072b"
- "0072c"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,9 @@ domain:
- gamedev
scope: multi-app
priority: media
depends: ["0072b", "0072c"]
depends:
- "0072b"
- "0072c"
blocks: []
related: []
created: 2026-05-10
@@ -7,7 +7,9 @@ domain:
- gamedev
scope: app-scoped
priority: media
depends: ["0072b", "0072c"]
depends:
- "0072b"
- "0072c"
blocks: []
related: []
created: 2026-05-10
@@ -7,12 +7,16 @@ domain:
- gamedev
scope: multi-app
priority: media
depends: ["0072b"]
depends:
- "0072b"
blocks: []
related: []
created: 2026-05-10
updated: 2026-05-17
tags: [gamedev, cpp, physics]
tags:
- gamedev
- cpp
- physics
---
## Objetivo
@@ -7,7 +7,11 @@ domain:
- gamedev
scope: multi-app
priority: alta
depends: ["0072b", "0072c", "0072d", "0072j"]
depends:
- "0072b"
- "0072c"
- "0072d"
- "0072j"
blocks: []
related: []
created: 2026-05-10
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-10
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Sintoma
+1 -1
View File
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-10
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Sintoma
@@ -13,7 +13,7 @@ blocks: []
related: []
created: 2026-05-13
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Objetivo
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-13
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Objetivo
@@ -1,7 +1,7 @@
---
id: "0087"
title: "Capability Discovery Acceleration"
status: completado
status: pendiente
type: feature
domain:
- meta
@@ -1,5 +1,5 @@
---
id: "0178"
id: "0088"
title: "kanban: requester input vacío + navegación con teclado"
status: pendiente
type: feature
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Problema
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0088a — Trading: project scaffolding
@@ -8,7 +8,7 @@ domain:
- meta
scope: multi-app
priority: alta
depends: ["0088a"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -7,7 +7,7 @@ domain:
- trading
scope: multi-app
priority: alta
depends: ["0088a", "0088d"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -7,7 +7,7 @@ domain:
- trading
scope: app-scoped
priority: alta
depends: ["0088a"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -8,7 +8,7 @@ domain:
- meta
scope: multi-app
priority: alta
depends: ["0088a"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -8,7 +8,7 @@ domain:
- meta
scope: multi-app
priority: alta
depends: ["0088a"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -7,7 +7,7 @@ domain:
- trading
scope: app-scoped
priority: alta
depends: ["0088b", "0088c", "0088d", "0088e", "0088f"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -7,7 +7,7 @@ domain:
- trading
scope: multi-app
priority: alta
depends: ["0088b", "0088c", "0088d", "0088e", "0088f", "0088g"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -7,7 +7,7 @@ domain:
- trading
scope: app-scoped
priority: alta
depends: ["0088a", "0088d"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -8,7 +8,7 @@ domain:
- frontend
scope: multi-app
priority: alta
depends: ["0088d", "0088g", "0088h", "0088i"]
depends: []
blocks: []
related: []
created: 2026-05-17
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Problema
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Problema
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Problema
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Problema
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
## Problema
@@ -1,7 +1,7 @@
---
id: "0096"
title: "Estandarizar ubicacion de apps: fuera de carpetas por lenguaje"
status: completado
status: pendiente
type: feature
domain:
- apps-infra
@@ -12,7 +12,7 @@ blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready]
tags: []
---
# 0100 — Migrar frontmatter inline a YAML canonico en dev/issues/
@@ -1,7 +1,7 @@
---
id: "0101"
title: "dev_console Go binario: /issue /flow /work unificados"
status: completado
status: pendiente
type: app
domain:
- meta
@@ -1,7 +1,7 @@
---
id: "0103"
title: "Taxonomia + slash commands /issue /flow /work"
status: completado
status: pendiente
type: feature
domain:
- meta
@@ -16,7 +16,7 @@ related:
- "0103"
created: 2026-05-17
updated: 2026-05-17
tags: [slash-command, dispatch, type-aware, ausente-ready]
tags: [slash-command, dispatch, type-aware]
---
# 0104 — `/fix-issue` type-aware dispatch
@@ -1,7 +1,7 @@
---
id: "0105"
title: "Estandarizar bloque service: en app.md + indexer + fn doctor services-spec"
status: completado
status: in-progress
type: feature
domain:
- meta
+1 -1
View File
@@ -16,7 +16,7 @@ related:
- "0107"
created: 2026-05-17
updated: 2026-05-17
tags: [modules, versioning, codegen, fail-loud, ausente-ready]
tags: [modules, versioning, codegen, fail-loud]
---
# 0107e — Version pinning + codegen fail-loud
@@ -1,7 +1,7 @@
---
id: "0109g"
title: "skill_tree: panel terminal embebida (claude TUI dentro de la app)"
status: deferred
status: pendiente
type: feature
domain:
- meta
@@ -15,7 +15,12 @@ related:
- "0109"
created: 2026-05-17
updated: 2026-05-17
tags: [ausente-ready, skill-tree, cpp, imgui, dashboard, gamification]
tags:
- skill-tree
- cpp
- imgui
- dashboard
- gamification
---
# 0109k — Dashboard panel
+7 -1
View File
@@ -16,7 +16,13 @@ related:
- "0106"
created: 2026-05-18
updated: 2026-05-18
tags: [ausente-ready, service, go, http, issues, flows, api]
tags:
- service
- go
- http
- issues
- flows
- api
---
# 0109m — issues_api service
@@ -15,7 +15,7 @@ related:
- "0106"
created: 2026-05-18
updated: 2026-05-18
tags: [http, cpp, registry-gap, curl, helper, ausente-ready]
tags: [http, cpp, registry-gap, curl, helper]
---
# 0110 — Helper HTTP cliente C++ en el registry
+1 -1
View File
@@ -16,7 +16,7 @@ related:
- "0068"
created: 2026-05-18
updated: 2026-05-19
tags: [e2e_checks, recopilador, batch, coverage, epic, ausente-ready]
tags: [e2e_checks, recopilador, batch, coverage, epic]
---
# Sub-issues
+1 -1
View File
@@ -16,7 +16,7 @@ related:
- "0068"
created: 2026-05-19
updated: 2026-05-19
tags: [e2e_checks, recopilador, batch, design, ausente-ready]
tags: [e2e_checks, recopilador, batch, design]
---
# 0121a — Design-e2e batch
+3 -1
View File
@@ -7,7 +7,9 @@ domain:
- registry-quality
scope: registry
priority: media
depends: ["0121a"]
depends:
- "0121a"
- "0121b"
blocks:
- "0122"
related:
+1 -1
View File
@@ -17,7 +17,7 @@ related:
- "0086"
created: 2026-05-18
updated: 2026-05-18
tags: [revisor, mejorador, proposals, auto-apply, autonomous, ausente-ready]
tags: [revisor, mejorador, proposals, auto-apply, autonomous]
---
# 0122 — fn-revisor + ampliar filtro auto-aplicable del orquestador
+1 -1
View File
@@ -13,7 +13,7 @@ related:
- "0121a"
created: 2026-05-19
updated: 2026-05-19
tags: [dag_engine, cleanup, technical-debt, ausente-ready]
tags: [dag_engine, cleanup, technical-debt]
---
# 0124 — dag_engine cleanup
+1 -1
View File
@@ -13,7 +13,7 @@ related:
- "0121a"
created: 2026-05-19
updated: 2026-05-19
tags: [deploy_server, cli, idempotency, ausente-ready]
tags: [deploy_server, cli, idempotency]
---
# 0125 — deploy_server `--db` flag
+1 -1
View File
@@ -1,7 +1,7 @@
---
id: "0128"
title: "kanban: adjuntar archivos (drag&drop desc/chat + tab Archivos)"
status: in-progress
status: in_progress
type: feature
domain:
- apps-tools
+6 -1
View File
@@ -13,7 +13,12 @@ blocks:
- 0130b
related:
- "0130"
tags: [registry, go, parser, frontmatter, fsnotify, ausente-ready]
tags:
- registry
- go
- parser
- frontmatter
- fsnotify
flow: "0130"
created: "2026-05-22"
updated: "2026-05-22"
+2 -1
View File
@@ -8,7 +8,8 @@ domain:
- dev-ux
scope: app-scoped
priority: alta
depends: ["0130a"]
depends:
- "0130a"
blocks:
- "0130c"
related:
@@ -8,7 +8,8 @@ domain:
- dev-ux
scope: app-scoped
priority: alta
depends: ["0130b"]
depends:
- "0130b"
blocks: []
related:
- "0130"
@@ -16,7 +16,7 @@ related:
- "0131"
created: 2026-05-22
updated: 2026-05-22
tags: [cpp, imgui, terminal, pty, module, ausente-ready]
tags: [cpp, imgui, terminal, pty, module]
flow: ""
---
+2 -2
View File
@@ -1,14 +1,14 @@
---
id: "0134"
title: "Mesh protocol spec: capability manifests, ed25519 envelopes, enrollment, audit chain"
status: pendiente
status: pending
type: spec
domain:
- infra
- cybersecurity
- protocols
scope: cross-app
priority: alta
priority: high
depends: []
blocks:
- "0135"
+2 -2
View File
@@ -1,7 +1,7 @@
---
id: "0144"
title: "Agent LLM per machine (user + sudo) con tool registry y mesh dispatch"
status: pendiente
status: pending
type: spec
domain:
- agents
@@ -9,7 +9,7 @@ domain:
- infra
- cybersecurity
scope: multi-app
priority: alta
priority: high
depends:
- "0134"
- "0140"
@@ -1,8 +1,8 @@
---
id: "0146"
title: "add-pc one-shot: añade PC al mesh + agente LLM en <2min desde movil"
status: pendiente
priority: alta
status: pending
priority: high
created: 2026-05-24
related_flows: ["0009"]
related_issues: ["0134", "0144", "0145"]
+2 -2
View File
@@ -1,8 +1,8 @@
---
id: "0147"
title: "matrix-client-pc scaffold: Wails + React+Mantine + login MAS"
status: pendiente
priority: alta
status: pending
priority: high
created: 2026-05-24
related_flows: ["0010"]
related_issues: ["0148", "0162"]
@@ -1,8 +1,8 @@
---
id: "0148"
title: "matrix-client-pc rooms list + timeline con sync incremental"
status: pendiente
priority: alta
status: pending
priority: high
created: 2026-05-24
related_flows: ["0010"]
related_issues: ["0147", "0149"]

Some files were not shown because too many files have changed in this diff Show More