| Semana y locale | `firstDayOfWeek` puede sustituir el valor del locale | `locale` y `startOfWeek` son entradas distintas | `locale` y `weekStartsOn` son props de Root | No ofrece primitiva Calendar | Compartir sólo el cálculo que ya respeta locale o sustitución explícita. |
| Selección | RangeCalendar conserva su valor de rango | Un mismo DatePicker admite modos de selección | Calendar y RangeCalendar son familias públicas separadas | No hay contrato comparable | Mantener providers, estado y eventos separados. |
| Mes y año | Las fechas se presentan según locale | El formateo recibe los datos de locale | Ambos componentes exponen formato de mes y año | No hay contrato comparable | Centralizar únicamente la función pura usada por ambos providers y sus selects. |
Propiedad exclusiva de Soma: los helpers permanecen en el módulo puro existente de
Calendar, que RangeCalendar ya consume. No se crea otro provider ni otra capa, y
no se modifican partes, props, eventos, tamaños, variantes, colores, demos, estilos,
selección, anuncios o efectos. El pre-flight y su alcance quedan aceptados por la
instrucción vigente de continuar el plan con refactorizaciones neutrales. La
validación exige línea base y repetición de los tests de ambos providers y helpers,
`check:gate`, auditoría dirigida de ambos componentes y gate completo.
Resultado: cinco familias de funciones duplicadas delegan ahora en tres helpers
puros. Calendar y RangeCalendar conservan sus providers, métodos públicos,
precedencia de formatos y lógica de selección. El diff de producción elimina 88
líneas e incorpora 69: **19 líneas netas menos**. Los tres archivos dirigidos
pasaron 28/28 pruebas antes y 29/29 después, incluida la regresión de dependencia
reactiva; el barrido AST transversal bajó de 13 a 8 grupos de funciones idénticas
en Soma. `docs:check` terminó con 0 errores y 0 avisos, `check:gate` aceptó los 89
errores del ledger, las dos auditorías dirigidas dieron PASS y el gate completo
pasó **473/473 archivos y 5484/5484 pruebas**, incluidos build y smoke de
`apps/base`.
### Pre-flight de Soma para las partes de ítem de los dos menús (2026-09-22)
El usuario autorizó la deduplicación interna sin cambios de comportamiento, API
| Duplicación exacta | `SpinPressRepeater` + factory en el barrido inicial | Resuelto en módulo compartido; mantener pruebas de pulsación y cancelación. |
| Contrato compartido | CalendarNav y `gridWalk` ya cubren cabecera, paginación y teclado | Mantener providers separados: límites de vista, título y selección no son intercambiables |
| Riesgo funcional | L-138: retorno de foco de Dialog/Drawer | Mantenerlo como defecto de accesibilidad reproducible, fuera de refactor neutro |
| Riesgo funcional | L-140: Select.Value no conserva etiqueta con portal cerrado | Corregir sólo tras decidir owner persistente de value→label |
| Revisión masiva | L-152: reenvío de `bind:ref` en wrappers Eidos/Soma | Auditoría por familia y prueba cliente por wrapper; no sustitución global |
| Duplicación exacta | `SpinPressRepeater` + factory en el barrido inicial | Resuelto en módulo compartido; mantener pruebas de pulsación y cancelación. |
| Contrato compartido | CalendarNav, `gridWalk` y helpers puros cubren navegación y formato | Mantener providers separados: límites de vista, título y selección no son intercambiables |
| Riesgo funcional | L-138: retorno de foco de Dialog/Drawer | Mantenerlo como defecto de accesibilidad reproducible, fuera de refactor neutro |
| Riesgo funcional | L-140: Select.Value no conserva etiqueta con portal cerrado | Corregir sólo tras decidir owner persistente de value→label |
| Revisión masiva | L-152: reenvío de `bind:ref` en wrappers Eidos/Soma | Auditoría por familia y prueba cliente por wrapper; no sustitución global |