Auditoría post-Fase 5b — deudas y mejoras¶
Documento generado tras cerrar Fase 5b (codegen a binario nativo). Identifica deudas técnicas, gaps de docs, mejoras de calidad/UX. No ejecuta fixes — es input para decidir qué atacar y en qué orden.
🟢 Body form-urlencoded → tipo declarado en fitz run (CERRADO v0.50.0, 2026-08-20)¶
El gap (clase FITZ-14, paridad run↔build): un handler @post fn login(creds:
Credentials) que recibía un body application/x-www-form-urlencoded deserializaba al
type declarado en fitz build (confirmado sobre el binario, A5 refutado), pero en
fitz run el body llegaba como un Value::Map crudo en vez de una Instance → un
creds.user explotaba con "field access .user on a value of type Map" (500). El
path JSON sí coercía; el form-urlencoded no. Bloqueaba el login zero-JS
(<form method=POST>, el caso canónico de FITZ-05 + MatHelp) en el intérprete.
El fix (src/http.rs, parse_urlencoded_body): en vez de armar un Value::Map
directo, ahora construye un serde_json::Value::Object all-string (paralelo bit-a-bit al
__parse_urlencoded del codegen) y reusa el MISMO path de coerción que el body JSON
(parse_body): json_to_instance(&obj, t) cuando hay tipo declarado, json_to_value
(free Map<Str, Str>) cuando no. El codegen ya hacía esto (__parse_urlencoded →
__from_fitz_json), así que el fix es puro alineamiento del intérprete → paridad
bit-a-bit. Defaults/nullables aplicados igual que en JSON; body vacío con tipo declarado
→ defaults o "missing field" claro. Los 3 tests urlencoded existentes (body libre,
declared_type: None) quedan idénticos (json_to_value da el mismo Map, preserve_order
mantiene el orden). 2 tests nuevos en http::tests (e2e_fitz05_form_urlencoded_*:
typed body + defaults/nullables). Smoke real: login POST form-urlencoded → 2 Set-Cookie
idénticos en fitz run y en el binario.
🟢 Deuda A — fitz check valida los módulos .fitz importados (CERRADO v0.43.0, 2026-08-18)¶
El gap: fitz check sobre un .fitz clásico chequeaba solo el entry.
Los módulos importados nunca se parseaban ni type-checkeaban — solo se
pre-escaneaban señales (auth provider W12 / background B10 / live components
§9.bb). Un error de sintaxis (o de tipos) en un módulo importado pasaba
fitz check limpio y solo explotaba en fitz run (parse) o fitz build
(type-check del loader). El repro que lo destapó: un Err(_) => return, bare
(return como valor de arm) en un empleados.fitz importado.
El fix (src/main.rs, ~180 LoC, sin tocar el checker ni el codegen): el
entry rutea por check_file_with_deps (dep-aware) que, tras chequear el entry,
llama check_imported_fitz_modules — un walker que recorre el grafo de imports
(transitivo) y corre lexer + parser + check_program_with_context sobre cada
módulo local .fitz. Decisiones:
- Walker dedicado, NO reuso del codegen::ModuleLoader — el loader corre
codegen por módulo (emite .rs), lo que agrega superficie de fallo y peores
diagnósticos (solo el primer error, sin span). El walker reusa las piezas que
importan (resolve_import_file_path, los pre-scans, el checker) con cero
acoplamiento al codegen.
- Contexto del proyecto heredado (ProjectCheckContext): el provider / bg
fns / live components pre-escaneados de los imports DIRECTOS del entry se pasan
como fallback a cada módulo (paralelo a los main_imported_* del loader). Sin
esto, un handler @authenticated en comments.fitz (que no importa
auth.fitz, lo cablea main.fitz — patrón B12) daría un falso positivo. El
módulo propio gana; lo que no declara cae al contexto del proyecto.
- .fitzv se saltean en el walk (cubiertos por el sweep a2 + el pipeline de
view). Deps externas de fitz.toml se saltean (build las valida).
- Ciclos + dedup por visited set de paths canónicos.
- Errores agregados (no aborta al primero); el entry sigue siendo dueño de
su propio reporte. check_file (wrapper viejo) se eliminó — todo pasa por
check_file_with_deps.
7 tests cli_e2e (deuda_a_check_*). Smoke verde sobre api-orm-full /
api-orm-full-fullstack / api-fullstack-postgres (multi-módulo con B12 +
subcarpetas). Actualiza el comment de Commands::Check (que decía "does NOT
recurse into imported modules").
Deudas residuales derivadas (NO bloquean, refinables si aparece demanda):
- Un nivel de profundidad del project context: el provider/bg/live heredado
se pre-escanea de los imports DIRECTOS del entry (paralelo al loader). Si el
provider viviera en un módulo importado transitivamente (no directo del entry),
un módulo hermano podría dar falso positivo. El patrón canónico (main importa
todos los módulos) lo cubre.
- Un .fitz importado desde un .fitzv no lo alcanza el walker (skipeamos
el .fitzv); lo cubre el pipeline de view del .fitzv.
- import_root fallback parcial: el walker resuelve contra el dir del módulo
importador, con fallback al dir del entry — no replica el import_root exacto
del loader del codegen para todos los layouts anidados raros (el loader tiene
su propia lógica). Los layouts probados (subcarpetas src/types/, src/data/)
resuelven bien.
🟢 Paso 0 SSR isomórfico — to_json en fitz build sin HTTP (CERRADO 2026-08-07)¶
Fix aplicado (2026-08-07): se extrajo el core de serialización JSON
(axum-free) de HTTP_RUNTIME_PRELUDE a un JSON_SERIALIZE_PRELUDE
independiente en src/codegen.rs — los dos traits __ToFitzJson /
__FromFitzJson + los impls de primitivos/contenedores (Option, Vec,
Arc<Mutex>, Vec<(K,V)>, Result) + __MapKey/__MapKeyFromStr +
__json_shape. HTTP_RUNTIME_PRELUDE conserva solo los tipos de dominio
HTTP (Request/Response/File) + el glue axum (__apply_cors_and_respond)
+ los parsers urlencoded/multipart. El JSON prelude se emite cuando
has_http || uses_to_json, antes del HTTP prelude (los impls de dominio
dependen de los traits; Rust resuelve impls sin importar orden, así que el
output HTTP es funcionalmente idéntico). Nuevo detector program_uses_to_json
(walk del AST, call de ident pelado — paralelo a program_uses_smtp), campo
CodegenCtx.uses_to_json + transitividad por módulo (LoadedModule) + mirror
lado-módulo (use crate::{__ToFitzJson, __FromFitzJson}), gating de los
per-type impls (gen_type_http_impls + emit_helpers_for_imported_types) por
has_http || uses_to_json, y serde_json (con preserve_order) al Cargo.toml
generado cuando uses_to_json y ningún otro branch ya lo trajo (sin
duplicar). Un fitz build de un CLI puro con to_json ahora solo linkea
serde_json (sin axum ni tokio) y produce output bit-a-bit idéntico a
fitz run (validado a mano + E2E to_json_in_pure_cli_build_matches_interpreter
en tests/compile_e2e.rs). Tests: +5 unit codegen (to_json_in_pure_cli_*,
program_uses_to_json_*, cargo_toml_*_serde_json*) + 1 E2E. 4024 lib
(default) + 4185 (lsp) verdes; fmt + clippy -D warnings (default + lsp)
limpios. Divergencias run/build menores siguen (Float NaN/Inf, Bytes,
Map con clave nominal) — ver detalle histórico abajo.