|
|
# CONTINUE — Familia `commerce` del tier `blocks`
|
|
|
|
|
|
> **Kickoff para sesión nueva**: _«Lee `docs/process/CONTINUE-blocks-commerce.md`
|
|
|
> y continúa la fase que toque.»_
|
|
|
>
|
|
|
> **Estado 2026-08-10: DISEÑO CERRADO, CERO CÓDIGO ESCRITO.** Las decisiones
|
|
|
> D-COM.1…5 están firmadas por el usuario. La fase **C0** (dossier + plan de
|
|
|
> ejecución + grupo en el catálogo + entrada en `next-features.md`) está
|
|
|
> **pendiente**: este handoff es lo único que existe todavía.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 0. Qué es esto y por qué existe
|
|
|
|
|
|
Una familia de **26 blocks de ecommerce** más **8 componentes de canon** y un
|
|
|
**art nuevo `$commerce`**, diseñada con el mismo método con que nació el tier:
|
|
|
analizar lo hecho → comparativa contra las referencias reales de cada
|
|
|
ecosistema → fijar suelo de paridad → producir la lista.
|
|
|
|
|
|
El punto de partida, en tres hechos:
|
|
|
|
|
|
1. **No existía una sola línea de dominio commerce en el repo.** Barrido de
|
|
|
`cart · checkout · product · sku · order · basket · storefront · payment`
|
|
|
sobre `src/ · web/ · scripts/`: nada. Lo único adyacente es el block
|
|
|
`pricing`, que es comparativa de planes SaaS y cuyo README declara
|
|
|
explícitamente que **no formatea moneda**. `billing` figuraba diferido en F5
|
|
|
de [`PLAN-blocks.md`](./PLAN-blocks.md).
|
|
|
2. **El canon ya resuelve casi todo lo que un catálogo commerce exige** (§3), y
|
|
|
por eso la lista de huecos es corta y cada uno tiene motivo escrito.
|
|
|
3. **La doctrina de coordinación (2026-07-31) es justo lo que commerce pide.**
|
|
|
Hoy sólo 3 de 15 blocks coordinan y sólo 2 tienen máquina de estado.
|
|
|
Commerce invierte esa proporción — **14 de 26 coordinan** — porque casi todo
|
|
|
lo que se vende puede estar bloqueado. **El diseño arranca por el estado,
|
|
|
nunca por el layout.**
|
|
|
|
|
|
---
|
|
|
|
|
|
## 1. Puerta de lectura — antes de tocar nada
|
|
|
|
|
|
Precondición dura, no sugerencia. Leer **directo**, nunca delegando la lectura
|
|
|
a agentes.
|
|
|
|
|
|
- Siempre: `CLAUDE.md` (llega solo) · este handoff.
|
|
|
- Contrato del tier: [`architecture/blocks.md`](../architecture/blocks.md)
|
|
|
(B-1…B-11, la regla de admisión, la sección «Coordination»).
|
|
|
- Para un componente de canon: [`building-a-component.md`](../building-a-component.md)
|
|
|
(la ruta de 9 fases, LA puerta) + [`guides/component-guide.md`](../guides/component-guide.md)
|
|
|
(§Build contract + reglas A1–A37) + [`guides/completion-checklist.md`](../guides/completion-checklist.md)
|
|
|
(la matriz de aceptación).
|
|
|
- Vocabulario cerrado: [`canon/vocabularies.md`](../canon/vocabularies.md)
|
|
|
(generado del código — archetypes, familias, verbos, intents, holds).
|
|
|
- Contratos transversales: [`canon/tsc.md`](../canon/tsc.md) ·
|
|
|
[`canon/recipe-contract.md`](../canon/recipe-contract.md) ·
|
|
|
[`canon/direction-contract.md`](../canon/direction-contract.md).
|
|
|
- Para el ala agéntica: [`architecture/agent.md`](../architecture/agent.md)
|
|
|
(§5 el primitivo de actor, §7 la superficie de revisión).
|
|
|
- **Y el README de CADA componente que el block compone.** El mapa de
|
|
|
composición se escribe leyendo, no de memoria.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 2. Las decisiones firmadas (D-COM.1…5, 2026-08-10)
|
|
|
|
|
|
| # | Decisión | Consecuencia operativa |
|
|
|
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| **D-COM.1** | El estado del carrito vive en un **art nuevo `$commerce`** (`EngineCommerce`/`ActiveCommerce` + port de transporte que suministra el app), espejo de `$agent`/`AgentTransport` | Un carrito vive en cabecera, PDP, carrito y checkout: es estado **inter-block**, y B-10 prohíbe que un block importe otro. B-4 deriva `$<art>` de `src/arts/*`, así que la carpeta lo allowlista sola |
|
|
|
| **D-COM.2** | Alcance: alas **A+B+C+D+E** (26 blocks). Admin FUERA. **B2B diferida con disparador** | Admin lo cubre F3 (`data-table`, `dashboard`, `settings`), y ningún design system serio shippea commerce admin. B2B se registra en `next-features.md` |
|
|
|
| **D-COM.3** | La ley europea entra en el **TIPO**, más un token `jurisdiction` en el contexto comercial de `$commerce` | `priorPrice{amount, basis:'lowest-30d'}` obligatorio en rebaja · `taxIncluded` no opcional · `unit` cuando se vende por medida. No en `$prefs`: no es preferencia del usuario |
|
|
|
| **D-COM.4** | La procedencia por actor es **hilo, no apéndice** | `actor` nace en la línea de carrito en C2; el ala E la renderiza al final sin reabrir nada |
|
|
|
| **D-COM.5** | Grupo **«Commerce»** en `_lib/catalog.ts`; slugs sin prefijo salvo colisión | `cart`, no `commerce-cart`; pero `commerce-header`, igual que `site-header` |
|
|
|
|
|
|
**Dos cabos abiertos que resuelve la fase 0 de C2, no antes:**
|
|
|
|
|
|
1. ⚠️ **`$commerce` sería el primer art de DOMINIO.** Los 25 actuales son
|
|
|
infraestructura transversal (`adom`, `color`, `motion`, `prefs`…). O se
|
|
|
acepta explícitamente y se anota en `src/arts/README.md`, o se enmienda la
|
|
|
doctrina de arts. **No se cuela en silencio.** `src/svrs/commerce` no sirve:
|
|
|
B-4 no admite `$svrs` desde un block.
|
|
|
2. **El objeto de valor de dinero vive en una hoja por debajo del art y de
|
|
|
eidos**, para evitar el ciclo — mismo patrón que el `ActorToken`, cuyo tipo
|
|
|
vive bajo orca y agent mientras la autoridad de acuñación queda en
|
|
|
`EngineAgent`. Candidato: `src/libs/money`, junto al `src/libs/currency` que
|
|
|
ya existe.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 3. Lo que el canon YA resuelve (no lo reinventes)
|
|
|
|
|
|
Medido sobre los 167 slugs de `src/uix/eidos/components/`, 100 con pila
|
|
|
completa morfo+soma+eidos:
|
|
|
|
|
|
| Necesidad | Se compone con |
|
|
|
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| Rejilla de producto | `AutoGrid` / **`CardGroup`** (ya es rejilla **seleccionable**) + `Card` + `AspectRatio` + `Image` + `Badge` |
|
|
|
| Estrellas | **`RatingGroup`** (`allowHalf · hoverPreview · clearable · readonly · valueText`) |
|
|
|
| Cantidad | **`NumberField`** (`min/max/step/largeStep · clampOnBlur · Increment/DecrementTrigger · Scrubber`) |
|
|
|
| Dinero | **`FormatNumber`** (`formatStyle="currency"`) + `Text numeric="tabular"` |
|
|
|
| **Divisa y conversión** | **`$format.currency`**: `setCurrency · format · formatAs · convert/convertAs` + `createRates({ fetchRate })`. **Ninguna referencia del mundo tiene esto** |
|
|
|
| Galería | `Carousel` + `Image` + `AspectRatio` (falta zoom/lightbox → §4) |
|
|
|
| Variantes | `RadioCards` · `ToggleGroup` · `ColorSwatch` (falta el eje de disponibilidad → §4) |
|
|
|
| Checkout | **`Stepper`** (`linear`) + `Form` + `Field` + **`Form.AutoFields`** + esquema SIUM |
|
|
|
| Carrito | `Drawer` + `Table`/`GridList` + `NumberField` + `EmptyState` |
|
|
|
| Facetas | `Accordion` + `CheckboxGroup` + **`Slider type="multiple"`** (ES el rango de precio) + `TagGroup` + `Combobox` |
|
|
|
| Pedidos | `Table` + `$libs/datagrid` — sorting multi/server · filtering · selection · pagination · visibility · pinning · row-detail. **Sin virtualización** |
|
|
|
| Seguimiento | **`Timeline`** (`align="alternate"`, `Marker`, `Connector`) |
|
|
|
| Stock | `Meter` (zonas `below/above/optimum`) + `Badge` |
|
|
|
| Estados | `EmptyState · Result · Callout · Skeleton · Toast · Announce` — **el cuarteto completo, que ningún catálogo del mercado tiene** |
|
|
|
| Envío/peso | `$format.units` (`length · mass · volume` + `convert`) |
|
|
|
| Retail | `Barcode` (EAN-13/UPC-A/ITF-14…) + `QrCode` |
|
|
|
| Búsqueda | `SearchField` (`debounceMs`, `loading`) · `Combobox` · `Command` |
|
|
|
|
|
|
---
|
|
|
|
|
|
## 4. Los 8 huecos de canon (fase C1)
|
|
|
|
|
|
Criterio único: **superficie de contrato** (evento real, máquina, `data-*` que
|
|
|
el CSS selecciona, obligación a11y de widget). Todo lo demás es composición y
|
|
|
va al block. Cada uno entra por la ruta de 9 fases.
|
|
|
|
|
|
| # | Componente | Por qué es canon |
|
|
|
| ---- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
| C1.1 | **`price`** | La ley vive en el tipo. Obligación a11y real: el tachado debe leerse «antes X, ahora Y», no «X Y» |
|
|
|
| C1.2 | **`variant-picker`** | El ítem de mayor valor de la comparativa. **Tres ejes booleanos por opción** (`exists`/`available`/`selected`, nomenclatura de Hydrogen) → eidos pinta las cuatro celdas de la matriz desde CSS sin ramas JS |
|
|
|
| C1.3 | **`quantity-field`** | Especialización fina **componiendo `NumberField`** (precedente sancionado: NumberField dentro de Knob). Aporta mínimo 1, **quitar al bajar de mínimo**, tope = stock, estado en vuelo, nombre accesible por producto |
|
|
|
| C1.4 | **`facets`** | La máquina, no las vistas. Data-driven (precedente: Menubar, NavTree). **Con la live region que Algolia nunca shippeó** — su `stats` renderiza el conteo como texto plano |
|
|
|
| C1.5 | **`lightbox`** | Ya era candidato de canon en F5 con disparador «cuando un block real de media/galería lo pida». Este es el disparador |
|
|
|
| C1.6 | **`address-field`** | Data-driven sobre metadatos públicos de país: conjunto, **orden**, **etiquetas**, regex postal y token `autocomplete` (WCAG 1.3.5). Requiere `$libs/address` |
|
|
|
| C1.7 | **`selection-set`** | Wishlist, comparar y lista de requisición B2B son **el MISMO proveedor**: conjunto sincronizado a URL, con tope, optimista. Construirlo una vez |
|
|
|
| C1.8 | **`embedded-field`** | Envoltorio de iframe de proveedor. **Nunca un input de tarjeta** — el PAN no entra en nuestro DOM. Aporta la resolución de tokens del tema al otro lado del límite vía `eidos.resolveToken()` |
|
|
|
|
|
|
**Enmiendas de canon, no componentes nuevos**: `RatingGroup` (hoy `readonly`
|
|
|
conserva `role="radio"` y cada estrella es parada de tabulación — diez ratings
|
|
|
en un listado son 50 paradas) · `Timeline`/`Stepper` (¿estado `error`? el
|
|
|
seguimiento de un pedido no es camino feliz) · `Card` (elevación + el
|
|
|
invariante del enlace de tarjeta entera) · `Badge` (`tone` que no dependa del
|
|
|
color) · `Table` (virtualización, gap conocido).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 5. Los 26 blocks
|
|
|
|
|
|
**Ala A · descubrimiento (7)** — `commerce-header` · `product-grid` ·
|
|
|
`product-listing`◆ · `category-preview` · `promo-section` · `incentives` ·
|
|
|
`recommendation-slot`.
|
|
|
|
|
|
**Ala B · ficha (6)** — `product-gallery` · `buy-box`◆ · `product-info` ·
|
|
|
`reviews`◆ · `product-qa`◆ · `product-compare`◆.
|
|
|
|
|
|
**Ala C · carrito y pago (4)** — `cart`◆ · `order-summary`◆ · `checkout`◆ ·
|
|
|
`payment-methods`◆.
|
|
|
|
|
|
**Ala D · post-venta (6)** — `order-confirmation` · `order-tracking` ·
|
|
|
`order-history` · `order-detail` · `returns`◆ · `guest-order-lookup`◆.
|
|
|
|
|
|
**Ala E · agéntica (3)** — `cart-review`◆ · `cart-handoff`◆ ·
|
|
|
`purchase-authorization`◆.
|
|
|
|
|
|
◆ = coordina (máquina de estado + palabras). Son **14 de 26**.
|
|
|
|
|
|
**Ala F · B2B: DIFERIDA con disparador** — `quote-request` ·
|
|
|
`requisition-list` · `quick-order-pad` · aprobación de PO · pago a crédito ·
|
|
|
conmutador de cuenta/sede. `selection-set` (C1.7) ya la deja medio construida.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 6. El patrón de coordinación — cópialo literal
|
|
|
|
|
|
`contact` y `newsletter` son los dos ejemplares vivos. La forma exacta:
|
|
|
|
|
|
- **`state.ts`** — unión exhaustiva de estados (cada miembro con su línea de
|
|
|
doc) · interfaz `…StateInput` con campos `readonly` · `resolve…State(input)`
|
|
|
como escalera de guardas **cuyo ORDEN es la prioridad** · `can…(state):
|
|
|
boolean` · **dos `Record<State, …>` exhaustivos**: `…_REASON:
|
|
|
Record<S, string | null>` y `…_ACTION: Record<S, string>`.
|
|
|
Como la clave es el tipo, **añadir un estado es un error de tipos hasta que
|
|
|
escribes su frase y su etiqueta**: un estado que bloquea sin decir por qué no
|
|
|
se puede escribir.
|
|
|
- **`context.ts`** — interfaz con **getters** (para que las lecturas sigan la
|
|
|
fuente reactiva), `reasonId`, `t(ref)`; `Symbol` privado del módulo;
|
|
|
`set…Context` / `get…Context` (el getter devuelve `| undefined` y cada parte
|
|
|
guarda).
|
|
|
- **`…-reason.svelte`** — pinta la frase **y la anuncia** por `uix.announce`
|
|
|
(el segundo servicio que el contrato B sanciona), **sólo al cambiar**, con un
|
|
|
`let announced = ''` que NO es `$state` (es un libro de efectos, no estado
|
|
|
reactivo). `aria-describedby` es mecanismo **aparte y aditivo**: asociación,
|
|
|
no anuncio, y se quieren los dos.
|
|
|
- **`state.test.ts`** — asserts **estructurales**, no caso a caso:
|
|
|
`ALL_STATES.filter(can…)` · «para todo estado bloqueante, `…_REASON` es
|
|
|
truthy» · el regex del idlangref `/^#\?blocks\.<slug>\.[a-z.]+\|.+/`.
|
|
|
- El estado se deriva **UNA vez en la raíz** y las partes lo leen. Ninguna
|
|
|
parte recalcula; ninguna inventa su propio `disabled`.
|
|
|
|
|
|
**Regla de forma del tier — no la re-decidas**: una parte compound se gana
|
|
|
sólo si **se repite** (el app mapea sobre N) o **coordina** (lee el contexto).
|
|
|
Si no hace ninguna de las dos, es un **slot de snippet** en la raíz.
|
|
|
|
|
|
**Las palabras** se registran en `web/routes/blocks/_lib/blocks-langs.ts` bajo
|
|
|
`blocks.{slug}.*` con `es`/`en`; el arnés las inyecta en `langs.schema` desde
|
|
|
`_lib/BootUix.svelte`. Sin registrar, sale el fallback inglés y no se rompe
|
|
|
nada.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 7. Anatomía de fichero
|
|
|
|
|
|
```text
|
|
|
src/uix/blocks/{kebab}/
|
|
|
├── README.md # Function · Composition map · Decisions · Gaps
|
|
|
│ # + el párrafo **Landmark + headings** (B-8)
|
|
|
├── index.ts # export compound + tipos
|
|
|
├── types.ts # props; contenido por snippets
|
|
|
├── {kebab}.svelte # composición: sólo canon, layout por componentes, sin .css
|
|
|
├── {kebab}-{parte}.svelte
|
|
|
└── (si coordina) state.ts · state.test.ts · context.ts
|
|
|
|
|
|
web/routes/blocks/{kebab}/
|
|
|
├── +page.svelte # BlockDemo + controles vivos + pestañas de doc
|
|
|
├── {Name}Site.svelte # el block dentro de una página de contenido REAL
|
|
|
└── preview/
|
|
|
├── +layout@.svelte # `@` resetea el layout; BootUix; lee mode/dir/lang de la URL
|
|
|
└── +page.svelte # sirve {Name}Site desde searchParams
|
|
|
```
|
|
|
|
|
|
Y **flipar `shipped: true`** en `web/routes/blocks/_lib/catalog.ts`, dentro del
|
|
|
grupo «Commerce». El guard parsea ese fichero **por regex**
|
|
|
(`{ slug: '…', … shipped: true }`) y comprueba las **dos direcciones**: un
|
|
|
block sin ficha es invisible para el raíl; un slug publicado sin block es un
|
|
|
enlace muerto.
|
|
|
|
|
|
Los tipos: la raíz extiende `Omit<HTMLAttributes<HTMLElement>, 'children'>`;
|
|
|
**toda otra parte extiende los props del componente de canon que envuelve**,
|
|
|
nunca `HTMLAttributes` (los atributos crudos chocan con el `style`/`class`
|
|
|
refinados del canon). Cuando un slot comparte nombre con un atributo HTML
|
|
|
(`title`, `media`, `width`), se hace `Omit` — «la lección del hero».
|
|
|
|
|
|
---
|
|
|
|
|
|
## 8. Verificación
|
|
|
|
|
|
**Por componente de canon**: `npm run component:audit --only {kebab}` PASS ·
|
|
|
`npm run morfo:check` · `npm run morfo:vocabulary` · `eidos-lint` ·
|
|
|
`npx vitest run src/uix/eidos` · `npm run perm:check` · `npm run rtl:check`.
|
|
|
|
|
|
**Por block**: `npm run blocks:check` verde · `npx vitest run src/uix/blocks` ·
|
|
|
`npm run check` **sin regresión sobre baseline** (medir antes y después: el
|
|
|
baseline se mueve) · `npm run docs:check` · prettier.
|
|
|
|
|
|
**Navegador de verdad, y mirado**: claro y oscuro (`colorScheme: 'dark'`), 375
|
|
|
y 1280, **y RTL**. Sonda de audio + `MutationObserver` de `data-event*` tras la
|
|
|
puerta de hidratación honesta, **con un control en el mismo entorno** — sin
|
|
|
control, una latencia no es un veredicto.
|
|
|
|
|
|
**Acceptance propia de la familia**, además del contrato B:
|
|
|
|
|
|
1. **Cero cadenas horneadas.** La lista de ~20 props traducibles que
|
|
|
`ProductDetail` de BigCommerce Catalyst exige es la checklist: ninguna de
|
|
|
ellas existe aquí.
|
|
|
2. **El cuarteto de estados** en todo block con datos: poblado · cargando ·
|
|
|
vacío · error.
|
|
|
3. **Ningún estado bloqueante mudo** — la propiedad ya está fijada por test en
|
|
|
`contact`/`newsletter`; se hereda.
|
|
|
4. **Tabla de cumplimiento por block**, generada del morfo: qué criterios WCAG
|
|
|
y qué artículos satisface.
|
|
|
5. **Página compuesta de integración** por ala (listado → PDP → carrito →
|
|
|
checkout → confirmación).
|
|
|
|
|
|
---
|
|
|
|
|
|
## 9. Lo que muerde específicamente en commerce
|
|
|
|
|
|
- **RTL es EL eje donde commerce rompe**, y es un foso real: de doce catálogos
|
|
|
estudiados, exactamente uno anuncia RTL y no tiene ecommerce. Duele en el
|
|
|
orden antes/ahora del precio, la colocación del símbolo de divisa, los `−`/`+`
|
|
|
del stepper que **no** deben espejarse, el `scrollLeft` negativo del carrusel
|
|
|
y los chips de filtro.
|
|
|
- **Todo evento con consecuencia monetaria es `commit` con intent real**:
|
|
|
añadir = positivo, quitar = negativo con deshacer, seleccionar agotado =
|
|
|
`signal-threat`. Y el stepper suena por **repetición** (`step` por emisión),
|
|
|
así que la velocidad del gesto ES la velocidad del trinquete.
|
|
|
- **`Form.Submit` estampa su propio `aria-label` genérico**, que gana la
|
|
|
computación del nombre accesible: un botón con palabra de estado DEBE pasar
|
|
|
el suyo explícito o incumple WCAG 2.5.3. Medido en `contact` (A-04).
|
|
|
- **Bajo validación `progressive` se pregunta al ESQUEMA** (`validateSync`),
|
|
|
nunca a `form.isValid` — ahí significa «aún no se ha encontrado nada mal», y
|
|
|
un formulario vacío se declara válido. Y se **deja pasar `invalid`** al
|
|
|
submit, o el camino de error por campo es inalcanzable por construcción.
|
|
|
- **Deuda heredada que commerce va a encontrar otra vez**: las 27 filas todavía
|
|
|
CONFIRMADAS de [`AUDIT-blocks-ledger.md`](./AUDIT-blocks-ledger.md) y los 8
|
|
|
hallazgos de canon congelados (F15–F22 en
|
|
|
[`PLAN-blocks-quality.md`](./PLAN-blocks-quality.md)). Muerden aquí en
|
|
|
concreto: `Card` sin prop de elevación, la ranura `contrast` blanca sobre
|
|
|
todo escalón sólido, y el `aria-label` incondicional del canon.
|
|
|
- **Solape con F3**: `data-table` (F3.3) y `wizard` (F3.8) son parientes de
|
|
|
`order-history` y `checkout`. No bloquea — commerce compone `Table` +
|
|
|
`$libs/datagrid` y `Stepper` directamente, igual que haría F3 — pero cuando
|
|
|
F3 llegue habrá que decidir si `order-history` **es** `data-table`
|
|
|
configurado o su hermano.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 10. Higiene de la comparativa
|
|
|
|
|
|
El dossier de referencia lleva **marcas de verificación** y hay que
|
|
|
respetarlas, por la misma razón que existe el ledger:
|
|
|
|
|
|
- **Verificado**: el inventario de Tailwind Plus Ecommerce (transcrito
|
|
|
categoría a categoría) · la ausencia total de commerce en Untitled UI, en los
|
|
|
headless y en los design systems · el desglose de Storefront UI (26
|
|
|
componentes npm / 24 bloques copy-paste) · la ausencia de blocks de ecommerce
|
|
|
en **todo** el ecosistema Svelte · las obligaciones legales de la UE.
|
|
|
- **NO verificado, y por tanto no citable**: las cifras por categoría de
|
|
|
Flowbite (su web es una SPA que devuelve cuerpo vacío) · todas las
|
|
|
estadísticas de Baymard (corpus de pago) · la penalización de conversión del
|
|
|
checkout en chat · los nombres de campo concretos de los esquemas de AP2.
|
|
|
|
|
|
**Regla**: una cifra sin fuente leída no entra en una tabla comparativa ni
|
|
|
justifica alcance por sí sola. Y **nunca se cita el total auto-declarado de un
|
|
|
catálogo** — se publica la enumeración y el número se deriva de ella. Se
|
|
|
observó dos veces que el total declarado y el enumerado no coinciden, y aplica
|
|
|
también a nuestras propias cifras.
|
|
|
|
|
|
---
|
|
|
|
|
|
## 11. Lo siguiente
|
|
|
|
|
|
**C0**, en este orden:
|
|
|
|
|
|
1. Escribir el dossier `docs/process/RESEARCH-commerce-references.md` con las
|
|
|
7 pistas y las marcas de §10.
|
|
|
2. Escribir el plan de ejecución `docs/process/PLAN-blocks-commerce.md` con la
|
|
|
ficha por ítem (Función · Compone · API · Layout/landmark · v1 · Demo).
|
|
|
3. Añadir el grupo «Commerce» a `web/routes/blocks/_lib/catalog.ts` con los 26
|
|
|
slugs en `shipped: false`.
|
|
|
4. Registrar la iniciativa en `docs/next-features.md` (+ el ala B2B diferida
|
|
|
con su disparador).
|
|
|
|
|
|
Luego **C2** (el art `$commerce`, cuya fase 0 resuelve los dos cabos de §2),
|
|
|
y sólo entonces **C1** — sus tipos los consume todo lo demás.
|