Full walk of Form (largest finding set in the project):
- Morfo: validated. 14 parts — Provider/Submit/Reset/ErrorSummary +
9 AutoFields parts for the reflective renderer. Provider declares
data-pending/dirty/touched/invalid/submitted on the contract. Sema
events `commit-submit` (fulfill), `signal-invalid` (risk),
`commit-reset` (neutral) are correct.
- `texts.label` added with catalog entry (`label = 'Formulario' / 'Form'`).
- Recipe CSS: `[data-form][data-invalid]` rule added. Low-emphasis
affordance — the ErrorSummary picks up the risk border but field
cells keep their own `[data-invalid]` styling via the Field recipe.
- README rewritten with canonical sections:
- `## Baseline` summarizing air / soma / morfo coverage
- `## Comparativa` (was `## Reference Comparison`) — extended to
include shadcn-svelte plus AutoFields differentiators
(discriminated unions, array fields, first-error focus,
validation timing modes)
- `## Decisiones` documenting the small-wrapper rule, AutoFields
exception, validation timing ownership, the no-noise-on-load
default, sema event placement, and the low-emphasis invalid
treatment
- `## Gaps` (new) with disposition markers — apg is `descartar`
(no APG for "Form" — APG covers individual widgets), AutoFields
i18n is `implementar`, multi-step / submission feedback / etc.
are `diferir`, auto-save / optimistic UI are `descartar`
Audit script refinement:
- R-1.2 (data-disabled styles) now only fires when the morfo
*declares* `data-disabled` on any part. Form's Provider doesn't
emit a disabled state at the root (individual fields handle it
themselves), so demanding defensive CSS for a state the contract
never emits was a false-positive. The rule still fires correctly
for components that DO declare `data-disabled` in their morfo.
Audit: PASS 7 → 8. Form flips to PASS with only one remaining
warn (`A-1.4` no apg URL — `descartar` documented as a gap).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- **Demos arrancan con defaults válidos**: `onChange` validaría
inmediatamente y mostraría errores antes de que el usuario edite, lo
cual es ruido perceptivo. Sólo demos que explícitamente quieran un
estado inválido inicial parten así.
- **Sema sólo en commit-submit / signal-invalid / commit-reset**: los
cambios per-field son del Field, no del Form. El Form sólo emite en
los momentos donde el "todo" cambia (envío, fallo de validación
global, reset).
- **`data-invalid` en el root es una señal de bajo énfasis**: marca el
ErrorSummary con borde risk pero NO repinta los fields individuales —
esos tienen su propio `[data-invalid]` desde el Field recipe.
## Gaps
| Gap | Disposición | Detalle |
| --- | --- | --- |
| `apg` URL canónica | **descartar** | No hay un APG específico para "Form"; APG cubre widgets individuales. El form HTML nativo es la referencia accesibilidad. |
| Action confirmation modal antes de submit destructivo | **diferir** | Caso aún sin patrón. Cuando aparezca, vive en Dialog/AlertDialog que el consumer monta dentro de `Form.Submit`. |
| AutoFields i18n (labels desde el schema) | **implementar** | SIUM `meta({ label })` resuelve por idlangref. Falta documentar el patrón y validar con `translations:check`. |
| Multi-step form / wizard | **diferir** | Composición sobre Stepper + Form. No es responsabilidad de Form. Sin patrón canónico definido aún. |
| Submission feedback (toast on success) | **diferir** | El consumer decide; el contrato de Form ya emite `commit-submit` para que un sema listener arme el toast. |
| Optimistic UI rollback | **descartar** | Patrón de aplicación; Form no debe asumir transport. |
| Auto-save / draft persistence | **descartar** | Fuera de scope visual; vive en `$libs/forms` si fuera necesario. |