From 3303f75916f45cdf1d3aec232d6e439f72fe76fd Mon Sep 17 00:00:00 2001 From: "Joe Mayo (Power Apps)" Date: Tue, 18 Aug 2026 10:23:31 -0700 Subject: [PATCH 1/2] WIP: sync from PA-Client on 8/11 --- .../canvas-apps/agents/canvas-app-planner.md | 8 +- .../agents/canvas-screen-builder.md | 34 +- .../canvas-apps/references/ControlGuide.md | 3 +- .../canvas-apps/references/CreateWorkflow.md | 17 +- .../canvas-apps/references/EditWorkflow.md | 19 +- plugins/canvas-apps/references/LayoutGuide.md | 4 +- .../canvas-apps/references/PlanTemplates.md | 434 +++++++++--------- .../references/ValidationWorkflow.md | 16 +- plugins/canvas-apps/references/YamlSyntax.md | 7 +- .../canvas-apps/skills/canvas-app/SKILL.md | 146 +++--- 10 files changed, 354 insertions(+), 334 deletions(-) diff --git a/plugins/canvas-apps/agents/canvas-app-planner.md b/plugins/canvas-apps/agents/canvas-app-planner.md index 5fe12bcaf..30e06a0e1 100644 --- a/plugins/canvas-apps/agents/canvas-app-planner.md +++ b/plugins/canvas-apps/agents/canvas-app-planner.md @@ -340,11 +340,11 @@ Planning complete. | Action | Screen | Target File | YAML Key | Name Prefix | Screen Brief | |--------|--------|-------------|----------|-------------|--------------| -| [Create / Modify] | [Screen] | [absolute file path] | [key] | [prefix] | [absolute brief path] | +| [Create / Modify] | [Screen] | `[working directory]/[file].pa.yaml` | [key] | [prefix] | `[working directory]/[file-base].screen-plan.md` | -Plan index: [absolute plan index path] -Shared plan: [absolute shared plan path] -App file: [[absolute App.pa.yaml path] for CREATE, "unchanged" for EDIT] +Plan index: `[working directory]/canvas-app-plan.md` +Shared plan: `[working directory]/canvas-app-shared.md` +App file: [`[working directory]/App.pa.yaml` for CREATE, "unchanged" for EDIT] App compile: [Clean / diagnostics remaining, with detail] ``` diff --git a/plugins/canvas-apps/agents/canvas-screen-builder.md b/plugins/canvas-apps/agents/canvas-screen-builder.md index 3923dc01b..da6a2d063 100644 --- a/plugins/canvas-apps/agents/canvas-screen-builder.md +++ b/plugins/canvas-apps/agents/canvas-screen-builder.md @@ -23,11 +23,11 @@ Your invocation includes: - Action: `Create` or `Modify` - Logical screen name -- Absolute target file under the working directory +- Absolute target file under `[working directory]` - YAML screen key - Control name prefix -- Shared plan: an absolute `canvas-app-shared.md` path -- Screen brief: an absolute `*.screen-plan.md` path +- Shared plan: `[working directory]/canvas-app-shared.md` +- Screen brief: an absolute `[working directory]/*.screen-plan.md` path ## 1. Read Only Assigned Context @@ -37,7 +37,7 @@ Read: 2. The assigned screen brief 3. For `Modify`, the exact target `.pa.yaml` -Do not read `canvas-app-plan.md`, other screen briefs, or other screen YAML files. +Do not read `[working directory]/canvas-app-plan.md`, other screen briefs, or other screen YAML files. Do not call discovery tools. The assigned documents contain all required context. Before writing, verify that the screen brief includes definitions for every control type @@ -66,10 +66,10 @@ Screens: Screen1: ``` -`Screen1.pa.yaml` always exists in a new app. When your target file already exists, the -create/write tool fails with `File already exists`. Read the file and replace its contents -with the edit tool instead — the action is still `Create` in the sense that you author the -whole screen. +`[working directory]/Screen1.pa.yaml` always exists in a new app. When your target file already exists, +`create` fails with `File already exists`. Read the file and replace its contents with +`edit` instead — the action is still `Create` in the sense that you author the whole +screen, but the tool call is `edit`. Use meaningful child-control names derived from the logical screen, each carrying your assigned control name prefix after the standard control-type abbreviation. @@ -118,7 +118,7 @@ Do not fix unrelated pre-existing issues. - Quote non-formula strings and YAML-sensitive formula values. - Prefer the simplest correct formula. - Write the file in as few tool calls as possible. Compose the complete screen, then write - it with one `Write` or one whole-file `Edit`. Dozens of incremental edits against a + it with one `create` or one whole-file `edit`. Dozens of incremental edits against a file you keep re-reading is the dominant cost in this workflow and does not improve the result. - Keep the screen proportionate: roughly 40 controls is the practical ceiling for one @@ -134,16 +134,16 @@ Do not fix unrelated pre-existing issues. ## 3. Self-QA -1. Read `${PLUGIN_ROOT}/references/QAChecks.md` **once** and keep it in context. It is a - long document; re-reading it between fixes is the largest avoidable cost in this role. +1. Read `${PLUGIN_ROOT}/references/QAChecks.md` **once** and keep it in context. It is a long document; + re-reading it between fixes is the largest avoidable cost in this role. 2. Re-read the target file. 3. Apply **every** check in order and fix issues inline. Checks are not optional and not sampled: a check you skipped is a defect you shipped, and most of them have no compile diagnostic behind them, so nothing downstream will catch it. 4. For Modify, scope checks to changed or added content. -5. Record an outcome for every check by number — `PASS`, `FIXED(n)` or `N/A` — as the - "Reporting" section in `${PLUGIN_ROOT}/references/QAChecks.md` describes. Report the - line; do not summarise it as a total. +5. Record an outcome for every check by number — `PASS`, `FIXED(n)` or `N/A` — as + `${PLUGIN_ROOT}/references/QAChecks.md` § "Reporting" describes. You report the line; do not + summarize it as a total. Do not call `compile_canvas`; the orchestrator owns compilation. It compiles as soon as the first builder returns, so return promptly rather than polishing indefinitely. @@ -159,13 +159,13 @@ QA: 1 [outcome] · 2 [outcome] · … Status: Done ``` -The `QA:` line must list every check in `${PLUGIN_ROOT}/references/QAChecks.md`. A return -without it is incomplete, and the orchestrator will send the screen back. +The `QA:` line must list every check in `${PLUGIN_ROOT}/references/QAChecks.md`. A return without it is +incomplete, and the orchestrator will send the screen back. ## Constraints - Modify exactly one screen file. -- Never edit `App.pa.yaml` or `_EditorState.pa.yaml`. +- Never edit `[working directory]/App.pa.yaml` or `[working directory]/_EditorState.pa.yaml`. - Never substitute a filename, YAML key, or control name prefix. - Never use a property absent from that control's definition. - Never write a version suffix on a `Control:` value. diff --git a/plugins/canvas-apps/references/ControlGuide.md b/plugins/canvas-apps/references/ControlGuide.md index 51ae8b9ff..fe2b02925 100644 --- a/plugins/canvas-apps/references/ControlGuide.md +++ b/plugins/canvas-apps/references/ControlGuide.md @@ -39,8 +39,7 @@ to reinvent with primitives. Then run `describe_control` on every type you plan Default to AutoLayout. Use ManualLayout only when the user explicitly requests pixel-perfect positioning or the app is a fixed-size desktop dashboard. Mobile and -cross-device apps MUST use AutoLayout. See `${PLUGIN_ROOT}/references/LayoutGuide.md` for -the patterns. +cross-device apps MUST use AutoLayout. See `${PLUGIN_ROOT}/references/LayoutGuide.md` for the patterns. ⚠️ **`GroupContainer` has no `OnSelect` — it cannot be clicked.** This is a common dead end when building card UI: the container lays out perfectly but tapping it does nothing. diff --git a/plugins/canvas-apps/references/CreateWorkflow.md b/plugins/canvas-apps/references/CreateWorkflow.md index 6f7b596c9..0b23aea96 100644 --- a/plugins/canvas-apps/references/CreateWorkflow.md +++ b/plugins/canvas-apps/references/CreateWorkflow.md @@ -1,6 +1,6 @@ # Create Workflow -Use this workflow only when the working directory has no meaningful screen content. +Use this workflow only when `[working directory]` has no meaningful screen content. ## 1. Read Guidance @@ -25,8 +25,8 @@ Determine: Use AutoLayout for phone, tablet, multi-device, or unknown targets. ManualLayout is acceptable for desktop-only, fixed dashboards. -The landing screen must reuse `[working directory]/Screen1.pa.yaml`; every additional -screen gets a new file. +The landing screen must reuse `[working directory]/Screen1.pa.yaml`; every additional screen gets a new +file. ## 3. Present the Plan @@ -56,17 +56,16 @@ Invoke the `canvas-app-planner` agent with `Task` and: ```text Mode: CREATE -Working directory: [absolute working directory] -Plan index: [working directory]/canvas-app-plan.md -Shared plan: [working directory]/canvas-app-shared.md +Working directory: `[working directory]` +Plan index: `[working directory]/canvas-app-plan.md` +Shared plan: `[working directory]/canvas-app-shared.md` Requirements: [user requirements] Approved plan: [full approved plan] Target users and device: [stated or inferred] ``` -The planner discovers resources, writes `[working directory]/App.pa.yaml`, the plan index, -shared plan, and one screen brief per dispatch row. It does not redesign the approved -plan. +The planner discovers resources, writes `[working directory]/App.pa.yaml`, the plan index, shared plan, +and one screen brief per dispatch row. It does not redesign the approved plan. Wait for the planner to finish, then return to **Planned Build Handoff** in the `canvas-app` skill. diff --git a/plugins/canvas-apps/references/EditWorkflow.md b/plugins/canvas-apps/references/EditWorkflow.md index 51e2db65e..d89549ead 100644 --- a/plugins/canvas-apps/references/EditWorkflow.md +++ b/plugins/canvas-apps/references/EditWorkflow.md @@ -1,10 +1,10 @@ # Edit Workflow -Use this workflow only when the working directory already has meaningful content. +Use this workflow only when `[working directory]` already has meaningful content. ## 1. Assess Complexity -Read all `.pa.yaml` files in the working directory. +Read all `[working directory]/*.pa.yaml` files. Treat the edit as **simple** only when all are true: @@ -17,12 +17,11 @@ Anything else is **complex**. ## 2. Simple Edit -1. Read `${PLUGIN_ROOT}/references/YamlSyntax.md`. Also read - `${PLUGIN_ROOT}/references/ControlGuide.md` when the edit touches control properties or - enums, and `${PLUGIN_ROOT}/references/LayoutGuide.md` when it touches sizing, scrolling, - or colour. +1. Read `${PLUGIN_ROOT}/references/YamlSyntax.md`. Also read `${PLUGIN_ROOT}/references/ControlGuide.md` when the edit + touches control properties or enums, and `${PLUGIN_ROOT}/references/LayoutGuide.md` when it touches + sizing, scrolling, or colour. 2. Use `describe_control` before adding a property not already present on that control. -3. Apply targeted edits directly to the absolute working-directory path. +3. Apply targeted edits directly to the `[working directory]` folder. 4. Read `${PLUGIN_ROOT}/references/ValidationWorkflow.md` and follow it. 5. Stop after the final summary; do not invoke planner or builder agents. @@ -74,9 +73,9 @@ Invoke the `canvas-app-planner` agent with `Task` and: ```text Mode: EDIT -Working directory: [absolute working directory] -Plan index: [working directory]/canvas-app-plan.md -Shared plan: [working directory]/canvas-app-shared.md +Working directory: `[working directory]` +Plan index: `[working directory]/canvas-app-plan.md` +Shared plan: `[working directory]/canvas-app-shared.md` Edit requirements: [user requirements] Approved plan: [full approved plan] Current app state: [palette, variables, layout, screens, controls] diff --git a/plugins/canvas-apps/references/LayoutGuide.md b/plugins/canvas-apps/references/LayoutGuide.md index 2ca47df13..075177a9e 100644 --- a/plugins/canvas-apps/references/LayoutGuide.md +++ b/plugins/canvas-apps/references/LayoutGuide.md @@ -102,8 +102,8 @@ layout scopes. GridLayout needs coordinated column, row and height math; a stale row count can produce a valid but visibly wrong screen. When planning a `GroupContainer` with -`Variant: GridLayout`, use `${PLUGIN_ROOT}/references/GridLayoutGuide.md` and put its exact -formulas in the screen brief. Builders do not read that conditional reference. +`Variant: GridLayout`, use `${PLUGIN_ROOT}/references/GridLayoutGuide.md` and put its exact formulas in +the screen brief. Builders do not read that conditional reference. ## Galleries are Classic — their rows do not reflow diff --git a/plugins/canvas-apps/references/PlanTemplates.md b/plugins/canvas-apps/references/PlanTemplates.md index 2ad38f9ea..a0856dc03 100644 --- a/plugins/canvas-apps/references/PlanTemplates.md +++ b/plugins/canvas-apps/references/PlanTemplates.md @@ -1,217 +1,217 @@ -# Canvas App Plan Templates - -The planner writes three artifact types: - -1. `[working directory]/canvas-app-plan.md` — compact orchestration index -2. `[working directory]/canvas-app-shared.md` — cross-screen conventions -3. `[working directory]/[target-base].screen-plan.md` — one implementation brief per screen - -## Contents - -- Plan Index — CREATE -- Plan Index — EDIT -- Shared Plan -- Screen Brief — CREATE -- Screen Brief — MODIFY - -## Plan Index — CREATE - -```markdown -# Canvas App Plan - -## Mode -CREATE - -## Requirements -[Original requirements] - -## Requirement Coverage -| Requirement | Planned affordance | Fidelity | -|-------------|--------------------|----------| -| [Concrete noun or interaction from the request] | [Visible control and exact behavior] | Exact / Approximation: [reason] | - -## Working Directory -[absolute working directory] - -## Discovery Summary -- Controls: [relevant controls] -- Data sources: [used sources or none] -- Connectors: [used connectors or none] - -## Dispatch -| Action | Screen | Target File | YAML Key | Name Prefix | Screen Brief | -|--------|--------|-------------|----------|-------------|--------------| -| Create | [Landing] | [working directory]/Screen1.pa.yaml | Screen1 | [Prefix] | [working directory]/Screen1.screen-plan.md | -| Create | [Additional] | [working directory]/[Name].pa.yaml | [Name] | [Prefix] | [working directory]/[Name].screen-plan.md | -``` - -## Plan Index — EDIT - -```markdown -# Canvas App Plan - -## Mode -EDIT - -## Requirements -[Original edit requirements] - -## Requirement Coverage -| Requirement | Planned affordance | Fidelity | -|-------------|--------------------|----------| -| [Concrete noun or interaction from the request] | [Visible control and exact behavior] | Exact / Approximation: [reason] | - -## Working Directory -[absolute working directory] - -## Discovery Summary -- Existing screens: [names] -- Layout: [ManualLayout / AutoLayout / mixed] -- Data sources: [used sources or none] - -## Dispatch -| Action | Screen | Target File | YAML Key | Name Prefix | Screen Brief | -|--------|--------|-------------|----------|-------------|--------------| -| Modify | [Existing] | [working directory]/[File].pa.yaml | [existing key] | [Prefix] | [working directory]/[File].screen-plan.md | -| Create | [New] | [working directory]/[File].pa.yaml | [new key] | [Prefix] | [working directory]/[File].screen-plan.md | - -## App Changes -### Before builders -[Shared definitions screens bind to — collections, named formulas, app variables, OnStart -seed data — or "None"] -### After builders -[Changes referencing screens that do not exist yet, such as StartScreen — or "None"] -``` - -## Shared Plan - -```markdown -# Canvas App Shared Plan - -## Aesthetic Direction -- Palette: [description] -- Primary background: RGBA([...]) -- Accent: RGBA([...]) -- Text primary: RGBA([...]) -- Text secondary: RGBA([...]) -- Typography: [scale and weights] - -## Layout Strategy -[Shared layout rules and target-device rationale. Record the breakpoint formulas and the -rule that responsive properties derive from current width rather than `OnVisible` -variables.] - -## Named State -[Variables, named formulas, collections, and ownership] - -## Control Naming -[Standard control-type abbreviations followed by the per-screen namespace, such as -`conDiscNavBar` and `btnDetailBack`, plus the rule that repeated UI blocks are -instantiated under each screen's own namespace] - -## Cross-Screen Contracts -[Navigation targets and shared state expectations. For repeated navigation blocks, list -the exact items in order and prohibit extra screen-specific children. Use ModernButtons -for cross-screen navigation; reserve ModernTabList for panels within one screen.] - -## YAML Conventions -- Formula prefix -- Multi-line formula syntax -- String and record-literal quoting -- Enum escaping -- App-specific conventions -``` - -## Screen Brief — CREATE - -```markdown -# Screen Plan: [Logical Screen] - -## Assignment -- Action: Create -- Target file: [working directory]/[File].pa.yaml -- YAML key: [key] -- Control name prefix: [Prefix] - -## Specification -- Purpose: [description] -- Layout: [root and child structure. For each fixed-height section and horizontal row - with four or more substantive children, include a desktop/narrow/phone budget with - child grouping, minimum widths/heights, gaps, padding and resulting section size.] -- Grid contract: [for each GridLayout, exact columns, rows, column minimum, row minimum, - height and child-position formulas; omit when there is no GridLayout] -- Controls: [prefixed control names and purpose] -- Column headers: [for any grid or repeated row of inputs, the exact visible header - strings — "Mon", "Tue", … . A row of identical unlabelled inputs is unusable, and - `AccessibleLabel` is not a substitute for a visible header. Omit if the screen has no - repeated input row.] -- Data binding: [sources, fields and variables; identify small screen-local read-only - tables that stay inline in `Items`, versus shared or mutable collections owned by App. - For entities with multiple date/status fields, define which field drives each visible - view and ensure displayed labels, seed data and filters use that same meaning.] -- Navigation: [targets and triggers] -- State: [OnVisible initialization] - -## Relevant Data Source Schemas -[Only the fields this screen reads or writes; omit if none] - -## Relevant API Details -[Only the operations and parameters this screen calls; omit if none] - -## Required Variants -[Control type -> exact variant to use, for every control type whose definition includes a -Variants section; omit if none] - -## Control Definitions -[For each control type used on this screen: the complete list of valid input property -names, plus the full enum name for each enum property this screen sets. Not the whole -describe_control response. - -Give each enum property the **compile-ready literal**, not a list of members. Write -`Precision: =DecimalPrecision.'1'`, never `Enum name: DecimalPrecision; values: 0, 1, 2`. -A member list is transcribed literally by the builder and a member starting with a digit -then fails to compile.] -``` - -## Screen Brief — MODIFY - -```markdown -# Screen Plan: [Logical Screen] - -## Assignment -- Action: Modify -- Target file: [working directory]/[File].pa.yaml -- YAML key: [existing key] -- Control name prefix: [Prefix] - -## Current State -[Concise summary of relevant existing controls and layout] - -## Changes -1. [Exact required change] - -## Controls to Add -[Name, type, placement, properties; or "None"] - -## Controls to Remove -[Names; or "None"] - -## Properties to Update -[Control -> property -> exact value; or "None"] - -## Relevant Data Source Schemas -[Only the fields this edit reads or writes; omit if none] - -## Relevant API Details -[Only the operations this edit calls; omit if none] - -## Required Variants -[Control type -> exact variant, for any control this edit adds whose definition includes a -Variants section; omit if none] - -## Changed or Added Control Definitions -[For each control type receiving a new property, enum, or variant — including types -already present in the app: valid input property names, plus the full enum name and -compile-ready literal for each enum property this edit sets. Write -`Precision: =DecimalPrecision.'1'`, not a bare member list; omit if none] -``` +# Canvas App Plan Templates + +The planner writes three artifact types: + +1. `[working directory]/canvas-app-plan.md` — compact orchestration index +2. `[working directory]/canvas-app-shared.md` — cross-screen conventions +3. `[working directory]/[target-base].screen-plan.md` — one implementation brief per screen + +## Contents + +- Plan Index — CREATE +- Plan Index — EDIT +- Shared Plan +- Screen Brief — CREATE +- Screen Brief — MODIFY + +## Plan Index — CREATE + +```markdown +# Canvas App Plan + +## Mode +CREATE + +## Requirements +[Original requirements] + +## Requirement Coverage +| Requirement | Planned affordance | Fidelity | +|-------------|--------------------|----------| +| [Concrete noun or interaction from the request] | [Visible control and exact behavior] | Exact / Approximation: [reason] | + +## Working Directory +[absolute working directory] + +## Discovery Summary +- Controls: [relevant controls] +- Data sources: [used sources or none] +- Connectors: [used connectors or none] + +## Dispatch +| Action | Screen | Target File | YAML Key | Name Prefix | Screen Brief | +|--------|--------|-------------|----------|-------------|--------------| +| Create | [Landing] | `[working directory]/Screen1.pa.yaml` | Screen1 | [Prefix] | `[working directory]/Screen1.screen-plan.md` | +| Create | [Additional] | `[working directory]/[Name].pa.yaml` | [Name] | [Prefix] | `[working directory]/[Name].screen-plan.md` | +``` + +## Plan Index — EDIT + +```markdown +# Canvas App Plan + +## Mode +EDIT + +## Requirements +[Original edit requirements] + +## Requirement Coverage +| Requirement | Planned affordance | Fidelity | +|-------------|--------------------|----------| +| [Concrete noun or interaction from the request] | [Visible control and exact behavior] | Exact / Approximation: [reason] | + +## Working Directory +[absolute working directory] + +## Discovery Summary +- Existing screens: [names] +- Layout: [ManualLayout / AutoLayout / mixed] +- Data sources: [used sources or none] + +## Dispatch +| Action | Screen | Target File | YAML Key | Name Prefix | Screen Brief | +|--------|--------|-------------|----------|-------------|--------------| +| Modify | [Existing] | `[working directory]/[File].pa.yaml` | [existing key] | [Prefix] | `[working directory]/[File].screen-plan.md` | +| Create | [New] | `[working directory]/[File].pa.yaml` | [new key] | [Prefix] | `[working directory]/[File].screen-plan.md` | + +## App Changes +### Before builders +[Shared definitions screens bind to — collections, named formulas, app variables, OnStart +seed data — or "None"] +### After builders +[Changes referencing screens that do not exist yet, such as StartScreen — or "None"] +``` + +## Shared Plan + +```markdown +# Canvas App Shared Plan + +## Aesthetic Direction +- Palette: [description] +- Primary background: RGBA([...]) +- Accent: RGBA([...]) +- Text primary: RGBA([...]) +- Text secondary: RGBA([...]) +- Typography: [scale and weights] + +## Layout Strategy +[Shared layout rules and target-device rationale. Record the breakpoint formulas and the +rule that responsive properties derive from current width rather than `OnVisible` +variables.] + +## Named State +[Variables, named formulas, collections, and ownership] + +## Control Naming +[Standard control-type abbreviations followed by the per-screen namespace, such as +`conDiscNavBar` and `btnDetailBack`, plus the rule that repeated UI blocks are +instantiated under each screen's own namespace] + +## Cross-Screen Contracts +[Navigation targets and shared state expectations. For repeated navigation blocks, list +the exact items in order and prohibit extra screen-specific children. Use ModernButtons +for cross-screen navigation; reserve ModernTabList for panels within one screen.] + +## YAML Conventions +- Formula prefix +- Multi-line formula syntax +- String and record-literal quoting +- Enum escaping +- App-specific conventions +``` + +## Screen Brief — CREATE + +```markdown +# Screen Plan: [Logical Screen] + +## Assignment +- Action: Create +- Target file: `[working directory]/[File].pa.yaml` +- YAML key: [key] +- Control name prefix: [Prefix] + +## Specification +- Purpose: [description] +- Layout: [root and child structure. For each fixed-height section and horizontal row + with four or more substantive children, include a desktop/narrow/phone budget with + child grouping, minimum widths/heights, gaps, padding and resulting section size.] +- Grid contract: [for each GridLayout, exact columns, rows, column minimum, row minimum, + height and child-position formulas; omit when there is no GridLayout] +- Controls: [prefixed control names and purpose] +- Column headers: [for any grid or repeated row of inputs, the exact visible header + strings — "Mon", "Tue", … . A row of identical unlabelled inputs is unusable, and + `AccessibleLabel` is not a substitute for a visible header. Omit if the screen has no + repeated input row.] +- Data binding: [sources, fields and variables; identify small screen-local read-only + tables that stay inline in `Items`, versus shared or mutable collections owned by App. + For entities with multiple date/status fields, define which field drives each visible + view and ensure displayed labels, seed data and filters use that same meaning.] +- Navigation: [targets and triggers] +- State: [OnVisible initialization] + +## Relevant Data Source Schemas +[Only the fields this screen reads or writes; omit if none] + +## Relevant API Details +[Only the operations and parameters this screen calls; omit if none] + +## Required Variants +[Control type -> exact variant to use, for every control type whose definition includes a +Variants section; omit if none] + +## Control Definitions +[For each control type used on this screen: the complete list of valid input property +names, plus the full enum name for each enum property this screen sets. Not the whole +describe_control response. + +Give each enum property the **compile-ready literal**, not a list of members. Write +`Precision: =DecimalPrecision.'1'`, never `Enum name: DecimalPrecision; values: 0, 1, 2`. +A member list is transcribed literally by the builder and a member starting with a digit +then fails to compile.] +``` + +## Screen Brief — MODIFY + +```markdown +# Screen Plan: [Logical Screen] + +## Assignment +- Action: Modify +- Target file: `[working directory]/[File].pa.yaml` +- YAML key: [existing key] +- Control name prefix: [Prefix] + +## Current State +[Concise summary of relevant existing controls and layout] + +## Changes +1. [Exact required change] + +## Controls to Add +[Name, type, placement, properties; or "None"] + +## Controls to Remove +[Names; or "None"] + +## Properties to Update +[Control -> property -> exact value; or "None"] + +## Relevant Data Source Schemas +[Only the fields this edit reads or writes; omit if none] + +## Relevant API Details +[Only the operations this edit calls; omit if none] + +## Required Variants +[Control type -> exact variant, for any control this edit adds whose definition includes a +Variants section; omit if none] + +## Changed or Added Control Definitions +[For each control type receiving a new property, enum, or variant — including types +already present in the app: valid input property names, plus the full enum name and +compile-ready literal for each enum property this edit sets. Write +`Precision: =DecimalPrecision.'1'`, not a bare member list; omit if none] +``` diff --git a/plugins/canvas-apps/references/ValidationWorkflow.md b/plugins/canvas-apps/references/ValidationWorkflow.md index 08baad8e4..c871d021a 100644 --- a/plugins/canvas-apps/references/ValidationWorkflow.md +++ b/plugins/canvas-apps/references/ValidationWorkflow.md @@ -25,7 +25,7 @@ repairing it across six finished files is not. When gate 3 reveals a systemic defect: -- Repair the files that already exist in place, with targeted `Edit` calls. +- Repair the files that already exist in place, with targeted `edit` calls. - Correct the shared plan and the briefs for rows **not yet dispatched**, so the next wave does not repeat the defect. - Never re-dispatch a builder whose file already exists. A regenerated screen discards the @@ -53,7 +53,7 @@ If compilation fails, fix diagnostics in this order: For each tier: -1. Read every referenced absolute path in the working directory. +1. Read every referenced file under `[working directory]`. 2. Fix all diagnostics in the tier. 3. Re-run `compile_canvas` before moving to the next tier. @@ -114,7 +114,7 @@ lines. Reading all of them wastes the context you need to fix them. ### Liveness -Every turn in the repair phase must end in an `Edit` or a `compile_canvas`. Those are the +Every turn in the repair phase must end in an `edit` or a `compile_canvas`. Those are the only two actions that change the outcome. After **two consecutive turns** containing neither, stop and emit the unresolved-diagnostics @@ -123,7 +123,7 @@ stopped compiling is not thinking — it is searching for a capability that does and it will not recover on its own. Reading a file, planning an approach, or delegating is not progress on its own. If you find -yourself unable to express a fix with `Edit`, return to the named file and diagnostic +yourself unable to express a fix with `edit`, return to the named file and diagnostic location. Repeated identical lines need separate targeted edits with enough surrounding context to make each match unique. @@ -150,7 +150,7 @@ Track the count of **distinct** diagnostics after every compile. You repair the app yourself. You already hold the plan, the dispatch table, and the diagnostic history, and a fresh agent would have to rediscover all of it. -- Fix compile diagnostics with targeted `Edit` calls against the named file. This is +- Fix compile diagnostics with targeted `edit` calls against the named file. This is always the correct response to a diagnostic. - Do not spawn a general-purpose agent to "fix compilation." That restarts discovery from zero and has no shared budget with you. @@ -171,9 +171,9 @@ The summary must describe a compile you actually observed. Before writing it, co has, compile again — a clean result from before your last edit says nothing about what you shipped. -Edits to non-compiled artifacts do not invalidate the result: `canvas-app-plan.md`, -`canvas-app-shared.md` and `*.screen-plan.md` are planning documents, and updating one -after the final compile is fine. +Edits to non-compiled artifacts do not invalidate the result: `[working directory]/canvas-app-plan.md`, +`[working directory]/canvas-app-shared.md` and `[working directory]/*.screen-plan.md` are planning documents, and +updating one after the final compile is fine. ## 2. Summary diff --git a/plugins/canvas-apps/references/YamlSyntax.md b/plugins/canvas-apps/references/YamlSyntax.md index 5138f692e..357451e31 100644 --- a/plugins/canvas-apps/references/YamlSyntax.md +++ b/plugins/canvas-apps/references/YamlSyntax.md @@ -5,8 +5,8 @@ starting workspace every new app arrives with. **Who does what.** Discovery and compilation belong to the orchestrator and the `canvas-app-planner`: they run `list_controls`, `describe_control`, the data and API -tools, and `compile_canvas`. A `canvas-screen-builder` has only `Read`, `Write` and -`Edit` — it never discovers and never compiles, and relies entirely on the property names, +tools, and `compile_canvas`. A `canvas-screen-builder` has only `view`, `create` and +`edit` — it never discovers and never compiles, and relies entirely on the property names, enum names and variants recorded in its screen brief. Where these guides say "run `list_controls`" or "compile early", that instruction is addressed to the orchestrator and planner. @@ -31,8 +31,7 @@ planner. expensive to reinvent from primitives. 2. Run `describe_control` for every control type you intend to use, and record the exact property names, `Enum name:` lines and variants. -3. Review this guide, `${PLUGIN_ROOT}/references/ControlGuide.md`, - `${PLUGIN_ROOT}/references/LayoutGuide.md` and +3. Review this guide, `${PLUGIN_ROOT}/references/ControlGuide.md`, `${PLUGIN_ROOT}/references/LayoutGuide.md` and `${PLUGIN_ROOT}/references/DesignGuide.md` before designing a screen. 4. Plan state: the variables each screen sets, and where they are initialized. 5. Choose a layout strategy: AutoLayout for responsive, ManualLayout only for fixed diff --git a/plugins/canvas-apps/skills/canvas-app/SKILL.md b/plugins/canvas-apps/skills/canvas-app/SKILL.md index 3f38c7936..30fc32caf 100644 --- a/plugins/canvas-apps/skills/canvas-app/SKILL.md +++ b/plugins/canvas-apps/skills/canvas-app/SKILL.md @@ -29,8 +29,8 @@ Always use absolute paths for app files. Never edit `_EditorState.pa.yaml`; Stud ## Route the Request -Inspect the synced `.pa.yaml` files before choosing a workflow. A blank app normally -contains `App.pa.yaml`, `Screen1.pa.yaml`, and `_EditorState.pa.yaml`. +Inspect the synced `.pa.yaml` files before choosing a workflow. A blank app normally contains +`App.pa.yaml`, `Screen1.pa.yaml`, and `_EditorState.pa.yaml`. Treat the app as empty when it has no screens with meaningful leaf controls. Containers without leaf controls do not make the app non-empty. @@ -44,7 +44,7 @@ Do not load both workflow documents. CREATE and complex EDIT workflows return here after the planner finishes. -1. Read the absolute `canvas-app-plan.md` path returned by the planner. +1. Read `[working directory]/canvas-app-plan.md` returned by the planner. 2. Verify its `## Requirement Coverage` table maps every concrete requested noun and interaction to a visible affordance. Any approximation must be explicit and must not use UI copy that claims the unavailable interaction is exact. @@ -52,38 +52,40 @@ CREATE and complex EDIT workflows return here after the planner finishes. - Every row has `Action`, `Screen`, `Target File`, `YAML Key`, `Name Prefix`, and `Screen Brief`. - CREATE rows use `Create`; EDIT rows use `Modify` or `Create`. - - Target files and screen briefs are absolute paths under the working directory. + - Target files and screen briefs are absolute paths under `[working directory]`. - No two rows target the same file. - No two rows share a `Name Prefix`. - - In CREATE mode the first row targets `Screen1.pa.yaml` with YAML key `Screen1`. -4. Confirm `canvas-app-shared.md` and every dispatch row's screen brief exist. Verify each - brief's assignment matches its dispatch row. + - In CREATE mode the first row targets `[working directory]/Screen1.pa.yaml` with YAML key `Screen1`. +4. Confirm `[working directory]/canvas-app-shared.md` and every dispatch row's `Screen Brief` exists. + Verify each brief's assignment matches its dispatch row. 5. In EDIT mode, apply the `### Before builders` group of `## App Changes` to - `App.pa.yaml` now. Screens bind to those collections, formulas and variables, and - compiling them against a stale app file produces false name errors. -6. Confirm the planner reported a clean `compile_canvas` for CREATE-mode `App.pa.yaml`. - If it did not, compile now and resolve every App-level diagnostic before dispatching. + `[working directory]/App.pa.yaml` now. Screens bind to those collections, formulas and variables, and + compiling them against a stale `App.pa.yaml` produces a flood of false name errors. +6. Confirm the planner reported a clean `compile_canvas` for `[working directory]/App.pa.yaml`. If it + did not, compile now and resolve every `App`-level diagnostic before dispatching. For EDIT mode, compile after applying the before-builder app changes and resolve App-level diagnostics before dispatching. -7. Invoke `canvas-screen-builder` once per dispatch row, in parallel waves of at most - three. Wait for the whole wave to return before dispatching the next. +7. Invoke `canvas-screen-builder` once per dispatch row, in waves of + **at most three**. Fire the wave's invocations together in one message, wait for that + wave to return, then dispatch the next. -Never dispatch more than three builders at once. Larger fan-outs can hang, and waves of -three expose systemic defects before every screen repeats them. +Never dispatch more than three builders at once. Larger fan-outs have hung without +returning, and waves of three get you the first compile sooner, which is where systemic +defects surface. -If any pre-dispatch check fails, do not start builders. Re-invoke `canvas-app-planner` -with the specific defects and repeat the checks on the corrected artifacts. +If any pre-dispatch check fails, do not start builders. Re-invoke the planner with the +specific defects and repeat the checks on the corrected artifacts. Pass each builder only: ```text Action: [Create / Modify] Screen: [logical screen name] -Target file: [absolute .pa.yaml path] +Target file: `[working directory]/[file].pa.yaml` YAML screen key: [key from dispatch row] Control name prefix: [prefix from dispatch row] -Shared plan: [absolute canvas-app-shared.md path] -Screen brief: [absolute screen-plan.md path] +Shared plan: `[working directory]/canvas-app-shared.md` +Screen brief: `[working directory]/[file-base].screen-plan.md` Plugin root: ${PLUGIN_ROOT} ``` @@ -100,55 +102,77 @@ unrecognized. Confirm it matches a remaining dispatch row and leave it in place. After all builders finish: - Check each builder's `QA:` line. It must list an outcome for every check in - `${PLUGIN_ROOT}/references/QAChecks.md`. Treat these as unrun and return the existing - screen to the builder for self-QA only: - - a missing or truncated line, a line omitting any check listed in + `${PLUGIN_ROOT}/references/QAChecks.md`. Treat these as unrun and send the screen back for self-QA + only — not a rebuild — before you compile: + - a missing or truncated `QA:` line, a line that omits any check listed in `${PLUGIN_ROOT}/references/QAChecks.md`, or a bare fix count; - - an outcome contradicted by the screen structure, such as - `QACHK-CROSS-AXIS-ALIGNMENT` `N/A` despite AutoLayout children, - `QACHK-ACCESSIBLE-LABEL-MISSING` `N/A` despite content controls, - `QACHK-LOW-CONTRAST-TEXT` `N/A` despite a coloured surface, or - `QACHK-ROOT-CONTAINMENT` `PASS` while a responsive root has screen-level siblings; - - `QACHK-GALLERY-ROW-FITS-CONTENT` `N/A` despite the screen containing a Gallery; - - `QACHK-ACTION-LABEL-FIT` `PASS` while a multiword action directly under vertical - AutoLayout lacks `Width: =Parent.Width`. -- A self-QA follow-up is not a rebuild. Ask the builder to inspect and repair the existing - target file, then return the corrected `QA:` line. -- Compare every repeated navigation block against `canvas-app-shared.md`: same items, - order, wordmark, colours, and narrow-width behavior. Builders cannot perform this - app-wide comparison because each sees only one screen. -- Reject `QACHK-CARD-PLACEHOLDER` `PASS` when a `ModernCard` displays Title, Subtitle and - Description with `Height < 180`; return that screen for self-QA. -- If a builder returns `Status: Blocked`, re-invoke the planner to repair only that screen - brief, then rerun only that builder. -- `Status: Blocked` is the only reason to rerun screen generation. Repair compile - diagnostics in place; regeneration discards fixes and does not converge. -- In EDIT mode, apply the `### After builders` group of `## App Changes` to `App.pa.yaml`. - The orchestrator is the sole owner of EDIT changes to that file. + - an outcome that contradicts the screen structure — for example, + `QACHK-CROSS-AXIS-ALIGNMENT` is `N/A` despite AutoLayout children, + `QACHK-ACCESSIBLE-LABEL-MISSING` is `N/A` despite content or input controls, + `QACHK-LOW-CONTRAST-TEXT` is `N/A` despite a non-default coloured surface, or + `QACHK-ROOT-CONTAINMENT` is `PASS` while a responsive root has screen-level siblings; + - `QACHK-GALLERY-ROW-FITS-CONTENT` is `N/A` despite the screen containing a Gallery; + - `QACHK-ACTION-LABEL-FIT` is `PASS` while a multiword action directly under vertical + AutoLayout lacks `Width: =Parent.Width`; + `PASS` is valid after a complete inspection finds no defect; never reject it solely + because the screen has many controls. + This costs one cheap turn. The defects these checks catch — clipped headings, invisible + buttons, placeholder cards — are invisible to `compile_canvas`, so if you skip this the + app ships broken while reporting clean. +- A self-QA follow-up is not a rebuild or a screen-generation re-dispatch. Tell the + builder to inspect and repair the existing target file, then return the corrected + `QA:` line without regenerating the screen. +- Compare every repeated navigation block against `[working directory]/canvas-app-shared.md`: same + destination items, same order, no extra brand/label injected into one screen's nav, + and width formulas that fit the narrowest target. This is an app-wide check builders + cannot perform because each sees only one screen. +- Reject `QACHK-CARD-PLACEHOLDER` `PASS` when a ModernCard displays Title, Subtitle and + Description with `Height < 180`; send that screen back for self-QA. +- If a builder returns `Status: Blocked`, re-invoke the planner to correct that screen + brief, then rerun only the affected builder. Never ask a builder to guess missing + definitions. +- `Status: Blocked` is the **only** reason to rerun screen generation from a brief. + Compile diagnostics are not. Once a screen file exists you repair it in place with + targeted edits. Re-running generation rewrites the whole screen from scratch, discards + the fixes already applied, and produces a fresh crop of defects. That loop does not + converge. +- In EDIT mode, apply the `### After builders` group of `## App Changes` in + `[working directory]/canvas-app-plan.md` to `[working directory]/App.pa.yaml`. The `### Before builders` group was + already applied at pre-dispatch. If a group says `None`, do not edit the file for it. +- The orchestrator is the sole owner of EDIT changes to `[working directory]/App.pa.yaml`. - Read `${PLUGIN_ROOT}/references/ValidationWorkflow.md` and follow it. ## Shared Invariants -1. Never guess control properties. Use `describe_control`; only write properties returned - for that exact control type or already present on that exact existing control. +1. Never guess control properties. Use `describe_control`; only use properties returned + for that exact control type. 2. Use exact RGBA values and shared variable names from approved plans. -3. Control names are unique across the entire app, not per screen. Every new control uses - the standard control-type abbreviation followed by the screen prefix, such as - `conDiscNavBar` or `btnDetailBack`, especially for repeated nav bars, headers, - toolbars, and badges. -4. Never write a version suffix on `Control:`. Write `Control: ModernText`, never - `Control: ModernText@1.5.0`. One suffixed instance can produce hundreds of false - `Unknown property` diagnostics throughout the app. -5. Never invent an enum type name. Copy the exact `Enum name:` from `describe_control`. - Quote enum members that start with a digit: - `DecimalPrecision.'1'`, not `DecimalPrecision.1`. -6. In CREATE mode, reuse `Screen1.pa.yaml` for the landing screen and set +3. **Control names are unique across the entire app, not per screen.** Two screens may + not both contain a control named `NavBar` or `btnBack`; the compiler rejects the + second with `An entity with name '...' already exists`. Every control a builder + writes uses the standard control-type abbreviation followed by that screen's assigned + name prefix, such as `conDiscNavBar` or `btnDetailBack`. This applies especially to UI + blocks repeated on many screens — nav bars, headers, toolbars, badges. +4. **Never write a version suffix on `Control:`.** Write `Control: ModernText`, never + `Control: ModernText@1.5.0`. One suffixed instance pins the whole app to a single + template version, and every property that exists only in the other version then fails + with `Unknown property '...' for control type '...'` — on controls that are perfectly + correct. One stray suffix can produce hundreds of them. +5. **Never invent an enum type name.** `describe_control` prints the exact name on the + `Enum name:` line of each enum property. Copy it verbatim. Enum names do not follow + from control names: `Badge.Appearance` is `BadgeCanvas.Appearance`, `Progress.Shape` + is `Progress.Shape`, and `ModernDropdown.Appearance` is just `Appearance`. An enum + **member** that starts with a digit must be quoted too — `DecimalPrecision.'1'`, never + `DecimalPrecision.1`, which fails with `Expected operator` and `Expected an operand` + rather than `Name isn't recognized`. +6. In CREATE mode, reuse `[working directory]/Screen1.pa.yaml` for the landing screen and set `App.StartScreen` to `=Screen1`. 7. Never navigate from `App.OnStart` or the start screen's `OnVisible`. 8. Keep mock data compact: roughly 5-8 short rows per collection. -9. Builders own exactly one screen file. The planner owns CREATE-mode `App.pa.yaml`; the - orchestrator owns EDIT-mode `App.pa.yaml`. -10. Compile early and after each builder wave. Never defer the first compile until every - file is written. +9. Builders own exactly one screen file. The planner owns CREATE-mode `App.pa.yaml`. + The orchestrator owns EDIT-mode `App.pa.yaml`. +10. Compile early and often. `App.pa.yaml` is validated before builders are dispatched, + and again as soon as the first builder returns. Never defer the first compile until + every file is written. 11. Do not report completion until the workspace compiles clean or remaining diagnostics are explicitly reported. From 8f6b83783d0a686ff429c28c011fa0eed453a72c Mon Sep 17 00:00:00 2001 From: "Joe Mayo (Power Apps)" Date: Wed, 19 Aug 2026 16:44:36 -0700 Subject: [PATCH 2/2] [canvas-apps] Sync prompts from PA-Client --- .../canvas-apps/agents/canvas-app-planner.md | 22 ++- .../agents/canvas-screen-builder.md | 2 +- .../canvas-apps/references/ControlGuide.md | 52 +++--- .../canvas-apps/references/CreateWorkflow.md | 2 +- plugins/canvas-apps/references/DesignGuide.md | 4 +- .../canvas-apps/references/EditWorkflow.md | 4 +- plugins/canvas-apps/references/LayoutGuide.md | 10 +- .../canvas-apps/references/PlanTemplates.md | 6 + plugins/canvas-apps/references/QAChecks.md | 10 +- .../references/ValidationWorkflow.md | 5 +- plugins/canvas-apps/references/YamlSyntax.md | 163 +++++++++++++----- .../canvas-apps/skills/canvas-app/SKILL.md | 4 + 12 files changed, 193 insertions(+), 91 deletions(-) diff --git a/plugins/canvas-apps/agents/canvas-app-planner.md b/plugins/canvas-apps/agents/canvas-app-planner.md index 30e06a0e1..4282e3d1a 100644 --- a/plugins/canvas-apps/agents/canvas-app-planner.md +++ b/plugins/canvas-apps/agents/canvas-app-planner.md @@ -60,7 +60,7 @@ Read: - `${PLUGIN_ROOT}/references/YamlSyntax.md` — file structure, syntax rules, parse-error triage - `${PLUGIN_ROOT}/references/ControlGuide.md` — control selection, per-control properties, enums -- `${PLUGIN_ROOT}/references/LayoutGuide.md` — responsive layout, scrolling, colour contrast +- `${PLUGIN_ROOT}/references/LayoutGuide.md` — responsive layout, scrolling, color contrast - `${PLUGIN_ROOT}/references/PowerFxGuide.md` — state, events, named formulas, mock data - `${PLUGIN_ROOT}/references/DesignGuide.md` — aesthetic direction and design process - `${PLUGIN_ROOT}/references/PlanTemplates.md` — the exact shape of every artifact you write @@ -89,6 +89,13 @@ ManualLayout. recorded, because the builder cannot look it up. 5. Call API and schema detail tools only for resources involved in the edit. +### Component refresh checkpoint + +Immediately before auditing properties, re-run `describe_control` for +every Canvas or Code Component used by the plan to ensure any imported or updated components made in Studio are available. +Especially if a successful compile applied local component-definition changes, since the previous lookup. +Treat earlier component responses as stale; builders cannot refresh them. + ## 3. Audit Control Properties Before writing plans: @@ -151,7 +158,7 @@ clear navigation is cheaper than a screen that no builder can write correctly in and no user can scan. Prefer splitting by task (entry vs. history vs. analysis) rather than by control count. -## 5. Specify the Narrow-Width Behaviour +## 5. Specify the Narrow-Width Behavior Builders implement exactly what the brief specifies. If the brief describes only the desktop composition, the screen will break on a phone — this is the most frequently @@ -168,7 +175,7 @@ For every screen brief, state explicitly: - That the root container scrolls (`LayoutOverflowY: =LayoutOverflow.Scroll`). - That the screen-level `Children:` list contains only that root, with every visible section nested under the root's `Children:` list. -- The foreground colour for text on every coloured surface, so nothing renders +- The foreground color for text on every colored surface, so nothing renders dark-on-dark. - A width or `LayoutMinWidth` for status badges and KPI values that fits the longest value they can display. @@ -244,6 +251,12 @@ Do not edit any `.pa.yaml` file. Put all required app-level edits in the plan in If a group is empty, write `None` for it. +### All modes + +Put requested screen or component-definition ordering in `## Editor State Changes` as +the exact final `ScreensOrder` and `ComponentDefinitionsOrder` lists. Write `None` when +the current Studio order should remain unchanged. + ## 8. Write Progressive Plan Artifacts Follow `${PLUGIN_ROOT}/references/PlanTemplates.md`. @@ -257,6 +270,7 @@ Write only orchestration information: - Compact discovery summary - Dispatch table - EDIT-mode App changes +- Editor state changes The dispatch table columns are: @@ -354,7 +368,7 @@ App compile: [Clean / diagnostics remaining, with detail] - Do not edit existing `.pa.yaml` files in EDIT mode. - Call `compile_canvas` only to validate CREATE-mode `App.pa.yaml`. Do not use it to chase screen-file diagnostics; the orchestrator owns full-app validation. -- Do not edit `[working directory]/_EditorState.pa.yaml`. +- Do not edit `[working directory]/_EditorState.pa.yaml`; record ordering work in `## Editor State Changes` for the top-level orchestrator. - Do not embed all discovery output in the index or shared plan. - Every screen brief must be self-sufficient when read with the shared plan. - Never assign two screens the same control name prefix. diff --git a/plugins/canvas-apps/agents/canvas-screen-builder.md b/plugins/canvas-apps/agents/canvas-screen-builder.md index da6a2d063..8ab282910 100644 --- a/plugins/canvas-apps/agents/canvas-screen-builder.md +++ b/plugins/canvas-apps/agents/canvas-screen-builder.md @@ -165,7 +165,7 @@ incomplete, and the orchestrator will send the screen back. ## Constraints - Modify exactly one screen file. -- Never edit `[working directory]/App.pa.yaml` or `[working directory]/_EditorState.pa.yaml`. +- Do not edit `[working directory]/App.pa.yaml` or `[working directory]/_EditorState.pa.yaml`; the top-level orchestrator owns app-level and cross-file ordering changes. - Never substitute a filename, YAML key, or control name prefix. - Never use a property absent from that control's definition. - Never write a version suffix on a `Control:` value. diff --git a/plugins/canvas-apps/references/ControlGuide.md b/plugins/canvas-apps/references/ControlGuide.md index fe2b02925..06e476b6e 100644 --- a/plugins/canvas-apps/references/ControlGuide.md +++ b/plugins/canvas-apps/references/ControlGuide.md @@ -6,6 +6,7 @@ Choosing a control type, and writing properties and enum values that the compile ## Contents - Discover before you choose +- Interpret property defaults and requirements - Layout containers - Data display - Selection controls — `ItemDisplayText` is a per-item formula @@ -14,7 +15,7 @@ Choosing a control type, and writing properties and enum values that the compile - Enum type names - Enum member values - Option set values -- Colour and button-state patterns +- Color and button-state patterns - Timer lifecycle - Read-only ancestors - Cross-screen navigation @@ -27,7 +28,26 @@ Choosing a control type, and writing properties and enum values that the compile **⚠️ Required — not optional:** run `list_controls` before planning your layout. Controls you don't know exist can't influence your design, and the catalog includes high-level controls (`ModernTabList`, `ModernCard`, and others) that are easy to miss and expensive -to reinvent with primitives. Then run `describe_control` on every type you plan to use. +to reinvent with primitives. + +The resulting list will also specify if any Code Components or Canvas Components are available as control instances in the app. The result identifies the `ComponentName` to pass to `describe_control`. + +Run `describe_control` on every type you plan to use. + +## Interpret property defaults and requirements + +The `Default` shown for a property is the value the property takes when it is omitted from the YAML. +Properties marked `Required: true` must be provided, even when no default is shown. +Omit other properties to accept their default. + +### Refresh Canvas and Code Component descriptions + +`describe_control` results for Canvas and Code Components are snapshots of the current +Studio document, not durable catalog entries. Re-run `describe_control` for the returned +`ComponentName` after a successful `compile_canvas` applies changes to a local component +definition or its custom properties. Do not reuse component descriptions from an earlier +turn after any of those events. Refresh immediately before recording component properties +in a plan or editing a component instance. ## Layout containers @@ -283,10 +303,10 @@ or starts with a number: Visible: =ThisItem.Status = 'Status (Assignments)'.Active ``` -## Colour and button-state patterns +## Color and button-state patterns ```yaml -# Colour constants +# Color constants Fill: =Color.White BasePaletteColor: =Color.Blue @@ -294,7 +314,7 @@ BasePaletteColor: =Color.Blue Fill: =RGBA(240, 240, 240, 1) FontColor: =RGBA(0, 0, 0, 1) -# Conditional colour +# Conditional color BasePaletteColor: =If(isActive, Color.Blue, Color.Gray) ``` @@ -303,18 +323,6 @@ and `Transparent` can remain light even when `Fill` is set. Pair those appearanc dark `Color`, or switch to `Primary` and set `BasePaletteColor` for a dark surface. Do not assume `Fill` overrides the variant. -```yaml -Properties: - DisplayMode: =If(isDisabled, DisplayMode.Disabled, DisplayMode.Edit) - Text: =buttonText - OnSelect: |- - =If(condition, - false, # Guard clause - do nothing - Set(variable, value); # Execute logic - Set(anotherVar, anotherValue) - ) -``` - ## Timer lifecycle An automatic Timer needs a start edge after the control exists. If `AutoStart: =false` @@ -361,13 +369,13 @@ replace `Badge.Content`; omitting Content can render placeholder text such as `A **Styling:** -- `Fill` — background colour (absent on `Badge` and `Progress`) -- `Color` — text colour on the modern React controls; `Badge` spells it `FontColor` -- `BasePaletteColor` — theme colour for `Badge`, `Progress`, and the modern inputs +- `Fill` — background color (absent on `Badge` and `Progress`) +- `Color` — text color on the modern React controls; `Badge` spells it `FontColor` +- `BasePaletteColor` — theme color for `Badge`, `Progress`, and the modern inputs - `Size` — font size on the modern React controls; `Badge` spells it `FontSize` - `FontWeight` — Bold, Semibold, Normal, Lighter -**Behaviour:** +**Behavior:** - `DisplayMode` — Edit, View, Disabled - `Visible` — boolean visibility @@ -382,7 +390,7 @@ replace `Badge.Content`; omitting Content can render placeholder text such as `A - `LayoutGap` — spacing between items - `LayoutOverflowY` — vertical overflow (`Scroll` for scrollable containers) - `FillPortions` — proportional sizing -- `PaddingTop/Bottom/Left/Right` — container padding +- `PaddingTop`/`Bottom`/`Left`/`Right` — container padding ## Troubleshooting diff --git a/plugins/canvas-apps/references/CreateWorkflow.md b/plugins/canvas-apps/references/CreateWorkflow.md index 0b23aea96..f8f4b1f0a 100644 --- a/plugins/canvas-apps/references/CreateWorkflow.md +++ b/plugins/canvas-apps/references/CreateWorkflow.md @@ -8,7 +8,7 @@ Read: - `${PLUGIN_ROOT}/references/YamlSyntax.md` — file structure, syntax rules, parse-error triage - `${PLUGIN_ROOT}/references/ControlGuide.md` — control selection, per-control properties, enums -- `${PLUGIN_ROOT}/references/LayoutGuide.md` — responsive layout, scrolling, colour contrast +- `${PLUGIN_ROOT}/references/LayoutGuide.md` — responsive layout, scrolling, color contrast - `${PLUGIN_ROOT}/references/PowerFxGuide.md` — state, events, named formulas, mock data - `${PLUGIN_ROOT}/references/DesignGuide.md` — aesthetic direction and design process diff --git a/plugins/canvas-apps/references/DesignGuide.md b/plugins/canvas-apps/references/DesignGuide.md index 3318cda74..970d3649a 100644 --- a/plugins/canvas-apps/references/DesignGuide.md +++ b/plugins/canvas-apps/references/DesignGuide.md @@ -62,7 +62,7 @@ the real user experience. - **Font Weight**: Use `ModernText` for headlines with `FontWeight: =FontWeight.Bold` and a large font size. Use `ModernText` with `FontWeight: =FontWeight.Normal` for body content. - **Size Contrast**: Create dramatic hierarchy with size differences. Headers at 24-32, subheaders at 18-20, body at 14-16. - **Alignment as Statement**: Mix `Align.Left`, `Align.Center`, `Align.Right` intentionally. Centered text for impact, left-aligned for readability. -- **Font Properties**: Leverage `Size`, `FontWeight`, `Align`, `VerticalAlign`, and `Color` to create visual interest. On the modern React controls the text colour property is `Color` and the font size property is `Size` — `FontColor` and `FontSize` exist only on `Badge`. Confirm with `describe_control` rather than assuming. +- **Font Properties**: Leverage `Size`, `FontWeight`, `Align`, `VerticalAlign`, and `Color` to create visual interest. On the modern React controls the text color property is `Color` and the font size property is `Size` — `FontColor` and `FontSize` exist only on `Badge`. Confirm with `describe_control` rather than assuming. ### Color & Visual Theme @@ -80,7 +80,7 @@ the real user experience. - **Design for the narrowest width you claim to support**: A layout composed at 1440px and never re-checked will clip at 1024px and collapse on a phone. Size layout containers with `Parent.Width` or `FillPortions`, never a literal like `Width: =1120`. Reserve fixed pixel sizes for icons, avatars, and steppers — and keep interactive ones at 44px or larger. - **Every horizontal row of more than two controls needs a reflow strategy**: Set `LayoutWrap: =true`, or drive `LayoutDirection` from a width breakpoint, so rows stack instead of squeezing. This is the single most common defect in generated apps and it is invisible at the width you designed at. - **The screen root must scroll** whenever it holds a gallery, a form, or more than about three stacked sections: canvas screens do not scroll on their own, so give the root container `LayoutOverflowY: =LayoutOverflow.Scroll` and content below the fold stays reachable on short viewports. -- **Set foreground wherever you set background**: Text does not inherit a contrasting colour. Every time you choose a container `Fill`, set `Color` on the text inside it — dark-on-dark passes every automated check and is unreadable. +- **Set foreground wherever you set background**: Text does not inherit a contrasting color. Every time you choose a container `Fill`, set `Color` on the text inside it — dark-on-dark passes every automated check and is unreadable. - **Rows inside a `Gallery` need their own container**: `Gallery` is a Classic control and positions its template children absolutely, so a row authored at desktop width stays at desktop width everywhere. Put one AutoLayout `GroupContainer` in the template and build the row inside it. See `${PLUGIN_ROOT}/references/LayoutGuide.md`. - **Asymmetry & Breaking Grid**: Don't center everything. Offset elements. Use unexpected positioning. - **Spacing as Design**: Generous padding creates breathing room. Dense layouts create energy. diff --git a/plugins/canvas-apps/references/EditWorkflow.md b/plugins/canvas-apps/references/EditWorkflow.md index d89549ead..2b125a666 100644 --- a/plugins/canvas-apps/references/EditWorkflow.md +++ b/plugins/canvas-apps/references/EditWorkflow.md @@ -19,7 +19,7 @@ Anything else is **complex**. 1. Read `${PLUGIN_ROOT}/references/YamlSyntax.md`. Also read `${PLUGIN_ROOT}/references/ControlGuide.md` when the edit touches control properties or enums, and `${PLUGIN_ROOT}/references/LayoutGuide.md` when it touches - sizing, scrolling, or colour. + sizing, scrolling, or color. 2. Use `describe_control` before adding a property not already present on that control. 3. Apply targeted edits directly to the `[working directory]` folder. 4. Read `${PLUGIN_ROOT}/references/ValidationWorkflow.md` and follow it. @@ -31,7 +31,7 @@ Read: - `${PLUGIN_ROOT}/references/YamlSyntax.md` — file structure, syntax rules, parse-error triage - `${PLUGIN_ROOT}/references/ControlGuide.md` — control selection, per-control properties, enums -- `${PLUGIN_ROOT}/references/LayoutGuide.md` — responsive layout, scrolling, colour contrast +- `${PLUGIN_ROOT}/references/LayoutGuide.md` — responsive layout, scrolling, color contrast - `${PLUGIN_ROOT}/references/PowerFxGuide.md` — state, events, named formulas, mock data - `${PLUGIN_ROOT}/references/DesignGuide.md` — aesthetic direction and design process diff --git a/plugins/canvas-apps/references/LayoutGuide.md b/plugins/canvas-apps/references/LayoutGuide.md index 075177a9e..1c0968a2a 100644 --- a/plugins/canvas-apps/references/LayoutGuide.md +++ b/plugins/canvas-apps/references/LayoutGuide.md @@ -1,6 +1,6 @@ -# Canvas App YAML — Layout and Responsive Behaviour +# Canvas App YAML — Layout and Responsive Behavior -Sizing, positioning, scrolling, and the narrow-width behaviour that decides whether a +Sizing, positioning, scrolling, and the narrow-width behavior that decides whether a screen works on a phone. The defects in this guide are invisible at the width you author and are reported by no compile diagnostic. @@ -13,7 +13,7 @@ and are reported by no compile diagnostic. - Galleries are Classic — their rows do not reflow - Horizontal rows must reflow at narrow widths - Give labelled controls room for their longest value -- Text colour must be set wherever you set a background +- Text color must be set wherever you set a background - Never hard-code a layout width - The screen root must be able to scroll - Layout rules of thumb @@ -220,9 +220,9 @@ control sits in a horizontal row, set `FillPortions: =0` plus a `Width` (or `LayoutMinWidth`) that fits the longest value it can display, and set `Wrap: =false` on single-line text so it cannot silently become two lines. -## Text colour must be set wherever you set a background +## Text color must be set wherever you set a background -Text controls do not inherit a contrasting colour from their container. A dark `Fill` with +Text controls do not inherit a contrasting color from their container. A dark `Fill` with an unset `Color` renders near-black text on a near-black surface — technically valid and completely unreadable: diff --git a/plugins/canvas-apps/references/PlanTemplates.md b/plugins/canvas-apps/references/PlanTemplates.md index a0856dc03..00972f2a4 100644 --- a/plugins/canvas-apps/references/PlanTemplates.md +++ b/plugins/canvas-apps/references/PlanTemplates.md @@ -43,6 +43,9 @@ CREATE |--------|--------|-------------|----------|-------------|--------------| | Create | [Landing] | `[working directory]/Screen1.pa.yaml` | Screen1 | [Prefix] | `[working directory]/Screen1.screen-plan.md` | | Create | [Additional] | `[working directory]/[Name].pa.yaml` | [Name] | [Prefix] | `[working directory]/[Name].screen-plan.md` | + +## Editor State Changes +[Exact final ScreensOrder and ComponentDefinitionsOrder lists, or "None"] ``` ## Plan Index — EDIT @@ -81,6 +84,9 @@ EDIT seed data — or "None"] ### After builders [Changes referencing screens that do not exist yet, such as StartScreen — or "None"] + +## Editor State Changes +[Exact final ScreensOrder and ComponentDefinitionsOrder lists, or "None"] ``` ## Shared Plan diff --git a/plugins/canvas-apps/references/QAChecks.md b/plugins/canvas-apps/references/QAChecks.md index 86ca7f6df..af5586151 100644 --- a/plugins/canvas-apps/references/QAChecks.md +++ b/plugins/canvas-apps/references/QAChecks.md @@ -43,7 +43,7 @@ are not part of the identifier. - Check 19 — `QACHK-NO-REFLOW` — horizontal row with no narrow-width strategy - Check 20 — `QACHK-ROOT-NOT-SCROLLABLE` — screen content taller than the viewport cannot be reached -- Check 21 — `QACHK-LOW-CONTRAST-TEXT` — text colour not set against a coloured background +- Check 21 — `QACHK-LOW-CONTRAST-TEXT` — text color not set against a colored background - Check 22 — `QACHK-VARIANT-SURFACE-CONTRAST` — light foreground on a variant-supplied surface - Check 23 — `QACHK-CARD-PLACEHOLDER` — `ModernCard` slot left unset @@ -780,18 +780,18 @@ viewport. --- -## Check 21 — `QACHK-LOW-CONTRAST-TEXT` (text colour not set against a coloured background) +## Check 21 — `QACHK-LOW-CONTRAST-TEXT` (text color not set against a colored background) -**Problem:** Text controls do not inherit a contrasting colour from their container. A +**Problem:** Text controls do not inherit a contrasting color from their container. A container with a dark `Fill` whose child text controls omit `Color` renders near-black on near-black. `compile_canvas` passes it. **Detect:** For every container that sets a non-default `Fill`, check every descendant text control (`ModernText`, `Badge`, and any control with a `Text` or `Content` property) -for an explicit colour — `Color` on the modern React controls, `FontColor` on `Badge`, +for an explicit color — `Color` on the modern React controls, `FontColor` on `Badge`, `TitleColor`/`SubtitleColor`/`DescriptionColor` on `ModernCard`. -**Fix:** Set the colour explicitly wherever the background was set: +**Fix:** Set the color explicitly wherever the background was set: ```yaml Color: =RGBA(239, 246, 250, 1) diff --git a/plugins/canvas-apps/references/ValidationWorkflow.md b/plugins/canvas-apps/references/ValidationWorkflow.md index c871d021a..235c5dfb4 100644 --- a/plugins/canvas-apps/references/ValidationWorkflow.md +++ b/plugins/canvas-apps/references/ValidationWorkflow.md @@ -161,8 +161,9 @@ diagnostic history, and a fresh agent would have to rediscover all of it. - The only sanctioned re-delegation is back to `canvas-app-planner` when a builder returned `Status: Blocked` because its brief was genuinely missing a definition or an assignment field — never for a diagnostic on a file that already exists. - -Never modify `[working directory]/_EditorState.pa.yaml` while repairing diagnostics. +- Modify `[working directory]/_EditorState.pa.yaml` when a diagnostic identifies it or when the requested + screen or component-definition order requires correction. Preserve valid names and + repair only the affected order entries. ### Verify before you summarize diff --git a/plugins/canvas-apps/references/YamlSyntax.md b/plugins/canvas-apps/references/YamlSyntax.md index 357451e31..f2d4913da 100644 --- a/plugins/canvas-apps/references/YamlSyntax.md +++ b/plugins/canvas-apps/references/YamlSyntax.md @@ -1,46 +1,34 @@ # Canvas App YAML — File Structure and Syntax -How a `.pa.yaml` file is shaped, the syntax rules that decide whether it parses, and the -starting workspace every new app arrives with. - -**Who does what.** Discovery and compilation belong to the orchestrator and the -`canvas-app-planner`: they run `list_controls`, `describe_control`, the data and API -tools, and `compile_canvas`. A `canvas-screen-builder` has only `view`, `create` and -`edit` — it never discovers and never compiles, and relies entirely on the property names, -enum names and variants recorded in its screen brief. Where these guides say "run -`list_controls`" or "compile early", that instruction is addressed to the orchestrator and -planner. +How a `.pa.yaml` file is shaped, the syntax rules that decide whether it parses, and the starting workspace every new app arrives with. ## Contents -- Before you write YAML - File structure -- `Variant` is required for controls that declare variants -- Multi-line formulas -- Values containing `: ` must be quoted -- Power Fx record literals must be quoted -- Every property value starts with `=` -- Reading `YamlInvalidSyntax` reasons + - Named objects representations + - Creating control instances + - The `Variant` keyword may be optional, required or not allowed + - Canvas and Code Component discovery + - Canvas Component instances + - Code Component (aka third-party control) instances +- YAML syntax rules + - Multi-line formulas + - Values containing `: ` must be quoted + - Power Fx record literals must be quoted + - Every property value starts with `=` + - Reading `YamlInvalidSyntax` reasons - The starting workspace — `Screen1` and `_EditorState.pa.yaml` - App configuration -## Before you write YAML - -1. ⚠️ **Run `list_controls` first — this is non-optional.** Controls you don't know exist - can't influence your design, and the catalog includes high-level controls that are - expensive to reinvent from primitives. -2. Run `describe_control` for every control type you intend to use, and record the exact - property names, `Enum name:` lines and variants. -3. Review this guide, `${PLUGIN_ROOT}/references/ControlGuide.md`, `${PLUGIN_ROOT}/references/LayoutGuide.md` and - `${PLUGIN_ROOT}/references/DesignGuide.md` before designing a screen. -4. Plan state: the variables each screen sets, and where they are initialized. -5. Choose a layout strategy: AutoLayout for responsive, ManualLayout only for fixed - desktop dashboards. -6. Compile early and often rather than saving validation for the end. - ## File structure -Have one `.pa.yaml` file for the App object, and a separate file for each screen. +Each '*.pa.yaml' file should contain a single top-level object. These are specified using one of the following top-level keywords: +- `App` - Represents the 'App' object in the app. The filename for this object should be `App.pa.yaml`. +- `EditorState` - Controls the Studio ordering of screens and local component definitions through `ScreensOrder` and `ComponentDefinitionsOrder`. Use filename `_EditorState.pa.yaml`. +- `ComponentDefinitions` - A named-object-mapping of local component definitions. Use filename `.pa.yaml`. +- `Screens` - A named-object-mapping of screens in the app Use filename `.pa.yaml`. + +You should ensure each top-level object is placed into its own pa.yaml file, using the correct top-level keyword. ```yaml Screens: @@ -61,26 +49,93 @@ Screens: ... ``` -### `Variant` is required for controls that declare variants +### Named objects representations -`Variant` is not a styling nicety. A control whose template declares variants has no -default, and omitting the key fails the compile: +In the Power Apps YAML schema, data structures represent objects that have names. +There are two common structures used to represent sets of these objects: -```text -The keyword 'Variant' is required but is missing or empty. +#### named-object-sequence + +A YAML sequence (aka array) where each item represents a single named object. The ordering of these objects IS SIGNIFICANT and is implied by their order in the YAML source. + +Example: The `Children` keyword is always a named-object-sequence. +```yaml +Children: + - child1: + Control: Text + - child9: + Control: Text + - child2: + Control: Text ``` +The meaning of the `Children` order depends on the parent, but in most cases it reflects either Z-index order or order within a layout container. + +#### named-object-mapping + +A YAML mapping where each item's name is a keyword in the mapping. No ordering of these named objects is implied. +When the server writes YAML, it usually normalizes the order to provide consistent round-tripping, such as for source-control diffs. + +Example: All control instances and most top-level objects (App, Screens, ComponentDefinitions) support a `Properties` keyword +which contains the Power Fx expressions for each input property available for the control. +```yaml + - myControl1: + Control: ControlTypeId + Properties: + PropertyName1: =formula + PropertyName3: =formula + PropertyName2: =formula +``` + +### Creating control instances + +A control instance is any control that is not a top-level object. These are usually specified under the `Children` keyword of a parent object. +The structure of the `Children` is a named-object-sequence, as mentioned above. + +For each control instance, the following YAML object keywords are used to create a control instance (aka control creation keywords): +- `Control` - Required. aka 'ControlTypeId'. Indicates the control type. +- `ComponentName` - Required for any Canvas or Code Component instances (i.e. when `Control` is `CanvasComponent` or `CodeComponent`). See below for more info +- `ComponentLibraryUniqueName` - Required for instances of Canvas Components that are imported from a Component Library. This value comes from the library's unique name in Dataverse. +- `Variant` - Indicates a variant or flavor of the control which often defines additional properties and or behaviors. For some controls, this keyword may be optional, required or not allowed. +- `Layout` - Indicates the direction that a control should layout their children. For some controls, this keyword may be required or not allowed. + +To get details of whether a control requires any of the above keywords, you must make a call to the `describe_control` tool. -The message names no file and no control, so it is expensive to locate after the fact. -The two you will use constantly are: +### The `Variant` keyword may be optional, required or not allowed -| Control | Allowed `Variant` values | +The call to `describe_control` specifies whether the `Variant` keyword is optional or required. If the result doesn't list any variants, then the `Variant` keyword is not allowed. + +The two controls you will use constantly are: + +| ControlTypeId | Allowed `Variant` values | |---------|--------------------------| | `GroupContainer` | `AutoLayout`, `GridLayout`, `ManualLayout` | | `Gallery` | `Vertical`, `Horizontal`, `VariableHeight` (and many layout presets) | +* this list is not exhaustive; depend instead on the call to `describe_control`. + +### Canvas Component instances + +Canvas components (`Control: CanvasComponent`) are controls that are defined within the same Power App (aka local component), or imported from a Component Library stored in Dataverse. + +Local component definitions can be authored in the `Components/` folder as `.pa.yaml` files. + +Canvas component instances use the following control creation keywords: +```yaml +Control: CanvasComponent # required +ComponentName: Dialog # the name of the component after being imported into the app +ComponentLibraryUniqueName: cat_powercatcomponentlibrary_0be3a # Required for library components; otherwise, not used for local components +``` +Note: The following keywords are not supported for Canvas Components: `Variant`, `Layout` -`Form` (`Modern`, `Classic`) and the data-card and data-grid-column controls also require -one. `describe_control` lists a `Variants` section for any control that needs it — if that -section is present, the key is mandatory. +### Code Component (aka third-party control) instances + +Code components (`Control: CodeComponent`) are third-party controls made available by the Dataverse environment through a solution. Currently, they must be imported through the Power Apps Studio client. + +Code component instances use the following control creation keywords: +```yaml +Control: CodeComponent # required +ComponentName: cat_PowerCAT.Spinner # the name of the code component +``` +Note: The following keywords are not supported for Code Components: `ComponentLibraryUniqueName`, `Variant`, `Layout`. ## YAML syntax rules @@ -205,7 +260,7 @@ A new blank app is **not** an empty workspace. It already contains: - `App.pa.yaml` — app-level properties - `Screen1.pa.yaml` — one default screen, possibly with an empty container scaffold -- `_EditorState.pa.yaml` — Editor metadata (`ScreensOrder`) +- `_EditorState.pa.yaml` — Studio ordering metadata (`ScreensOrder` and `ComponentDefinitionsOrder`) ### Reuse `Screen1` — never leave it stranded @@ -215,8 +270,8 @@ and it makes the app look unfinished. **Rule:** In CREATE mode, the first screen of your design MUST be written into `Screen1.pa.yaml`, replacing its contents wholesale. Keep the top-level key as `Screen1` -so `_EditorState.pa.yaml` stays consistent, and give every control inside it a meaningful -name. +and include `Screen1` in the intended position in `_EditorState.pa.yaml`. Give every +control inside it a meaningful name. ```yaml # Screen1.pa.yaml — the app's first real screen. Do NOT create "Home.pa.yaml" @@ -233,7 +288,21 @@ Screens: ... ``` -Never edit `_EditorState.pa.yaml`; Studio owns it. +Edit `_EditorState.pa.yaml` when the requested Studio order differs from the current +order. List exact screen and component-definition names in the desired sequence: + +```yaml +EditorState: + ScreensOrder: + - Screen1 + - DetailsScreen + ComponentDefinitionsOrder: + - HeaderComponent +``` + +Preserve existing names that are not being removed from the app. Names omitted from an +order list are placed after listed entries, so include the full list when deterministic +ordering matters. ## App configuration diff --git a/plugins/canvas-apps/skills/canvas-app/SKILL.md b/plugins/canvas-apps/skills/canvas-app/SKILL.md index 30fc32caf..3d470adf4 100644 --- a/plugins/canvas-apps/skills/canvas-app/SKILL.md +++ b/plugins/canvas-apps/skills/canvas-app/SKILL.md @@ -56,6 +56,7 @@ CREATE and complex EDIT workflows return here after the planner finishes. - No two rows target the same file. - No two rows share a `Name Prefix`. - In CREATE mode the first row targets `[working directory]/Screen1.pa.yaml` with YAML key `Screen1`. + - `## Editor State Changes` exists and contains exact final order lists or `None`. 4. Confirm `[working directory]/canvas-app-shared.md` and every dispatch row's `Screen Brief` exists. Verify each brief's assignment matches its dispatch row. 5. In EDIT mode, apply the `### Before builders` group of `## App Changes` to @@ -140,6 +141,9 @@ After all builders finish: `[working directory]/canvas-app-plan.md` to `[working directory]/App.pa.yaml`. The `### Before builders` group was already applied at pre-dispatch. If a group says `None`, do not edit the file for it. - The orchestrator is the sole owner of EDIT changes to `[working directory]/App.pa.yaml`. +- Apply `## Editor State Changes` from `[working directory]/canvas-app-plan.md` to + `[working directory]/_EditorState.pa.yaml` after all builders finish. If it says `None`, leave the + file unchanged. - Read `${PLUGIN_ROOT}/references/ValidationWorkflow.md` and follow it. ## Shared Invariants