diff --git a/evals/model-apps/genpage/tests/design-fidelity-instructions.test.js b/evals/model-apps/genpage/tests/design-fidelity-instructions.test.js new file mode 100644 index 000000000..ed7a37d85 --- /dev/null +++ b/evals/model-apps/genpage/tests/design-fidelity-instructions.test.js @@ -0,0 +1,49 @@ +'use strict'; + +const { test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); + +const repoRoot = path.resolve(__dirname, '..', '..', '..', '..'); + +function read(relativePath) { + return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8'); +} + +test('shared rules prioritize user-directed visual design over MDA defaults', () => { + const rules = read('plugins/model-apps/references/rules.md'); + + assert.match(rules, /User design direction overrides default MDA styling/); + assert.match(rules, /User-provided screenshot or mockup[\s\S]+Fluent\/MDA defaults only when no direction exists/); + assert.match(rules, /Explicit design values may use CSS[\s\S]+literals or custom properties/); +}); + +test('create planning records a concrete design-fidelity contract', () => { + const planner = read('plugins/model-apps/agents/genpage-planner.md'); + const schema = read('plugins/model-apps/references/plan-schema.md'); + + assert.match(planner, /capture it as a hard requirement/); + assert.match(planner, /Do not silently[\s\S]+fall back to MDA styling/); + assert.match(schema, /Design source:/); + assert.match(schema, /Fidelity notes:/); +}); + +test('single-page and multi-page builders enforce the same design precedence', () => { + const skill = read('plugins/model-apps/skills/genpage/SKILL.md'); + const builder = read('plugins/model-apps/agents/genpage-page-builder.md'); + + assert.match(skill, /Treat `## Design Preferences` as acceptance criteria/); + assert.match(builder, /Treat the plan's Design Preferences as acceptance criteria/); + assert.match(builder, /rather[\s\S]+than normalizing the result to stock Fluent\/MDA/); +}); + +test('edit planning and execution preserve requested visual identity', () => { + const planner = read('plugins/model-apps/agents/genpage-edit-planner.md'); + const editFlow = read('plugins/model-apps/skills/genpage/edit-flow.md'); + + assert.match(planner, /### Design Fidelity/); + assert.match(planner, /Preserve functionality, not obsolete visual defaults/); + assert.match(editFlow, /visual requirements in the approved[\s\S]+override default MDA styling/); + assert.match(editFlow, /do not normalize the[\s\S]+page back to stock MDA/); +}); diff --git a/plugins/model-apps/CHANGELOG.md b/plugins/model-apps/CHANGELOG.md index c32559e3d..e990ed565 100644 --- a/plugins/model-apps/CHANGELOG.md +++ b/plugins/model-apps/CHANGELOG.md @@ -7,6 +7,12 @@ All notable changes to the **model-apps** plugin. Local-dev ergonomics, sample coverage, and an automated eval suite with real and synthetic fixtures. Builds on v2.1; no breaking changes. +### Changed +- `/genpage` now treats user-provided screenshots, website/brand references, and + text styling descriptions as design acceptance criteria across create and edit + flows. Fluent UI remains the accessible component foundation, but no longer + implies resetting explicit visual direction to default model-driven app styling. + ### Added - **Phase 0.5 — local-dev manifest.** Working dirs now get `package.json` and `genpage.d.ts` so `npm install` + editor IntelliSense work after diff --git a/plugins/model-apps/agents/genpage-edit-planner.md b/plugins/model-apps/agents/genpage-edit-planner.md index f8a81124a..53abc441a 100644 --- a/plugins/model-apps/agents/genpage-edit-planner.md +++ b/plugins/model-apps/agents/genpage-edit-planner.md @@ -79,6 +79,8 @@ Read the full source. Identify: - **Data access:** is `dataApi` used? Which entities? Which columns? - **Components in use:** Fluent UI V9 components, any D3.js charts, etc. - **Styling approach:** `makeStyles` + tokens, layout (flex/grid) +- **Visual identity:** palette, typography, density, radii, borders/shadows, imagery, + and whether the current page follows MDA defaults or a distinct design language - **Accessibility:** existing ARIA labels, keyboard handling ### 1d. `RuntimeTypes.ts` (optional) @@ -115,8 +117,16 @@ Ask questions via `AskUserQuestion`, one at a time: > code-only changes. Would you like to continue with code-only edits?" - If code-only: continue. -4. **"Any specific requirements for the changes?"** — styling, accessibility, - behavior, or preservation constraints not yet covered. +4. **"Any specific requirements for the changes?"** — styling or design reference + (screenshot/mockup, website/brand, or text description), accessibility, behavior, + or preservation constraints not yet covered. + - Treat new visual direction as a hard requirement and record concrete layout, + palette, typography, density, shape, borders/shadows, imagery, and interaction + details in Design Notes. + - When the edit is a visual redesign, the new direction overrides the original + page's MDA styling. Preserve functionality, not obsolete visual defaults. + - If a website reference cannot be inspected, ask for a screenshot or concrete + style details rather than falling back to MDA styling. > **Connector data changes** (SharePoint, weather, Office 365, SQL, custom REST): > if the edit adds, replaces, or removes connector-backed data, capture it in the @@ -152,6 +162,14 @@ Enter plan mode (`EnterPlanMode`) with: ### Preservation Constraints - [What must remain unchanged — feature preservation, specific behaviors] +### Design Fidelity +- **Source:** [screenshot/mockup, website/brand reference, text description, + existing page, or "preserve current design"] +- **Must match:** [concrete hierarchy, layout, palette, typography, density, shape, + imagery, and interaction details] +- **Allowed deviations:** [accessibility/responsiveness/host-safety adjustments only, + or "none"] + ### Risks - [Any tension with the original prompt, or any risky aspects — or "None"] ``` @@ -203,8 +221,10 @@ Write `genpage-edit-plan.md` to the working directory root (NOT inside the independently verifiable.> ## Design Notes - + ## Relevant Samples ` is `modalType="modal"` — it draws a `position: fixed` backdrop and traps focus across the whole window, which in the designer blankets the agent panel and locks the user out (they can't even ask the agent to remove it). Default dialogs to `modalType="non-modal"` **and** pass `mountNode`, or use an in-page absolutely-positioned panel. The page root must establish a containing block (`position: relative` + `contain: layout`) so even a fixed-position overlay is clipped to the page. Never size overlays to the viewport. See **Special Patterns > Dialogs and Overlays**. 18. **Never nest a `` inside another ``**: Stacked modal scrims and nested focus traps make dialogs impossible to dismiss reliably. Render sibling dialogs as separate top-level surfaces switched by state, never one `` as a child of another's JSX. 19. **All hooks above every early return — no conditional hook calls**: Detail/record pages crash with **minified React error #310** ("rendered more/fewer hooks than the previous render") on the *first* open of a record, then work on the second click. Cause: a hook — usually a `useMemo` deriving chart points or display rows from loaded data — sits *below* a loading/empty early return (`if (data.loading) return `). On the first render data is still loading, the component early-returns and never reaches that `useMemo` (fewer hooks); when data arrives it renders past the return and calls the extra hook → the hook count differs between renders → #310. The "works the second time" intermittency (the cached render skips the loading branch) is the signature of this bug. **Fix:** place every `useMemo`/`useState`/`useEffect`/`useCallback` **above all early returns**, and make derived memos tolerate not-yet-loaded data (read from an always-initialized value, e.g. `data.rows ?? []`). Early returns are fine — they just must come *after* the last hook call. This is the React rules of hooks: never call a hook below a conditional `return`. +20. **User design direction overrides default MDA styling**: Treat screenshots, + mockups, website/brand references, and explicit text descriptions as requirements, + not suggestions. Match their visual hierarchy, layout, palette, typography, density, + radii, borders, shadows, and imagery as closely as the runtime permits. Fluent UI V9 + remains the component/accessibility foundation; it does not require the page to look + like a stock model-driven app. Do not normalize a requested design into neutral cards, + standard form sections, command bars, default spacing, or the default blue accent. + Accessibility, responsiveness, and host-safety rules remain mandatory. --- @@ -83,9 +94,16 @@ export default GeneratedComponent; ## Layout and Styling ### Design Principles -- Follow Microsoft Fluent Design System principles +- When the user gives no visual direction, follow Microsoft Fluent Design System + principles and the host theme. +- When the user gives visual direction, preserve it. Use Fluent components for + behavior and accessibility, then style their slots with `makeStyles` to achieve the + requested appearance. - Use sentence case for all text -- Use theme tokens (e.g., `tokens.spacingVerticalXL`, `tokens.colorNeutralBackground1`) +- Use theme tokens (e.g., `tokens.spacingVerticalXL`, + `tokens.colorNeutralBackground1`) as defaults. Explicit design values may use CSS + literals or custom properties in `makeStyles`; do not substitute a near-enough token + when that substitution materially changes the requested design. - `makeStyles` for styling; inline styles only for dynamic values - Group content in sections for visual separation @@ -138,12 +156,32 @@ const useStyles = makeStyles({ - Provide back/forward navigation for wizard flows - No React Router or hash/history API routing -### User-Provided Mockups/Screenshots -- When user provides mockups, those take precedence for layout, structure, and visual design -- Follow the provided design closely while adapting to Fluent UI V9 components -- Maintain all technical constraints: accessibility (ARIA, keyboard nav, WCAG AA), responsive design, proper semantic HTML -- If the mockup conflicts with accessibility or responsive design requirements, prioritize accessibility while staying as close to the visual design as possible -- Translate design elements to equivalent Fluent UI components (e.g., custom buttons -> Fluent Button with appropriate styling) +### User-Directed Visual Design + +Use this precedence order: + +1. User-provided screenshot or mockup +2. User-provided website or brand reference +3. Explicit text description of the desired style +4. Existing page style for edits, unless the user asks to replace it +5. Fluent/MDA defaults only when no direction exists + +- Translate the source into concrete implementation decisions: page regions, visual + hierarchy, palette, typography, spacing/density, corner treatment, borders/shadows, + iconography, imagery, and interaction states. +- Follow the design closely while adapting controls to Fluent UI V9. "Use Fluent UI" + means use supported components and accessible behavior; it does **not** mean reset + the visual treatment to default Fluent/MDA styling. +- Do not add generic MDA chrome that is absent from the reference, such as a stock + command bar, neutral section cards, or standard form-style field groups. +- If a website reference cannot be inspected, ask for a screenshot or concrete style + details during planning. Never claim fidelity to a reference that was not available. +- Maintain accessibility (ARIA, keyboard navigation, WCAG AA), responsive behavior, + semantic HTML, and genpage host constraints. If those conflict with the reference, + make the smallest necessary deviation and preserve the rest of the design. +- Translate custom controls to equivalent Fluent components and style their slots + (for example, a branded button becomes a Fluent `Button` with matching colors, + typography, radius, border, and interaction states). --- diff --git a/plugins/model-apps/skills/genpage/SKILL.md b/plugins/model-apps/skills/genpage/SKILL.md index 4390ae83e..35850b364 100644 --- a/plugins/model-apps/skills/genpage/SKILL.md +++ b/plugins/model-apps/skills/genpage/SKILL.md @@ -326,12 +326,17 @@ subagent. Inline the page-builder workflow directly in the orchestrator: `${PLUGIN_ROOT}/references/localization.md` 6. Read `genpage-plan.md` (already in working directory) and `RuntimeTypes.ts` if Data mode is dataverse -7. Write the `.tsx` file to `/.tsx` following all rules -8. After writing, Grep every named import from `@fluentui/react-icons` against +7. Treat `## Design Preferences` as acceptance criteria. User screenshots, mockups, + website/brand references, and explicit text styling override default MDA visuals. + Preserve their concrete hierarchy, layout, palette, typography, density, shape, + imagery, and interaction states; use Fluent components for behavior/accessibility, + not as a reason to reset the design to stock MDA styling. +8. Write the `.tsx` file to `/.tsx` following all rules +9. After writing, Grep every named import from `@fluentui/react-icons` against `${PLUGIN_ROOT}/references/verified-icons.txt` (one Grep per name). Rewrite any unverified names with the closest verified alternative; do not load the full icon list into context -9. Proceed to Phase 6 +10. Proceed to Phase 6 This saves ~5-15s of Task overhead and ~3K tokens that would otherwise be duplicated in a subagent context. diff --git a/plugins/model-apps/skills/genpage/edit-flow.md b/plugins/model-apps/skills/genpage/edit-flow.md index ae7a91c1e..2880c1852 100644 --- a/plugins/model-apps/skills/genpage/edit-flow.md +++ b/plugins/model-apps/skills/genpage/edit-flow.md @@ -136,8 +136,10 @@ preservation constraints. Also read: - `${PLUGIN_ROOT}/references/rules.md` — all code-gen - rules still apply to edits (Fluent UI V9 only, makeStyles with tokens, WCAG AA, - no `100vh`/`100vw`, etc.) + rules still apply to edits (Fluent UI V9 only, `makeStyles`, WCAG AA, + no `100vh`/`100vw`, etc.). User-directed visual requirements in the approved + edit plan override default MDA styling; tokens are defaults, not a reason to + discard an explicit palette, typography, spacing, shape, or layout. - `/RuntimeTypes.ts` — if generated in Edit Phase 3, for verified column names - `//page.tsx` — the current source @@ -151,6 +153,12 @@ RuntimeTypes.ts when the edit touches Dataverse data access. Use ONLY logical names, datasets, table GUIDs, and operations from the seeded connector bindings or approved edit plan when the edit touches connector data access. +For visual edits, implement the plan's Design Fidelity/Design Notes as acceptance +criteria. Preserve the requested hierarchy, layout, palette, typography, density, +radii, borders/shadows, imagery, and interaction states. Use Fluent components for +behavior and accessibility while styling their slots to match; do not normalize the +page back to stock MDA cards, form sections, command bars, spacing, or blue accents. + Do NOT rewrite the entire file. Use the minimum necessary `Edit` operations. ## Edit Phase 6: Deploy Updated Page