Compare commits

..

1 Commits

Author SHA1 Message Date
Egutierrez 9a7a874a76 fix(infra): audit_uses_functions detecta imports Python anidados y multilinea (0056)
El parser Python de audit_uses_functions solo reconocia "from <pkg> import X"
con un unico componente de paquete (regex \w+), por lo que:

- "from <pkg>.<subpkg> import X" (import anidado) no matcheaba y la funcion se
  reportaba como falso unused_in_app_md.
- Las listas multilinea con parentesis "from <pkg> import (\n a,\n b,\n)" no se
  parseaban (escaneo linea a linea).

Cambios:
- Regex acepta puntos en el paquete y bloques parentizados multilinea.
- Resolucion validada contra el directorio de paquete del registry derivado de
  file_path (no del campo domain: las funciones metabase viven en
  python/functions/metabase/ pero tienen domain=infra). Imports de librerias
  externas se ignoran -> sin falsos missing.
- parsePyImportedSymbols descarta comentarios "# noqa", maneja "as alias" y
  star imports (tratados como vacio, no soportados por diseno).
- auditFnMeta carga file_path; query SELECT anade file_path.

Tests (functions/infra/audit_uses_functions_test.go):
- TestAuditUsesFunctions_DetectsNestedImport (golden)
- TestAuditUsesFunctions_NoFalsePositiveOnNested (edge: nested + multilinea)
- TestAuditUsesFunctions_StarImport (error/edge: star import no cuenta)

Verificado con fn doctor uses-functions sobre apps reales: drift baja de 11/42 a
9/42. mail_manager (9 falsos por "from infra.X import Y") y demand_radar (3 por
lista multilinea) quedan en 0 drift. El residual de osint_db/osint_web es carga
dinamica via importlib, documentado como fuera de alcance.

audit_uses_functions v1.0.0 -> v1.1.0. CHANGELOG actualizado.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 13:10:31 +02:00
233 changed files with 525 additions and 19019 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": [
+4
View File
@@ -8,6 +8,10 @@ Para contexto detallado del trabajo diario ver `docs/diary/`. Para decisiones ar
## [Unreleased]
### Fixed
- **`audit_uses_functions` detecta imports Python anidados y multilinea** (issue 0056) — el parser Python ahora reconoce `from <pkg>.<subpkg> import X` (antes la regex `\w+` rompia ante el punto y la funcion se reportaba como falso `unused_in_app_md`) y listas multilinea con parentesis `from <pkg> import (\n a,\n b,\n)`. La resolucion se valida contra el directorio de paquete del registry derivado de `file_path` (no del campo `domain`: las funciones `metabase` viven en `python/functions/metabase/` pero tienen `domain=infra`), e ignora imports de librerias externas. Aliases (`as`) y comentarios (`# noqa`) se descartan. Star imports (`from pkg import *`) y carga dinamica (`importlib`) quedan documentados como no soportados. Verificado: `fn doctor uses-functions` baja de 11/42 a 9/42 apps con drift — `mail_manager` (9 falsos positivos por `from infra.X import Y`) y `demand_radar` (3 por lista multilinea `from datascience import (...)`) quedan en 0 drift; el residual de `osint_db`/`osint_web` es carga dinamica via wrapper, fuera de alcance. `audit_uses_functions` v1.0.0 → v1.1.0.
## 2026-05-17
### Added
+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"]
+2 -2
View File
@@ -1,8 +1,8 @@
---
id: "0149"
title: "matrix-client-pc composer: markdown, reply, edit, reactions, media"
status: pendiente
priority: alta
status: pending
priority: high
created: 2026-05-24
related_flows: ["0010"]
related_issues: ["0148", "0150"]

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