siesa-agents 2.1.93 → 2.1.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,616 @@
1
+ ---
2
+ name: sa-screen-layout-refactor
3
+ description: Homologate existing SIESA frontend screens to approved HTML mockups by rebuilding their UI with siesa-ui-kit components — and, when no mockup exists for a screen, do it from a learned design memory built by scanning the mockup corpus. The mockup (or the memory synthesized from the corpus) dictates distribution and element inventory (N buttons, grids, checks, labels); the installed siesa-ui-kit dictates the implementation — kit molecules and compositions of them, almost never hand-rolled HTML. Behavior never changes — no new fields, validations, endpoints or logic. Use this skill whenever the user mentions refactoring or reorganizing a screen's layout, applying an HTML mockup or a `design-artifacts` mockup to an existing page, homologating a screen to the UI kit, "reorganizar pantallas", "aplicar el mockup", "refactor de layout", "refactorizar", "redistribuir la pantalla", refactoring a module "basado en las plantillas" or "con los patrones aprendidos", scanning/updating the design memory ("escanea los prototipos", "actualiza las memorias de diseño"), or wants existing screens rebuilt with siesa-ui-kit components — even if they never use the word "refactor", even without a mockup for that screen, and even when they hand over a whole folder of mockups at once.
4
+ ---
5
+
6
+ # Screen → UI-Kit Homologation (SIESA Frontend)
7
+
8
+ You rebuild the UI of existing screens with siesa-ui-kit components so they
9
+ match an approved mockup. You never change what the screen does.
10
+
11
+ Read the mockup as a **component inventory and a distribution plan** — it tells
12
+ you *what* is on the screen (a grid, five checkbox columns, two buttons, a
13
+ summary bar) and *where* it sits. It does NOT tell you *how* to build it: the
14
+ mockup's own HTML is throwaway Tailwind from a design tool, and copying its
15
+ markup or classes into the app is the failure mode this skill exists to
16
+ prevent. The *how* always comes from siesa-ui-kit:
17
+
18
+ - Every widget the mockup draws is realized with a kit component ("molecule"):
19
+ a checkbox is the kit `Checkbox`, a data grid is the kit `Table`, a tag is
20
+ `Badge`, a menu is `Dropdown`.
21
+ - When no single molecule fits, **compose** molecules: a permission matrix is
22
+ `Table` whose column `render` returns kit `Checkbox`es — not a hand-rolled
23
+ grid of styled `div`s. The kit is rich enough that most screens need zero
24
+ burned widget HTML.
25
+ - Plain HTML + Tailwind is allowed only for **inert structure**: flex/grid
26
+ wrappers, spacing, the page scaffold of UX spec §4.3. Anything a user reads,
27
+ clicks, focuses or toggles belongs to the kit.
28
+ - Existing hand-rolled widgets in the current screen ("HTML quemado") are not
29
+ something to preserve or restyle — they are precisely what this refactor
30
+ replaces with kit molecules, rewiring the existing handlers and state onto
31
+ the kit component's props.
32
+
33
+ The integrity boundary is unchanged and non-negotiable: every field, label,
34
+ validation, hook, query, mutation, handler and type that existed before still
35
+ exists after, with the same name and the same behaviour. Only the rendering
36
+ vocabulary and the distribution change. A homologation that quietly adds a
37
+ field or drops a validation is a feature change in costume, and the diff must
38
+ be defensible line by line against that accusation.
39
+
40
+ ## Sources of truth
41
+
42
+ The paths below are **defaults**, resolved at setup step 0a — an explicit user
43
+ argument or a discovered location overrides them; a path that resolves to
44
+ nothing or to several candidates is asked about, never guessed.
45
+
46
+ | What | Where | Role |
47
+ |---|---|---|
48
+ | Mockup queue | `_bmad-output/design-artifacts/html-and-design/*.html` (one `.html` = one screen) | WHAT is on the screen and WHERE it sits |
49
+ | Design memory | `_bmad-output/design-artifacts/design-memory/` (`manifest.yaml` + `*.md`) | Learned distribution/composition patterns — stands in for WHAT/WHERE **only when no mockup exists**, and only per `references/design-memory.md` |
50
+ | Installed kit exports | `apps/Frontend/node_modules/siesa-ui-kit/dist/index.d.ts` | WHICH components exist — the only authority |
51
+ | Component props | `apps/Frontend/node_modules/siesa-ui-kit/dist/components/<Name>/<Name>.types.d.ts` | The REAL props — never guess a prop name |
52
+ | Storybook | https://siesa-ui-kit.pages.dev | Visual catalog of variants/stories — never proof a component is importable |
53
+ | UX spec | `_bmad-output/planning-artifacts/ux-design-specification.md` | Styles, tokens, page structure, selection priority, language rules — nothing is inferred |
54
+ | Binding style rules | `rules/*.md` in this skill's directory | Complementary rules every generated line must obey (colors as CSS variables, rem not px, no inline styles, …) |
55
+ | Tests | `apps/Frontend/test/unit/<module-slug>/` | The behavior contract (vitest only includes `test/unit/**`, NOT files colocated in `src/`) |
56
+ | Reports | `_bmad-output/screen-layout-refactor/` | Per-screen and final reports |
57
+
58
+ Key definitions you take from the UX spec instead of inferring:
59
+
60
+ - **§2.1 Component Selection Priority** (mandatory order): 1) a siesa-ui-kit
61
+ molecule, 2) a **composition** of kit molecules, 3) **shadcn as the
62
+ fallback** when neither expresses the widget — used directly, flagged in the
63
+ report (`⚠️ shadcn fallback: <widget>`) so the team can later decide whether
64
+ to promote it into the kit. Hand-rolled HTML widgets are never an option at
65
+ any step. A shadcn component obeys the same `rules/` as everything else:
66
+ design-system token classes, rem, no inline styles — restyled to the design
67
+ system, never left on shadcn defaults.
68
+ - **§1 Design System Foundation**: brand palette (primary `#0e79fd`), semantic
69
+ colors, surfaces; neutrals are `slate.*`, never the secondary brand scale.
70
+ - **§4.3 Page Structure**: the standard page scaffold (header with title +
71
+ actions, content in a bordered rounded container).
72
+ - **§7 Language**: all user-visible text in Spanish; never invent copy.
73
+ - **§6 Accessibility**: WCAG 2.1 AA — the homologated screen keeps or improves
74
+ the accessible behavior of what it replaces.
75
+
76
+ Off limits — never edit these:
77
+
78
+ - `apps/Frontend/src/routes/**` (TanStack file routes, thin wrappers over pages)
79
+ - `apps/Frontend/src/app/**`, `providers/**`, `main.tsx`, `spa.tsx` (MFE shell, single-spa, auth)
80
+ - `apps/Frontend/src/modules/*/application|domain|infrastructure/**` (hooks, schemas, services, API)
81
+ - The app shell (sidebar, top nav) drawn inside a mockup — mockups include it
82
+ for context; the screen you refactor starts at the page content.
83
+
84
+ You work inside `presentation/` only. If a homologation seems to require
85
+ touching anything above — say, the mockup shows data the page's hook doesn't
86
+ provide — that is a signal to flag, not to widen the diff.
87
+
88
+ ## Design memory
89
+
90
+ The skill maintains a memory of the design language learned from the mockup
91
+ corpus, so a screen **without** a mockup can still be homologated from
92
+ precedent. Full protocol — directory layout, `manifest.yaml` schema, SHA-256
93
+ sync algorithm, extraction layers, file templates, memory-driven mode — lives
94
+ in `references/design-memory.md` in this skill's directory. **Read it whenever
95
+ memory is built, refreshed, or consumed.** The load-bearing rules, which also
96
+ appear there:
97
+
98
+ - Memory captures what only the corpus teaches: shell anatomy, screen
99
+ archetypes, widget → kit-composition patterns, layout rhythm. It never
100
+ stores hex, px, mockup theme classes, or kit prop signatures — colors and
101
+ measures are governed by the UX spec + `rules/`, and props are always
102
+ re-read from the installed typings.
103
+ - `manifest.yaml` registers every source `.html` with its SHA-256. At setup
104
+ the hashes are re-checked: missing manifest → full build; new/changed
105
+ sources → incremental update of the attributed sections; removed sources →
106
+ flagged, never silently forgotten.
107
+ - Memory is the **most junior** source of truth: an explicit mockup for the
108
+ target screen always outranks it, and it never overrides the UX spec, the
109
+ typings, or the domain.
110
+ - A memory-driven run executes directly — no plan is printed to chat and no
111
+ approval turn is spent. The synthesized plan (pattern ids, homologation
112
+ map, distribution) is embedded in the screen's report file on disk: that is
113
+ the audit trail replacing the mockup link.
114
+
115
+ ## Anti-hallucination protocol
116
+
117
+ This is the discipline that keeps the refactor honest, and it is checked in
118
+ review:
119
+
120
+ 1. A kit component "exists" only if the **installed** `dist/index.d.ts`
121
+ exports it. Storybook routinely runs ahead of the installed package — it
122
+ has shown `Card` and `ButtonGroup` while the installed build exported
123
+ neither. If Storybook has it and the typings don't, this run realizes the
124
+ widget via a kit composition or the shadcn fallback (flagged, with the
125
+ note "or bump siesa-ui-kit and re-run this mockup") — never an import that
126
+ won't compile and never a hand-rolled imitation.
127
+
128
+ ```bash
129
+ grep -oE "^export \{[^}]+\}" apps/Frontend/node_modules/siesa-ui-kit/dist/index.d.ts
130
+ ```
131
+
132
+ 2. Props come only from the component's `.types.d.ts`. Read it before writing
133
+ the first JSX attribute; a prop you "remember" from another design system is
134
+ a compile error at best and a silent no-op at worst.
135
+
136
+ 3. Variants come from Storybook stories (e.g. Table: "Con Bordes", "Filas
137
+ Alternas", "Con Render Personalizado"; Checkbox: sizes, `labelPosition`,
138
+ `description`) — use them to pick the variant that matches the mockup, then
139
+ confirm the enabling props in the typings.
140
+
141
+ 4. Styling comes from the UX spec (§1 tokens, §4.3 scaffold), the binding
142
+ `rules/` files, and what the kit component already renders. The mockup's
143
+ hex values and its private Tailwind theme (`surface-container-low`,
144
+ `on-surface-variant`, …) never enter the codebase — per `style-rules.md`
145
+ they are converted on entry: hex → design-system CSS variable (via its
146
+ Tailwind token class), px → rem (1rem = 16px, `44px → 2.75rem`), inline
147
+ styles → Tailwind classes.
148
+
149
+ ## Gate: explicit target, before anything else
150
+
151
+ The run starts blind and stays blind until the user names the target. The
152
+ skill NEVER infers what to refactor — not from the queue folder's contents,
153
+ not from recently touched files, not from the conversation's vibe. Before any
154
+ setup step executes, the invocation must contain, or the user must answer:
155
+
156
+ 1. **Which module/feature of the front** is being refactored (e.g. "usuarios",
157
+ "conceptos", "roles y permisos"). An explicit "todo el directorio de
158
+ mockups" / "procesa toda la cola" counts as an answer — it is the user
159
+ declaring full scope, which is different from the skill assuming it.
160
+ 2. Optionally, scope modifiers (content area only, a single mockup path, a
161
+ custom memory dir).
162
+
163
+ If the target is missing, ask (AskUserQuestion when available: "¿Qué módulo o
164
+ feature quieres refactorizar?" listing the modules detected under the resolved
165
+ frontend's `src/modules/` and the mockups present in the queue as options)
166
+ and **stop until answered** — no path resolution beyond what the question
167
+ needs, no memory build, no queue listing, no edits. Unattended with no target:
168
+ `❌ BLOCKED: no target — a module/feature name is required to run`.
169
+
170
+ Everything the user declares here defines the run's scope: mockups in the
171
+ queue that fall outside it are reported as skipped (`⏭️ out of scope`), never
172
+ processed "while we're at it".
173
+
174
+ ## Setup, once per run
175
+
176
+ 0a. **Resolve paths — never trust the burned-in defaults blindly.** Resolution
177
+ order for every path in the Sources-of-truth table: 1) an explicit user
178
+ argument, 2) what `design-memory/manifest.yaml` recorded on a previous run
179
+ (`sources_dir`, `memory_dir`, `frontend_dir`), 3) auto-discovery, 4) the
180
+ table's default.
181
+
182
+ **Frontend dir:** by team directive every app lives under `apps/` (backend
183
+ and frontend side by side), so discovery is anchored there and never
184
+ assumes the folder's name. The frontend is **the app that depends on
185
+ siesa-ui-kit** — the folder name (`Frontend`, `web`, `portal`) proves
186
+ nothing, the dependency does:
187
+
188
+ ```bash
189
+ grep -l '"siesa-ui-kit"' apps/*/package.json | xargs -r -n1 dirname
190
+ ```
191
+
192
+ If it resolves but `node_modules/siesa-ui-kit/dist/index.d.ts` is missing
193
+ inside it, the kit isn't installed — tell the user to install before
194
+ continuing (the typings are the component authority; without them nothing
195
+ downstream is trustworthy). **Artifacts:**
196
+
197
+ ```bash
198
+ find . -maxdepth 5 -type d -path "*design-artifacts/html-and-design" -not -path "*/node_modules/*"
199
+ find . -maxdepth 5 -name "ux-design-specification.md" -not -path "*/node_modules/*"
200
+ ```
201
+
202
+ Exactly one hit → use it (and record it in the manifest so the next run
203
+ skips discovery). Zero or multiple hits → interactively, ask the user;
204
+ unattended, `❌ BLOCKED: path resolution — <what> → <candidates found>`.
205
+ Everything downstream (`tsc`, vitest, module mapping, off-limits globs)
206
+ uses the **resolved** frontend dir; the literal `apps/Frontend` in this
207
+ skill's examples is just the reference layout.
208
+ 0. Read every `.md` in this skill's `rules/` directory. Each file there is a
209
+ binding rule set for all code this run generates or modifies — currently
210
+ `style-rules.md` (colors only via design-system CSS variables, all measures
211
+ in rem at 1rem = 16px, everything scales from the root font-size, no inline
212
+ styles, px/hex from specs are converted on entry, never copied). New rule
213
+ files dropped there later bind exactly the same way, without editing this
214
+ skill.
215
+ 0b. **Sync the design memory** (`references/design-memory.md`, "Sync
216
+ algorithm"): hash every `.html` in the mockup dir and compare against
217
+ `design-memory/manifest.yaml`. No manifest → full build of the memory
218
+ files; new/changed/removed sources → incremental update / flag; all hashes
219
+ match → skip. Report one line: `🧠 Memory: current (N sources)` or
220
+ `🧠 Memory: rebuilt/updated (+A new, B changed, C removed)`. If the user
221
+ provided a custom memory path, use it and record it in the manifest.
222
+ 1. List the queue: every `.html` in the resolved mockup dir, sorted by name —
223
+ that is the FIFO processing order — then **filter it to the target declared
224
+ at the gate**: only mockups matching the named module/feature stay in the
225
+ run (full-scope declarations keep everything). Out-of-scope mockups are
226
+ listed as `⏭️ out of scope`. A single mockup passed as an argument is a
227
+ one-item queue, wherever it sits on disk. Arguments may also scope the work
228
+ (e.g. "content area only, skip the app shell") — honor them.
229
+ 2. Confirm the kit typings are readable (`dist/index.d.ts` above). Do not wait
230
+ on Storybook; grep the typings.
231
+ 3. Capture the type-check baseline **before** editing anything and let it
232
+ finish — a killed run undercounts and you will later read your own errors
233
+ as pre-existing:
234
+
235
+ ```bash
236
+ cd apps/Frontend && npx tsc -p tsconfig.json 2>&1 | grep -c "error TS"
237
+ ```
238
+
239
+ Whatever the count is (0 on a green branch, dozens on a stale one), *that*
240
+ is the number Step 5 compares against.
241
+ 4. Branching: the git repo is the **monorepo root** (`apps/Frontend` is not its
242
+ own repo). Never work on `main` or `develop` — from those, create
243
+ `refactor/screen-layout-<slug>` at the moment of the first real edit. If the
244
+ session is already on a feature branch, stay on it and record that in the
245
+ report; yanking a user's in-flight branch around is worse than sharing it.
246
+ 5. Report the queue to the user (screen count and names), then start screen #1.
247
+
248
+ ## Per screen: six steps, in order
249
+
250
+ ### Step 1 — Validate inputs
251
+
252
+ Resolve the mockup to a real screen file. In order:
253
+
254
+ 1. An explicit target comment in the mockup wins:
255
+ `<!-- target: src/modules/concepts/presentation/pages/ConceptsPage.tsx -->`
256
+ 2. Otherwise map by convention: mockup slug → module folder
257
+ `apps/Frontend/src/modules/<module-slug>/presentation/pages/` → the
258
+ `*Page.tsx` in it. Sibling `*.layout.tsx` / `*.fields.tsx` files are part of
259
+ the screen but not the entry point.
260
+ 3. A filename that matches no module is not automatically blocked — read the
261
+ mockup's content: titles and field ids usually name the module outright
262
+ (`roles_view_edit.html` names roles/permissions → the administracion
263
+ permission editor). This inference resolves a **file** inside the scope the
264
+ user already declared at the gate; it never decides *what* gets
265
+ refactored — a content match pointing outside the declared target is
266
+ `⏭️ out of scope`, not a new work item.
267
+
268
+ If the module doesn't exist or the mapping is ambiguous (several `*Page.tsx`
269
+ and no target comment), the screen is `❌ BLOCKED: <screen> — <what is
270
+ missing>`. Log it, move on. Never guess a target; a refactor applied to the
271
+ wrong file is worse than a skipped one.
272
+
273
+ **If the mockup is missing but the target module is clear** (the user asked
274
+ "refactoriza el módulo de usuarios" and no `usuarios*.html` exists), do not
275
+ block automatically — enter **memory-driven mode** per
276
+ `references/design-memory.md`: check memory coverage against the current
277
+ screen's widget census, synthesize the homologation map and distribution from
278
+ the memory patterns (citing pattern ids), record that plan in the screen's
279
+ report, and proceed straight to Step 4 — no approval turn. Only if the memory doesn't exist, or has no precedent for
280
+ the screen's archetype, is the screen `❌ BLOCKED: <screen> — no mockup and no
281
+ memory precedent`. Steps 2–6 then run identically, with the synthesized plan
282
+ standing in for the mockup.
283
+
284
+ ### Step 2 — Build the homologation map
285
+
286
+ Inventory every widget the mockup draws — buttons, checkboxes, data grids,
287
+ tabs, badges, dropdown menus, inputs, labels with descriptions, pagination,
288
+ dividers, avatars — and map **each one** to its kit realization before touching
289
+ code. The map has three possible values per element:
290
+
291
+ 1. **A kit molecule** — the direct case. Common mappings against the currently
292
+ installed kit (re-verify each against `index.d.ts`; the kit grows):
293
+
294
+ | Mockup shows | Kit realization |
295
+ |---|---|
296
+ | Checkbox (with label / description) | `Checkbox` (`label`, `description`, `labelPosition`, `indeterminate`) |
297
+ | Data grid / table of rows | `Table` (`TableColumn.render`, `sortable`, `align`, `width`, pagination props) |
298
+ | Master catalog with CRUD affordances | `MasterCrud` (the mandated orchestrator for master modules, UX spec §2.2) |
299
+ | Button, icon button | `Button` |
300
+ | Tag / status chip | `Badge` |
301
+ | Toggle | `Switch` |
302
+ | Radio group | `Radio` |
303
+ | Text/number/email input | `Input`, `Textarea`, `Quantity` |
304
+ | Dropdown / kebab menu | `Dropdown` (+ `DropdownItemHeading`, `DropdownItemCollapsible`) |
305
+ | Fixed-list select / async master lookup | `Select` / `LookupField` (R-LF-001: backend data is always `lookup`) |
306
+ | Tabs | `Tabs` |
307
+ | Key–value detail block | `DescriptionList` |
308
+ | Inline message / banner | `Alert`, `Info` |
309
+ | Ephemeral feedback | `Toast` |
310
+ | Count badge | `Notification` |
311
+ | Section separator | `Divider` |
312
+ | Pager | `Pagination` |
313
+ | User avatar | `Avatar` |
314
+
315
+ 2. **A composition** — when no single molecule fits, compose them and say so in
316
+ the map. The canonical example: a module × action permission matrix is
317
+ `Table` with one column per action whose `render` returns a `Checkbox`
318
+ wired to the existing toggle callback — header, borders, row hover and
319
+ responsive behavior come free and consistent. Before composing, check
320
+ `design-memory/component-patterns.md` for a learned pattern that already
321
+ names this composition (cite its pattern id in the map), and search the
322
+ repo for a sibling module that already solved it — follow precedent instead
323
+ of inventing a second dialect:
324
+
325
+ ```bash
326
+ grep -rln "<pattern>" apps/Frontend/src/modules/*/presentation apps/Frontend/src/shared
327
+ ```
328
+
329
+ 3. **Shadcn fallback** — neither a molecule nor a reasonable composition of
330
+ kit molecules expresses the widget. Use the shadcn component that does,
331
+ record it in the map as `<widget> → shadcn <Component> (⚠️ fallback)`, and
332
+ carry the flag into the screen report so the team can evaluate promoting it
333
+ into siesa-ui-kit later. The shadcn piece is restyled to the design system
334
+ per `rules/` (token classes, rem, no inline styles) and its props/behavior
335
+ are wired to the screen's existing handlers exactly as a kit molecule would
336
+ be. A screen no longer blocks for a missing kit component; it blocks only
337
+ if not even shadcn covers the widget — then
338
+ `❌ BLOCKED: <screen> — <widget> has no kit or shadcn realization`. What you
339
+ never do is hand-roll the widget out of `div`s — a local reimplementation
340
+ looks fine in the PR and then diverges from the design system forever.
341
+
342
+ Decorative appshell chrome in the mockup (sidebar, top nav, breadcrumbs that
343
+ belong to the shell) is out of scope — do not inventory it.
344
+
345
+ Close the step with the verdict: `✅ HOMOLOGATION MAP READY` (list it) or the
346
+ blocked line.
347
+
348
+ ### Step 3 — Analyze the gap
349
+
350
+ With the map in hand, audit the **current** screen and write down:
351
+
352
+ - **Current implementation census** — for each widget on the screen today: is
353
+ it already a kit molecule, or burned HTML (a styled `div` grid, a native
354
+ `<input type="checkbox">`, a hand-rolled table)? The burned ones are the
355
+ refactor targets; the kit ones may only need re-distribution or variant
356
+ changes.
357
+ - **Target distribution** — where the mockup puts things (columns, order,
358
+ grouping, alignment, which elements sit in the header vs the body).
359
+ - **Changes needed** — element by element: replace X with kit Y, move Z into W.
360
+ - **Stays identical** — every field name, validation, hook call, query,
361
+ mutation, handler, prop and type; every aria-label and accessible behavior.
362
+
363
+ Two asymmetries, both flagged, never silently resolved:
364
+
365
+ - A mockup element with **no counterpart in the current screen** (an extra
366
+ column, a summary bar over data the page doesn't have, a subtitle showing
367
+ data no hook provides) is new functionality, not layout: `⚠️ WARNING` it in
368
+ the report and leave it out.
369
+ - A current element with **no place in the mockup** (a bulk-toggle row, an
370
+ extra action column, an alert region) stays rendered somewhere sensible and
371
+ gets flagged. Deleting functionality to satisfy a drawing is a functional
372
+ change disguised as layout. The mockup is not automatically right — one once
373
+ drew a status switch that would have opened a second, wrong write path.
374
+
375
+ ### Step 4 — Refactor
376
+
377
+ Decide which kind of screen you are holding; the tactic differs:
378
+
379
+ **(a) Hand-written JSX** (pages that compose their own components). Execute the
380
+ homologation map: replace each burned widget with its kit molecule or
381
+ composition, rewiring the **existing** handlers, state, refs and accessible
382
+ names onto the kit component's real props. The page's hooks, services and
383
+ callbacks are untouched — only the rendering layer changes vocabulary. Keep
384
+ whole subtrees where they already use the kit; retyped markup is where dropped
385
+ props and renamed fields come from. Structure the page per UX spec §4.3.
386
+
387
+ **(b) Kit-driven form** — one `<MasterCrud>` plus a declarative `fields[]`
388
+ array. There is no widget HTML to replace: the kit renders the form. Do NOT
389
+ rewrite fields — take over only the layout via `renderForm`:
390
+
391
+ ```tsx
392
+ renderForm={(formProps) => {
393
+ const { renderField } = formProps as RenderContentArgs
394
+ return <MyScreenFormLayout renderField={renderField as RenderField} t={t} />
395
+ }}
396
+ ```
397
+
398
+ The hard-won mechanics, worth understanding rather than copying:
399
+
400
+ - `renderForm` is not a slot for a form: the kit forwards it into its internal
401
+ `MasterCrudForm` as `renderContent`. Return **only the field-area content**;
402
+ the kit keeps its own `<form>`, save ref, header and Cancelar/Guardar footer.
403
+ Mounting another `<MasterCrudForm>` inside is the trap — nested forms, save
404
+ reads one state while fields write another: everything renders, nothing
405
+ saves, and no kit-mocked test notices.
406
+ - `renderField(accessorKey)` with **no second argument** uses the kit's own
407
+ renderer, so every `validate`, `disabled` predicate, lookup config and
408
+ calculated field survives untouched. Your layout module decides only *where*
409
+ each `accessorKey` is painted, and `fields[]` stays complete so submit
410
+ validation keeps iterating every field, visible or not.
411
+ - Two kit-side type frictions, fixed at the boundary with a comment, never by
412
+ loosening your types:
413
+ `type RenderContentArgs = Parameters<NonNullable<MasterCrudFormProps<T>['renderContent']>>[0]`
414
+ (the declared parameter omits `renderField`), and
415
+ `renderField as RenderField` where `RenderField = (accessorKey: string) => ReactNode`
416
+ (`inputRenderer` is typed required though omitting it is what triggers the
417
+ kit renderer).
418
+ - Put the layout in a sibling `<screen>.layout.tsx` that imports no services
419
+ and declares no fields. If that file ever needs a validation or an API call,
420
+ the change stopped being layout — back to Step 3.
421
+
422
+ Whichever kind: keep field `name`s/`accessorKey`s, react-hook-form
423
+ registrations and resolvers, zod schemas, TanStack Query/Router bindings,
424
+ `useEffect` dependencies, event handlers, i18n keys and TypeScript types
425
+ intact. New user-visible strings only where the new structure needs an
426
+ accessible name (a tablist label, a collapse button), in Spanish, per UX spec
427
+ §7 — never invented copy for a mockup's decorative headings.
428
+
429
+ Every line you write obeys the `rules/` files: colors only through
430
+ design-system variables (their Tailwind token classes — `bg-primary`,
431
+ `border-border` — never `bg-[#hex]`), measures in rem via Tailwind's scale
432
+ (arbitrary values in rem when the scale falls short, never `w-[240px]`), no
433
+ `style` attribute (runtime-computed values are the one commented exception),
434
+ and any absolute value a spec or mockup hands you is converted before it
435
+ enters the code. Burned HTML you are homologating loses its inline styles and
436
+ hardcoded values in the same pass — translating them to kit props and Tailwind
437
+ token classes is part of the replacement, not a follow-up.
438
+
439
+ #### Delegating the implementation
440
+
441
+ Steps 1–3 are this skill's job; a large Step 4 does not have to be. When the
442
+ refactor spans several files, hand it to the `sa-dev-story` workflow with a
443
+ brief that cannot drift: the target file, the homologation map, the
444
+ distribution from Step 3, the mechanics above, and the Never list. Delegating
445
+ the typing does not delegate the verdict — you still own Steps 5 and 6. Keep it
446
+ inline when the change is one file and a handful of edits.
447
+
448
+ ### Step 5 — Self-verify
449
+
450
+ ```bash
451
+ cd apps/Frontend && npx tsc -p tsconfig.json 2>&1 | grep "error TS" > "$TEMP/after.txt"
452
+ wc -l < "$TEMP/after.txt" # compare with the setup baseline
453
+ grep -E "<module-slug>|<new files>" "$TEMP/after.txt" # must print nothing
454
+ cd apps/Frontend && npx vitest run --pool=threads test/unit/<module-slug>
455
+ ```
456
+
457
+ The error count is not expected to be zero — it is expected to be **the
458
+ baseline**, with zero hits in files you touched. Tests live under
459
+ `test/unit/<module-slug>/` (the vitest config does not include `src/`);
460
+ `--pool=threads` works around fork-pool spawn timeouts on Windows — that
461
+ failure is environmental, not a red test.
462
+
463
+ Then enforce the `rules/` files mechanically over every file you touched —
464
+ each grep must print nothing (a hit that predates your diff and sits outside
465
+ the lines you changed is reported, not silently fixed):
466
+
467
+ ```bash
468
+ grep -nE "#[0-9a-fA-F]{3,8}\b|rgb\(|hsl\(" <touched files> # R1: no hardcoded colors
469
+ grep -nE "\[[0-9.]+px\]|: ?'?[0-9.]+px" <touched files> # R2: no px in arbitrary values or style objects
470
+ grep -nE "style=\{|style=\"" <touched files> # R4: no inline styles (commented runtime exception aside)
471
+ ```
472
+
473
+ Reading test failures after a homologation:
474
+
475
+ - A **behavioral** assertion gone red — a value that no longer saves, a label
476
+ gone missing, a toggle that stopped toggling, keyboard/focus behavior lost —
477
+ means the refactor dropped something. Fix the refactor, never the assertion.
478
+ - A **structural** assertion pinned to the exact markup you replaced (a
479
+ `data-*` attribute on a hand-rolled grid, a class name, a DOM shape) may
480
+ legitimately need updating *because the markup it pinned no longer exists*.
481
+ Update it to pin the same behavior on the kit-rendered DOM, and list every
482
+ such change in the report — silently weakening a test is how regressions
483
+ ship.
484
+
485
+ **On a kit-driven form the existing unit test cannot verify your work**: those
486
+ screens mock `siesa-ui-kit` wholesale and a mocked kit never invokes
487
+ `renderForm`. Add one RTL test against the **real** kit that: opens the form
488
+ and asserts the new structure; types into fields on two different
489
+ panels/sections, switches between them and asserts values survive; submits and
490
+ asserts the intercepted request body carries values **from both**. That last
491
+ assertion is the only proof the regrouping did not sever a field from form
492
+ state — the first real run of this skill caught exactly that failure. Do not
493
+ report ✅ Done on a kit-driven form without it.
494
+
495
+ Then read your own diff (`git diff -- <files>`):
496
+
497
+ - [ ] Distribution matches the mockup; every widget is a kit molecule or a declared composition
498
+ - [ ] No burned widget HTML remains in the touched area (structure wrappers are fine)
499
+ - [ ] No mockup markup or mockup theme classes copied in
500
+ - [ ] No field added, none removed; no validation added or modified
501
+ - [ ] No new or changed API call; hooks and services untouched
502
+ - [ ] Kit components used with real props (from `.types.d.ts`)
503
+ - [ ] `rules/` compliance: colors only via token classes, measures in rem, no
504
+ inline styles, spec px/hex converted — the three greps above print nothing
505
+ - [ ] Accessible behavior preserved (names, focus, keyboard) — §6
506
+ - [ ] All user-visible text in Spanish — §7
507
+ - [ ] Route wrapper and MFE/single-spa registration untouched
508
+ - [ ] Types at baseline, module tests green (with any structural-assertion updates listed)
509
+
510
+ ### Step 6 — Report
511
+
512
+ Append to `_bmad-output/screen-layout-refactor/<screen>.md` and keep going:
513
+
514
+ ```md
515
+ ## Screen: <name>
516
+ **File:** <path>
517
+ **Mode:** 📐 mockup-driven (<mockup file>) / 🧠 memory-driven (patterns: <ids>)
518
+ **Status:** ✅ Done / ❌ Blocked / ⚠️ Warning
519
+
520
+ ### Homologation map
521
+ - <mockup element> → <kit component / composition>
522
+
523
+ ### Layout changes applied
524
+ - ...
525
+
526
+ ### Preserved unchanged
527
+ - ...
528
+
529
+ ### Test updates (structural only, with reason)
530
+ - ...
531
+
532
+ ### Issues / warnings
533
+ - ...
534
+ ```
535
+
536
+ ## Queue behaviour
537
+
538
+ Process FIFO, write each screen's report before starting the next, and let a
539
+ blocked screen block only itself. A missing kit component no longer blocks —
540
+ it falls back to shadcn with its flag; a screen blocks only for unresolvable
541
+ targets, memory gaps, or widgets not even shadcn covers. Keep going until the
542
+ queue is empty.
543
+
544
+ Run one full build at the end rather than per screen
545
+ (`cd apps/Frontend && npm run build`) — per-screen `tsc` already catches type
546
+ breakage and the Vite build is slow enough that repeating it wastes the run.
547
+
548
+ ## Deliverables when the queue is empty
549
+
550
+ `_bmad-output/screen-layout-refactor/FINAL_REFACTOR_REPORT.md`:
551
+
552
+ ```md
553
+ | Screen | Status | Kit components used | shadcn fallbacks | Blocked reason |
554
+ |--------|--------|---------------------|------------------|----------------|
555
+
556
+ Summary:
557
+ - Total screens processed: X
558
+ - 🧠 Memory: <current / rebuilt> (N sources in manifest) — memory-driven screens: X
559
+ - ✅ Homologated: X
560
+ - ⚠️ shadcn fallbacks used: X — candidates to promote into siesa-ui-kit
561
+ - ❌ Blocked: X — list them
562
+ - ⚠️ Warnings requiring team review: X
563
+ - Final build: pass / fail
564
+ ```
565
+
566
+ `_bmad-output/screen-layout-refactor/INSTRUCTIVE.md` — how another team reruns
567
+ this for their module: preparing a mockup (one `.html` per screen, optional
568
+ `<!-- target: ... -->` comment), dropping mockups into the queue folder,
569
+ invoking the skill, reading the report, what a `⚠️ shadcn fallback` means
570
+ (working screen today; evaluate promoting the component into siesa-ui-kit,
571
+ publish, bump the dependency, optionally re-run only that mockup), and what to
572
+ do with a blocked screen.
573
+
574
+ ## Never
575
+
576
+ - Copy the mockup's HTML, classes or theme tokens into the app — the mockup is
577
+ a drawing, not source code
578
+ - Hand-roll a widget the kit owns, or restyle existing burned HTML instead of
579
+ replacing it with the kit molecule
580
+ - Reach for shadcn while a kit molecule or a composition of kit molecules
581
+ covers the widget — shadcn is strictly the third option
582
+ - Use a shadcn fallback without flagging it in the map and the report, or
583
+ leave it on shadcn default styling instead of the design-system tokens
584
+ - Import a component the **installed** typings don't export, or use a prop not
585
+ in its `.types.d.ts` — Storybook is a catalog, not proof
586
+ - Infer colors, spacing or typography — the UX spec and the kit's own rendering
587
+ decide
588
+ - Hardcode a color (hex/rgb/hsl, including `bg-[#…]`): colors exist only as
589
+ design-system CSS variables consumed through their token classes
590
+ - Write a fixed px measure: rem always (1rem = 16px), Tailwind's scale first,
591
+ arbitrary rem values second
592
+ - Use the `style` attribute: Tailwind classes only, with runtime-computed
593
+ values as the sole commented exception
594
+ - Add a field, input or form element; add or change a validation
595
+ - Add or modify an endpoint, service, schema or backend contract
596
+ - Remove existing functionality to make a mockup fit
597
+ - Touch routes, navigation, MFE shell or auth layers
598
+ - Work directly on `main` or `develop`
599
+ - Restate a field's definition in a layout module: on a kit-driven form,
600
+ hand-writing inputs instead of calling `renderField` is a rewrite in costume
601
+ - Weaken what a test verifies. Updating a structural assertion whose markup you
602
+ replaced is legitimate (and reported); loosening a behavioral assertion to
603
+ get green is not
604
+ - Start a run without an explicit user-declared target (a module/feature name,
605
+ or an explicit full-scope instruction) — inferring what to refactor is
606
+ forbidden; process anything the declared scope doesn't cover
607
+ - Treat the mockup as automatically right — it can contradict the domain, and
608
+ domain wins
609
+ - Store hex, px, mockup theme classes or kit prop signatures in a memory file —
610
+ memories speak design-system vocabulary only, converted on entry
611
+ - Use the memory when an explicit mockup for the target exists — the mockup
612
+ outranks it
613
+ - Hide a memory-driven run's provenance — the synthesized plan, the pattern
614
+ ids used, and any `⚠️ ambiguous` resolution always go in the screen's report
615
+ - Silently drop learned patterns when a source mockup disappears — flag it and
616
+ let a human retire the pattern