Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 437409641c | |||
| f3d427d9e4 | |||
| f5b30b23dc | |||
| 5eaf3f662e | |||
| 05fe76bce0 | |||
| 864430e988 | |||
| a69d14d38e | |||
| fd59530751 | |||
| 96da9e3015 | |||
| 00cd5274bc | |||
| cd658cc703 | |||
| 81b57f9acd | |||
| 02ee222dde | |||
| ba162ab301 | |||
| 415154d9a3 | |||
| d479a8e4e2 | |||
| 9286e3b6b1 | |||
| 649de07d6b | |||
| af1dd9bcc2 | |||
| fc5bc334c8 | |||
| 03f3dca823 | |||
| d412522db9 | |||
| c1a4a83717 | |||
| 81e8597d21 | |||
| 4de071f2f9 | |||
| fcf5a4c6a3 | |||
| 959648ec4f | |||
| a3f75d61ec | |||
| cb7a7fc1fd | |||
| 9cdde4a341 | |||
| 5501507588 |
+20
-10
@@ -25,9 +25,10 @@ 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 vertical legible en móvil).
|
||||
- `--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.
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
## Reglas duras
|
||||
|
||||
@@ -35,7 +36,7 @@ Por defecto, para un EDA "completo" cuando el usuario no especifica, activa `run
|
||||
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 4 salidas**: JSON sidecar + Markdown + **PDF móvil** + **notebook Jupyter colaborativo ejecutado en vivo**.
|
||||
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.
|
||||
|
||||
## Paso 1 — Perfilar y escribir los reports
|
||||
|
||||
@@ -43,18 +44,26 @@ Una tabla (caso normal):
|
||||
|
||||
```bash
|
||||
PYTHONPATH=python/functions python/.venv/bin/python3 - <<'PYEOF'
|
||||
from pipelines.profile_table import profile_table
|
||||
r = profile_table(
|
||||
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(
|
||||
"/ruta/datos.duckdb", "ventas",
|
||||
run_models=True, run_series=True, emit_pdf=True, run_llm=False,
|
||||
run_models=True, run_series=True, run_llm=False, out_dir="reports",
|
||||
)
|
||||
print("status:", r["status"])
|
||||
print("md: ", r["report_md_path"])
|
||||
print("json: ", r["report_json_path"])
|
||||
print("pdf: ", r["pdf_path"])
|
||||
print("pdf: ", r["pdf_path"], "(", r["n_pages"], "págs )")
|
||||
print("pptx: ", r["pptx_path"], "(", r["n_slides"], "slides )")
|
||||
print("manifest:", r["manifest_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
|
||||
@@ -90,6 +99,7 @@ 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 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/`.
|
||||
- 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/`.
|
||||
- `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.
|
||||
|
||||
@@ -31,12 +31,13 @@ Diferencia con `dev/flows/`:
|
||||
|
||||
**Fase 1 (manual via Claude):**
|
||||
|
||||
El agente lee `dev/issues/*.md`, parsea frontmatter YAML con `yaml.safe_load`, aplica el filtro, imprime tabla.
|
||||
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.
|
||||
|
||||
```python
|
||||
import yaml, pathlib, re
|
||||
issues = []
|
||||
for f in pathlib.Path("dev/issues").glob("*.md"):
|
||||
for f in pathlib.Path("dev/issues").glob("**/*.md"):
|
||||
if f.parent.name == "completed": continue
|
||||
if f.name in {"README.md", "template.md"}: continue
|
||||
txt = f.read_text()
|
||||
m = re.match(r"^---\n(.*?)\n---", txt, re.S)
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
"enabledMcpjsonServers": [
|
||||
"registry",
|
||||
"jupyter",
|
||||
"orchestrator"
|
||||
"orchestrator",
|
||||
"godot",
|
||||
"ardour"
|
||||
],
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
|
||||
@@ -3,11 +3,11 @@ name: launch_fleetclaude
|
||||
kind: function
|
||||
lang: bash
|
||||
domain: infra
|
||||
version: "1.5.0"
|
||||
version: "1.6.0"
|
||||
purity: impure
|
||||
signature: "launch_fleetclaude [--cwd <dir>] [--bin <path>] [--session <name>] [--reuse] [--cols <n>]"
|
||||
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]
|
||||
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]
|
||||
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 kitty 'FleetView' adjunta a ella, desacoplada del shell padre (setsid). 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 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."
|
||||
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 kitty titulada `FleetView (<perfil>)` con dos
|
||||
Tras invocarlo aparece una ventana de terminal 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,12 +78,24 @@ 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 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.
|
||||
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\...`).
|
||||
- **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
|
||||
@@ -116,14 +128,23 @@ 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, 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.
|
||||
- **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.
|
||||
|
||||
## 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
|
||||
|
||||
@@ -294,31 +294,61 @@ USAGE
|
||||
$T set-hook -g window-layout-changed "resize-pane -t $left_pane -x $cols"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 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 en una terminal, DESACOPLADA del shell padre para que
|
||||
# no muera al cerrar la terminal invocadora.
|
||||
# -----------------------------------------------------------------------
|
||||
# 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 kitty nueva desacoplada (setsid). No hacemos `attach`
|
||||
# una ventana de terminal NUEVA desacoplada. 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: 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
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# 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
|
||||
fi
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
# Permitir ejecutar el archivo directamente (no solo como funcion sourced).
|
||||
|
||||
+47
-31
@@ -18,6 +18,7 @@ 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.
|
||||
@@ -45,12 +46,21 @@ 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
|
||||
@@ -189,11 +199,19 @@ 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 argLines []string // code to parse CLI args
|
||||
var callArgs []string // arguments to pass to the function
|
||||
var bodyLines []string // code that fills _call_args / _call_kwargs
|
||||
|
||||
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
|
||||
@@ -235,27 +253,35 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
fmt.Sprintf("%s = %s(%s)", p.Name, factory.FuncName,
|
||||
strings.Join(factoryArgs, ", ")))
|
||||
|
||||
callArgs = append(callArgs, p.Name)
|
||||
// Factory objects are always present (required).
|
||||
bodyLines = append(bodyLines, emitCall(p, ""))
|
||||
} else {
|
||||
// Primitive type — from CLI args
|
||||
// Primitive type — from CLI args.
|
||||
if p.Default != "" {
|
||||
// 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))
|
||||
// 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, " "))
|
||||
} else {
|
||||
// Required param
|
||||
argLines = append(argLines,
|
||||
// Required param.
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf("if len(_args) <= %d: sys.exit('error: missing required arg: %s (%s)')",
|
||||
cliArgIdx, p.Name, p.Type))
|
||||
argLines = append(argLines,
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf("%s = _args[%d]", p.Name, cliArgIdx))
|
||||
argLines = append(argLines,
|
||||
convertArg(p.Name, p.Type, false))
|
||||
if conv := convertArg(p.Name, p.Type, false); conv != "" {
|
||||
bodyLines = append(bodyLines, conv)
|
||||
}
|
||||
bodyLines = append(bodyLines, emitCall(p, ""))
|
||||
}
|
||||
callArgs = append(callArgs, p.Name)
|
||||
cliArgIdx++
|
||||
}
|
||||
}
|
||||
@@ -289,18 +315,18 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
|
||||
// Arg parsing
|
||||
if len(argLines) > 0 {
|
||||
// Arg parsing — build the positional/keyword argument collections.
|
||||
sb.WriteString("# --- parse CLI args ---\n")
|
||||
for _, line := range argLines {
|
||||
sb.WriteString("_call_args = []\n")
|
||||
sb.WriteString("_call_kwargs = {}\n")
|
||||
for _, line := range bodyLines {
|
||||
sb.WriteString(line + "\n")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
|
||||
// Call
|
||||
sb.WriteString("# --- execute ---\n")
|
||||
sb.WriteString(fmt.Sprintf("_result = %s(%s)\n", fn.Name, strings.Join(callArgs, ", ")))
|
||||
sb.WriteString(fmt.Sprintf("_result = %s(*_call_args, **_call_kwargs)\n", fn.Name))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Output
|
||||
@@ -365,16 +391,6 @@ 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))
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
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 := ®istry.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"])
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 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: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 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: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 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: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 0056 — audit_uses_functions: detectar imports Python anidados (`from pkg.subpkg import X`)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 0057 — audit_uses_functions: mejorar deteccion de simbolos Go con abreviaturas
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 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: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 0061 — Integrar `notify_telegram` en deploy_server + bucle reactivo
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ domain:
|
||||
- registry-quality
|
||||
scope: registry-only
|
||||
priority: alta
|
||||
depends:
|
||||
- "0071f"
|
||||
depends: ["0071f"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
|
||||
@@ -7,8 +7,7 @@ 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: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
|
||||
## Sintoma
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
|
||||
## Sintoma
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 0100 — Migrar frontmatter inline a YAML canonico en dev/issues/
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0103"
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [slash-command, dispatch, type-aware]
|
||||
tags: [slash-command, dispatch, type-aware, ausente-ready]
|
||||
---
|
||||
|
||||
# 0104 — `/fix-issue` type-aware dispatch
|
||||
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0107"
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [modules, versioning, codegen, fail-loud]
|
||||
tags: [modules, versioning, codegen, fail-loud, ausente-ready]
|
||||
---
|
||||
|
||||
# 0107e — Version pinning + codegen fail-loud
|
||||
|
||||
@@ -15,12 +15,7 @@ related:
|
||||
- "0109"
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags:
|
||||
- skill-tree
|
||||
- cpp
|
||||
- imgui
|
||||
- dashboard
|
||||
- gamification
|
||||
tags: [ausente-ready, skill-tree, cpp, imgui, dashboard, gamification]
|
||||
---
|
||||
|
||||
# 0109k — Dashboard panel
|
||||
|
||||
@@ -16,13 +16,7 @@ related:
|
||||
- "0106"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags:
|
||||
- service
|
||||
- go
|
||||
- http
|
||||
- issues
|
||||
- flows
|
||||
- api
|
||||
tags: [ausente-ready, service, go, http, issues, flows, api]
|
||||
---
|
||||
|
||||
# 0109m — issues_api service
|
||||
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0068"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-19
|
||||
tags: [e2e_checks, recopilador, batch, coverage, epic]
|
||||
tags: [e2e_checks, recopilador, batch, coverage, epic, ausente-ready]
|
||||
---
|
||||
|
||||
# Sub-issues
|
||||
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0068"
|
||||
created: 2026-05-19
|
||||
updated: 2026-05-19
|
||||
tags: [e2e_checks, recopilador, batch, design]
|
||||
tags: [e2e_checks, recopilador, batch, design, ausente-ready]
|
||||
---
|
||||
|
||||
# 0121a — Design-e2e batch
|
||||
|
||||
@@ -7,9 +7,7 @@ domain:
|
||||
- registry-quality
|
||||
scope: registry
|
||||
priority: media
|
||||
depends:
|
||||
- "0121a"
|
||||
- "0121b"
|
||||
depends: ["0121a"]
|
||||
blocks:
|
||||
- "0122"
|
||||
related:
|
||||
|
||||
@@ -17,7 +17,7 @@ related:
|
||||
- "0086"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags: [revisor, mejorador, proposals, auto-apply, autonomous]
|
||||
tags: [revisor, mejorador, proposals, auto-apply, autonomous, ausente-ready]
|
||||
---
|
||||
|
||||
# 0122 — fn-revisor + ampliar filtro auto-aplicable del orquestador
|
||||
|
||||
@@ -13,7 +13,7 @@ related:
|
||||
- "0121a"
|
||||
created: 2026-05-19
|
||||
updated: 2026-05-19
|
||||
tags: [dag_engine, cleanup, technical-debt]
|
||||
tags: [dag_engine, cleanup, technical-debt, ausente-ready]
|
||||
---
|
||||
|
||||
# 0124 — dag_engine cleanup
|
||||
|
||||
@@ -13,7 +13,7 @@ related:
|
||||
- "0121a"
|
||||
created: 2026-05-19
|
||||
updated: 2026-05-19
|
||||
tags: [deploy_server, cli, idempotency]
|
||||
tags: [deploy_server, cli, idempotency, ausente-ready]
|
||||
---
|
||||
|
||||
# 0125 — deploy_server `--db` flag
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -13,12 +13,7 @@ blocks:
|
||||
- 0130b
|
||||
related:
|
||||
- "0130"
|
||||
tags:
|
||||
- registry
|
||||
- go
|
||||
- parser
|
||||
- frontmatter
|
||||
- fsnotify
|
||||
tags: [registry, go, parser, frontmatter, fsnotify, ausente-ready]
|
||||
flow: "0130"
|
||||
created: "2026-05-22"
|
||||
updated: "2026-05-22"
|
||||
|
||||
@@ -8,8 +8,7 @@ domain:
|
||||
- dev-ux
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends:
|
||||
- "0130a"
|
||||
depends: ["0130a"]
|
||||
blocks:
|
||||
- "0130c"
|
||||
related:
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
id: "0134"
|
||||
title: "Mesh protocol spec: capability manifests, ed25519 envelopes, enrollment, audit chain"
|
||||
status: pending
|
||||
status: pendiente
|
||||
type: spec
|
||||
domain:
|
||||
- infra
|
||||
- cybersecurity
|
||||
- protocols
|
||||
scope: cross-app
|
||||
priority: high
|
||||
priority: alta
|
||||
depends: []
|
||||
blocks:
|
||||
- "0135"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0144"
|
||||
title: "Agent LLM per machine (user + sudo) con tool registry y mesh dispatch"
|
||||
status: pending
|
||||
status: pendiente
|
||||
type: spec
|
||||
domain:
|
||||
- agents
|
||||
@@ -9,7 +9,7 @@ domain:
|
||||
- infra
|
||||
- cybersecurity
|
||||
scope: multi-app
|
||||
priority: high
|
||||
priority: alta
|
||||
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: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0009"]
|
||||
related_issues: ["0134", "0144", "0145"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0147"
|
||||
title: "matrix-client-pc scaffold: Wails + React+Mantine + login MAS"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
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: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010"]
|
||||
related_issues: ["0147", "0149"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0149"
|
||||
title: "matrix-client-pc composer: markdown, reply, edit, reactions, media"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010"]
|
||||
related_issues: ["0148", "0150"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0150"
|
||||
title: "matrix-client-pc E2EE: cross-signing, SAS verification, recovery"
|
||||
status: pending
|
||||
priority: critical
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010"]
|
||||
related_issues: ["0149", "0151"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0151"
|
||||
title: "matrix-client-pc calls LiveKit: 1:1 + grupales, mic/cam/screen"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010"]
|
||||
related_issues: ["0150", "0152"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0152"
|
||||
title: "matrix-client-pc mini-webapps embebidas: Matrix Widget API v2"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010"]
|
||||
related_issues: ["0151", "0153"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0154"
|
||||
title: "matrix-client-android scaffold: Kotlin + Compose + login MAS"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0155", "0162"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0155"
|
||||
title: "matrix-client-android rooms list + timeline Compose"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0154", "0156"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0156"
|
||||
title: "matrix-client-android composer: markdown, replies, edits, reactions, media"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0155", "0157"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0157"
|
||||
title: "matrix-client-android E2EE rust-sdk: cross-signing, SAS, recovery"
|
||||
status: pending
|
||||
priority: critical
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0156", "0158"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0158"
|
||||
title: "matrix-client-android calls LiveKit nativo: mic/cam/screen + PiP"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0157", "0159", "0161"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0159"
|
||||
title: "matrix-client-android push FCM via sygnal + Firebase setup"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0158", "0160"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0160"
|
||||
title: "matrix-client-android mini-webapps: WebView + Widget API v2 bridge"
|
||||
status: pending
|
||||
priority: medium
|
||||
status: pendiente
|
||||
priority: media
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0159", "0161"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0161"
|
||||
title: "matrix-client-android foreground service: calls + lifecycle + lockscreen"
|
||||
status: pending
|
||||
priority: high
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0011"]
|
||||
related_issues: ["0158", "0160"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0162"
|
||||
title: "Matrix: migrar Synapse a MAS como unico auth provider (MSC3861)"
|
||||
status: pending
|
||||
priority: critical
|
||||
status: pendiente
|
||||
priority: alta
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010", "0011"]
|
||||
related_issues: ["0147", "0154", "0163"]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: "0163"
|
||||
title: "Matrix admin panel propio: users, rooms, devices, sessions (sustituye synapse-admin)"
|
||||
status: pending
|
||||
priority: medium
|
||||
status: pendiente
|
||||
priority: media
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010", "0011"]
|
||||
related_issues: ["0162", "0147"]
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: "0179"
|
||||
title: "dev_console: escaneo recursivo de dev/issues/ (subcarpetas por dominio)"
|
||||
status: in-progress
|
||||
type: bugfix
|
||||
domain:
|
||||
- meta
|
||||
scope: app-scoped
|
||||
priority: media
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-06-30
|
||||
updated: 2026-06-30
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 0179 — dev_console: escaneo recursivo de dev/issues/
|
||||
|
||||
## Contexto
|
||||
|
||||
Los issues activos se reorganizaron en subcarpetas por dominio dentro de `dev/issues/` (`kanban/`, `trading/`, `gamedev/`, `cpp/`, `matrix/`, `imagegen/`) para descongestionar el listado plano. El skill `/issue` ya se actualizó a glob recursivo (`dev/issues/**/*.md`, excluyendo `completed/`). Falta alinear el binario `dev_console`, que carga los issues con `LoadAllIssues(root)` / `LoadOpenIssues(root)` en `apps/dev_console/` y hoy no recorre subcarpetas — por lo que no ve los 49 issues movidos.
|
||||
|
||||
## Objetivo
|
||||
|
||||
Que `dev_console issue list/board/work` y los flujos que dependen de `LoadAllIssues`/`LoadOpenIssues` recorran `dev/issues/` de forma recursiva, excluyendo `dev/issues/completed/`, manteniendo el resto del comportamiento idéntico.
|
||||
|
||||
## Tareas
|
||||
|
||||
- [ ] Localizar la implementación de `LoadAllIssues` / `LoadOpenIssues` en `apps/dev_console/` (probable `parser.go` o equivalente).
|
||||
- [ ] Cambiar el escaneo a `filepath.WalkDir` (o glob recursivo) bajo `dev/issues/`, saltando el directorio `completed/`.
|
||||
- [ ] Mantener el orden de salida estable (ordenar por `id`).
|
||||
- [ ] Recompilar el binario en el sub-repo de `dev_console` siguiendo TBD (`issue/0179-...`).
|
||||
|
||||
## Definition of Done
|
||||
|
||||
| Escenario | Tipo | Comando / evidencia | Resultado esperado |
|
||||
|---|---|---|---|
|
||||
| Golden: lista incluye subcarpetas | e2e | `./apps/dev_console/dev_console issue list` | Aparecen issues de `cpp/`, `kanban/`, `trading/`, etc. (>= 49 que antes faltaban) |
|
||||
| Edge: excluye completed/ | e2e | `dev_console issue list` | Ningún issue con `status: completado` de `completed/` aparece en el listado activo |
|
||||
| Edge: conteo total coincide con /issue | e2e | comparar conteo con el glob recursivo de `/issue` | Mismo total de activos |
|
||||
| Error: dev/issues vacío o ausente | unit | run en dir sin `dev/issues/` | Error claro, no panic |
|
||||
|
||||
## Notas
|
||||
|
||||
Hermano del cambio ya hecho en `.claude/commands/issue.md` (glob `**/*.md`). Hasta cerrar este issue, usar `/issue` (no `dev_console`) para vistas completas del backlog.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: "0180"
|
||||
title: "Modo ausente sobre la cola de issues: parametrizar /ausente + DAG dag_engine + validación"
|
||||
status: pendiente
|
||||
type: infra
|
||||
domain:
|
||||
- meta
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0179"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-06-30
|
||||
updated: 2026-06-30
|
||||
tags: []
|
||||
---
|
||||
# 0180 — Modo ausente sobre la cola de issues (parametrizar /ausente + DAG + validación)
|
||||
|
||||
## Contexto
|
||||
|
||||
Modelo de colaboración acordado (ver memoria `modelo-colaboracion-ausente`): durante la jornada de oficina (L–J 10–14 / 15–19, V 10–16) y la noche (01–09), Claude trabaja en `/ausente` la cola de issues `ausente-ready` (39 issues hoy), sin supervisión. La curación del backlog ya está hecha (triage, taxonomía, deps de series formalizadas, tag `ausente-ready`).
|
||||
|
||||
Faltan 3 piezas para automatizarlo de forma segura.
|
||||
|
||||
## Problemas a resolver
|
||||
|
||||
1. **`/ausente` está acoplado al roadmap ComfyUI.** El skill (`.claude/commands/ausente.md`) hardcodea su backlog a funciones ComfyUI (secciones "Configuración" y "Backlog del roadmap ComfyUI"). Hay que **parametrizar la fuente de tareas** para que pueda tomar la cola de issues: la siguiente tarea = primer issue de `/issue list -t ausente-ready` cuyas `depends` estén todas en `completed/`, re-cruzando deps en cada ciclo (un issue se libera cuando su dep se cierra).
|
||||
2. **Lanzamiento headless desde dag_engine.** `dag_engine` ejecuta steps (command/script/function), no abre una sesión Claude interactiva. Hay que resolver cómo un step arranca una sesión `role=orchestrator` en modo `/ausente` (candidatos: `launch_claude_agent_kitty_bash_infra` con DISPLAY, o `spawn_fleet_agent_bash_infra` si hay sesión tmux fleet) con el prompt autónomo + presupuesto.
|
||||
3. **Presupuesto conservador aplicado.** Tope: 1–2 ejecutores concurrentes, solo issues S/M, ~1M tokens por franja, parada al llegar. Materializar el tope de tokens (hoy `orchestration.md` solo fija fan-out=6).
|
||||
|
||||
## Schedule objetivo (cuando se active)
|
||||
|
||||
- Inicio de franjas de oficina: `0 10 * * 1-5` (10:00 L–V) y `0 15 * * 1-4` (15:00 L–J, tras comida).
|
||||
- Nocturno: `0 1 * * *` (01:00 diario).
|
||||
- El modo, una vez lanzado, itera con `ScheduleWakeup` hasta que el humano vuelve (para al recibir prompt humano).
|
||||
|
||||
Borrador del DAG: `apps/dag_engine/dags/ausente-issues-queue.yaml` (creado como DRAFT sin schedule activo).
|
||||
|
||||
## Definition of Done
|
||||
|
||||
| Escenario | Tipo | Comando / evidencia | Resultado esperado |
|
||||
|---|---|---|---|
|
||||
| Golden: corrida manual | e2e | lanzar `/ausente` con backlog=issues sobre 1 issue S de la cola | Coge el issue, lo implementa en worktree/sub-repo aislado, cierra DoD verde (golden+edge+error), push, bitácora actualizada |
|
||||
| Edge: dep no satisfecha | e2e | cola con un issue cuya `depends` sigue activa | NO lo coge; pasa al siguiente arrancable |
|
||||
| Edge: flota llena | e2e | 2 ejecutores activos (tope conservador) | Encola el resto, no lanza el 3.º |
|
||||
| Error: presupuesto agotado | e2e | tope de tokens alcanzado | Para limpio, deja bitácora con lo pendiente, no deja agentes huérfanos |
|
||||
| Vida útil | observabilidad | tras activar cron, 1 semana | Issues cerrados/semana > 0, 0 merges rotos a master, bitácora legible |
|
||||
|
||||
## Plan
|
||||
|
||||
1. Cerrar `0179` (dev_console recursivo) — dependencia.
|
||||
2. Parametrizar `/ausente` (fuente de backlog = issues ausente-ready | roadmap; pasar la fuente al invocar).
|
||||
3. Resolver el step de lanzamiento headless + presupuesto de tokens.
|
||||
4. **Validación manual** (golden + edges) antes de activar el cron.
|
||||
5. Activar schedule en el DAG + `systemctl --user restart dag_engine.service` con `--scheduler`.
|
||||
|
||||
## Notas
|
||||
|
||||
Este issue NO es `ausente-ready` a propósito: requiere decisiones de diseño humanas (mecanismo de lanzamiento, forma del presupuesto) y toca el propio sistema que orquesta el modo ausente. Se hace JUNTOS, no desatendido.
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0059"
|
||||
title: "Resolver doble tracking de `apps/*/app.md` (fn_registry + sub-repo)"
|
||||
status: pendiente
|
||||
status: completado
|
||||
type: infra
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "55"
|
||||
title: "Roadmap de prereqs — issues de osint_graph que odr_console necesita antes/durante MVP"
|
||||
status: pendiente
|
||||
status: deferred
|
||||
type: epic
|
||||
domain:
|
||||
- osint
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0087"
|
||||
title: "Capability Discovery Acceleration"
|
||||
status: pendiente
|
||||
status: completado
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0096"
|
||||
title: "Estandarizar ubicacion de apps: fuera de carpetas por lenguaje"
|
||||
status: pendiente
|
||||
status: completado
|
||||
type: feature
|
||||
domain:
|
||||
- apps-infra
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0101"
|
||||
title: "dev_console Go binario: /issue /flow /work unificados"
|
||||
status: pendiente
|
||||
status: completado
|
||||
type: app
|
||||
domain:
|
||||
- meta
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0103"
|
||||
title: "Taxonomia + slash commands /issue /flow /work"
|
||||
status: pendiente
|
||||
status: completado
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0105"
|
||||
title: "Estandarizar bloque service: en app.md + indexer + fn doctor services-spec"
|
||||
status: in-progress
|
||||
status: completado
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0109g"
|
||||
title: "skill_tree: panel terminal embebida (claude TUI dentro de la app)"
|
||||
status: pendiente
|
||||
status: deferred
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
@@ -19,7 +19,7 @@ related:
|
||||
- "0102"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags: [dod, evidence, frontmatter, taxonomy, validator]
|
||||
tags: [dod, evidence, frontmatter, taxonomy, validator, ausente-ready]
|
||||
flow: "0008"
|
||||
---
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ blocks:
|
||||
related: []
|
||||
created: 2026-05-22
|
||||
updated: 2026-05-22
|
||||
tags: [agents_and_robots, http, sse, apikey, traefik, systemd]
|
||||
tags: [agents_and_robots, http, sse, apikey, traefik, systemd, ausente-ready]
|
||||
dod_evidence_schema:
|
||||
- id: build_ok
|
||||
kind: cmd
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0153"
|
||||
title: "matrix-client-pc agent integration: paneles para rooms operados por agentes"
|
||||
status: pending
|
||||
status: deferred
|
||||
priority: medium
|
||||
created: 2026-05-24
|
||||
related_flows: ["0010", "0009"]
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0164"
|
||||
title: "Bots agents_and_robots: cryptohelper.Init() cuelga al habilitar encryption=true"
|
||||
status: pending
|
||||
status: deferred
|
||||
priority: high
|
||||
created: 2026-05-24
|
||||
related_flows: ["0009"]
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: ["0167", "0168"]
|
||||
created: 2026-05-24
|
||||
updated: 2026-05-24
|
||||
tags: [matrix, livekit, webrtc, turn, nat]
|
||||
tags: [matrix, livekit, webrtc, turn, nat, ausente-ready]
|
||||
---
|
||||
# 0166 — Desplegar TURN para LiveKit (coturn o integrado)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0171"
|
||||
title: "Manifest de sub-repos por project + re-clonado y auditoría de cobertura en Gitea"
|
||||
status: pendiente
|
||||
status: completado
|
||||
type: enhancement
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0173"
|
||||
title: "EDA: bugs críticos de correctitud estadística (outlier_pct ×100, distribution_type por-skew)"
|
||||
status: resuelto
|
||||
status: completado
|
||||
type: bugfix
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0174"
|
||||
title: "EDA series temporales: período estacional roto + correlación de niveles + to_returns ciego"
|
||||
status: resuelto
|
||||
status: completado
|
||||
type: bugfix
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0175"
|
||||
title: "EDA relational: precisión de FK inference (falsos positivos) + filtrar VIEWs + test ATTACH"
|
||||
status: resuelto
|
||||
status: completado
|
||||
type: bugfix
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0176"
|
||||
title: "EDA render: models/series/caveats en markdown+PDF + PDF para profile_database"
|
||||
status: resuelto
|
||||
status: completado
|
||||
type: feature
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0177"
|
||||
title: "EDA tipos: id secuencial fuera de correlación/PCA + η² espurio por cardinalidad + re-expresión no-continuas"
|
||||
status: resuelto
|
||||
status: completado
|
||||
type: bugfix
|
||||
domain:
|
||||
- registry-quality
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
# 0033 — C++ http_inspector + websocket_client
|
||||
|
||||
+1
-4
@@ -13,10 +13,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags:
|
||||
- gamedev
|
||||
- cpp
|
||||
- wasm
|
||||
tags: [ausente-ready, gamedev, cpp, wasm]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
+1
-1
@@ -13,7 +13,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-13
|
||||
updated: 2026-05-17
|
||||
tags: []
|
||||
tags: [ausente-ready]
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
+1
-1
@@ -15,7 +15,7 @@ related:
|
||||
- "0106"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags: [http, cpp, registry-gap, curl, helper]
|
||||
tags: [http, cpp, registry-gap, curl, helper, ausente-ready]
|
||||
---
|
||||
|
||||
# 0110 — Helper HTTP cliente C++ en el registry
|
||||
+1
-2
@@ -8,8 +8,7 @@ domain:
|
||||
- dev-ux
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends:
|
||||
- "0130b"
|
||||
depends: ["0130b"]
|
||||
blocks: []
|
||||
related:
|
||||
- "0130"
|
||||
+1
-1
@@ -16,7 +16,7 @@ related:
|
||||
- "0131"
|
||||
created: 2026-05-22
|
||||
updated: 2026-05-22
|
||||
tags: [cpp, imgui, terminal, pty, module]
|
||||
tags: [cpp, imgui, terminal, pty, module, ausente-ready]
|
||||
flow: ""
|
||||
---
|
||||
|
||||
+1
-2
@@ -7,8 +7,7 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends:
|
||||
- "0072a"
|
||||
depends: ["0072a"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+1
-2
@@ -7,8 +7,7 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends:
|
||||
- "0072b"
|
||||
depends: ["0072b"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+1
-3
@@ -7,9 +7,7 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends:
|
||||
- "0072a"
|
||||
- "0072b"
|
||||
depends: ["0072a", "0072b"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+1
-3
@@ -7,9 +7,7 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends:
|
||||
- "0072a"
|
||||
- "0072d"
|
||||
depends: ["0072a", "0072d"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+1
-2
@@ -7,8 +7,7 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: media
|
||||
depends:
|
||||
- "0072e"
|
||||
depends: ["0072e"]
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user