diff --git a/skills/uipath-maestro-case/SKILL.md b/skills/uipath-maestro-case/SKILL.md index 4f58b0e3e9..9966ceb438 100644 --- a/skills/uipath-maestro-case/SKILL.md +++ b/skills/uipath-maestro-case/SKILL.md @@ -50,8 +50,8 @@ without another prompt unless explicitly requested. If the request asks only for 10. **Cross-task references.** Use `"Stage Name"."Task Name".output_name` and the common output-reference-ID algorithm in [`plugins/variables/io-binding/impl-json.md`](references/plugins/variables/io-binding/impl-json.md#output-reference-id-authoritative). Use the source output’s `.id`; only a custom `=` output without `.id` uses its verified root companion’s `.id`. Never use a reassigned output’s `.var`. Discover names with `uip maestro case spec` for connector tasks or `uip maestro case tasks describe` for non-connectors. In larger `=js:` expressions use `vars.$xref('Stage','Task','output')`, resolved at Step 11.5. See [references/bindings-and-expressions.md](references/bindings-and-expressions.md). 11. **Build-review preference.** Capture once at journey start. Design handoff folds it into the Case Review Build options (`Build it — straight through` or `Build it — pause at the build preview`); provided SDD asks once after the roadmap. Non-interactive and resumed runs without a preference default to straight-through. At Phase 2→3, try `validate --skeleton-v2`; fall back once to legacy `--skeleton` only when the response explicitly says v2 is unknown/unsupported, typically invalid_argument/exit 3. Exit 3 alone is insufficient; real v2 failures are reported. Validation findings do not halt this advisory gate. Straight-through continues without prompting. Pause-at-preview follows [references/phased-execution.md](references/phased-execution.md): AskUserQuestion `Publish for review` / `Skip publish and continue` / `Abort`; on publish, refresh resources, upload with the required filter, print `DesignerUrl` before the follow-up, then ask `Continue to implementation` / `Abort`. Hard stops always remain at Phase 4 retry exhaustion, Phase 5, Phase 6, Phase 7, and any re-publish after a Phase 6 fix. 12. **Never auto-debug or publish to Orchestrator.** `uip maestro case debug` executes real emails, messages, and API calls. Phase 7 (`case pack` → `solution pack` → `solution publish`) ships to the tenant. Each requires its own AskUserQuestion consent. -13. **Artifact I/O.** For `caseplan.json`, `sdd.md`, `sdd.draft.md`, `tasks/registry-resolved.json`, `tasks/trigger-spec-cache.json`, `tasks/spec-cache..json`, `bindings_v2.json`, `id-map.json`, `entry-points.json`, and `build-issues.md`, use only your harness's file tools: `cat ` (or the Read tool, if the harness has one) to read, and Write / Edit (or `apply_patch`) to mutate. No Python, Node, jq, sed, awk, scripts, shell redirection, `tee`, `cp`, `mv`, `install`, or `rsync`; no helper scripts, including under `/tmp`, and no agent-authored script of any kind. **Exception — a read-only audit gate is allowed, not banned:** the planner's `audit_sdd.py` run over `sdd.md` writes nothing and only reports, so running it is always allowed. This rule exists to stop an artifact being AUTHORED or EDITED by script — never to stop it being CHECKED; the caseplan's own check is `uip maestro case validate --strict --sdd` (Rule 14). The `node -e ... fs.*` ban covers all file reads, including `~/.uip/case-resources/`; use `cat` (or Read) for cache lookup. If `caseplan.json` exceeds about 30KB, use the preview/detail cadence in [case-editing-operations.md](references/case-editing-operations.md), never a helper. Bash is allowed only for `cat`, UUID v4 generation without filesystem access, CLI metadata, validate, debug, and solution scaffold/upload. Prefixed IDs are chosen inline. -14. **Runnable resources and sidecars.** Before Phase 4, run Step 12 Checks 7, 9, 11, and 12 even when publish, debug, or resource refresh is skipped. A non-null `selected` resource must not become a placeholder: retain `data.name` and `data.folderPath` with complete root bindings, project it into `bindings_v2.json.resources[]`, and make its `resourceKey` self-consistent with its own defaults, never a copied tenant identity/UUID. Checks 9/11 exempt connector nodes; Check 12 covers resolved connector tasks, event triggers, and `wait-for-connector` rules, which require spliced `caseShape.context` plus Connection/Folder root bindings, not degraded typeId/connectionId-only data. CLI validate on the default profile is insufficient: the closing validate at Phase 3 exit and in Phase 4 is `uip maestro case validate --strict --sdd sdd.md --output json` (`--sdd` implies `--strict` and audits completeness against the SDD; omit it only when no `sdd.md` exists), and a `Valid` without `"Profile": "strict"` does not close the build. **Version guard:** `--strict`/`--sdd` exist from CLI 1.202. Fall back to plain `validate` only when the response is `invalid_argument` naming `--strict` or `--sdd` as an unknown option (exit 3 alone is insufficient; a strict *failure* is never a reason to drop the flags). On fallback, record `strict profile unavailable on CLI ` in `build-issues.md` and in the completion report, and run Step 12 Checks 1–15 by hand. Repair and recheck mismatches; halt before Phase 4 if they remain. Repeat Check 7 before every `resources refresh`. Refresh before every upload or debug. Every `solution upload` uses `--output-filter "{Status: Status, Action: Action, SolutionId: SolutionId, DesignerUrl: DesignerUrl}"`; print the returned DesignerUrl and say whether `Action` was `Imported` or `Overwritten`. +13. **Artifact I/O.** For `caseplan.json`, `sdd.md`, `sdd.draft.md`, `tasks/registry-resolved.json`, `tasks/trigger-spec-cache.json`, `tasks/spec-cache..json`, `id-map.json`, `entry-points.json`, and `build-issues.md`, use only your harness's file tools (`bindings_v2.json` is the exception: `uip maestro case bindings sync` generates it; never write it by hand): `cat ` (or the Read tool, if the harness has one) to read, and Write / Edit (or `apply_patch`) to mutate. No Python, Node, jq, sed, awk, scripts, shell redirection, `tee`, `cp`, `mv`, `install`, or `rsync`; no helper scripts, including under `/tmp`, and no agent-authored script of any kind. **Exception — a read-only audit gate is allowed, not banned:** the planner's `audit_sdd.py` run over `sdd.md` writes nothing and only reports, so running it is always allowed. This rule exists to stop an artifact being AUTHORED or EDITED by script — never to stop it being CHECKED; the caseplan's own check is `uip maestro case validate --strict --sdd` (Rule 14). The `node -e ... fs.*` ban covers all file reads, including `~/.uip/case-resources/`; use `cat` (or Read) for cache lookup. If `caseplan.json` exceeds about 30KB, use the preview/detail cadence in [case-editing-operations.md](references/case-editing-operations.md), never a helper. Bash is allowed only for `cat`, UUID v4 generation without filesystem access, CLI metadata, validate, `format`, `bindings sync`, debug, and solution scaffold/upload. Prefixed IDs are chosen inline. **Write `caseplan.json` pretty-printed — 2-space indentation, one key per line, no line over ~200 characters — from the T01 scaffold onward.** A compact plan cannot be patched by Edit/`apply_patch` (hunks need distinct context lines), and every observed `perl -pi`/`sed -i` violation of this rule started from a compact file. After every write of `caseplan.json`, run `uip maestro case format "" --output json`: it rewrites the file pretty-printed in place, is idempotent (`Changed: false` on a second run), and refuses an unparseable file untouched — it is the only sanctioned reformat. +14. **Runnable resources and sidecars.** Before Phase 4, run Step 12 Checks 7, 9, 11, and 12 even when publish, debug, or resource refresh is skipped. A non-null `selected` resource must not become a placeholder: retain `data.name` and `data.folderPath` with complete root bindings, regenerate the sidecar with `uip maestro case bindings sync`, and make its `resourceKey` self-consistent with its own defaults, never a copied tenant identity/UUID. Checks 9/11 exempt connector nodes; Check 12 covers resolved connector tasks, event triggers, and `wait-for-connector` rules, which require spliced `caseShape.context` plus Connection/Folder root bindings, not degraded typeId/connectionId-only data. CLI validate on the default profile is insufficient: the closing validate at Phase 3 exit and in Phase 4 is `uip maestro case validate --strict --sdd sdd.md --output json` (`--sdd` implies `--strict` and audits completeness against the SDD; omit it only when no `sdd.md` exists), and a `Valid` without `"Profile": "strict"` does not close the build. Section-end validates in Phases 2–3 use the plain profile (a half-built plan fails strict by design); the Phase 3 exit and every Phase 4 validate carry `--strict --sdd sdd.md`, and no plain-profile result after Phase 3 entry is ever quoted as a close. Run the strict validate alone — never chained with another validate in one command: two envelopes on one stdout get read as the first one. **Version guard:** `--strict`/`--sdd` exist from CLI 1.202. Fall back to plain `validate` only when the response is `invalid_argument` naming `--strict` or `--sdd` as an unknown option (exit 3 alone is insufficient; a strict *failure* is never a reason to drop the flags). On fallback, record `strict profile unavailable on CLI ` in `build-issues.md` and in the completion report, and run Step 12 Checks 1–15 by hand. Repair and recheck mismatches; halt before Phase 4 if they remain. Repeat Check 7 before every `resources refresh`. Refresh before every upload or debug. Every `solution upload` uses `--output-filter "{Status: Status, Action: Action, SolutionId: SolutionId, DesignerUrl: DesignerUrl}"`; print the returned DesignerUrl and say whether `Action` was `Imported` or `Overwritten`. 15. **Handoff contract.** Invoke `uipath-planner`’s Case Design Lane in this conversation, never as a subagent. It owns design, resolution, review, and SDD writing; this skill resumes at solution initialization. User-facing language presents one continuous flow and never mentions the handoff. If unavailable, say so in one line, request `sdd.md` or an approved pasted design, and stop. Cross-product planning remains a plain-text suggestion to the planner. Apply the Rule 15 receipt spot-check before unobserved SDD reads. 16. **Closed task types.** `caseplan.json` task `type` must be exactly one of: `process`, `agent`, `rpa`, `action`, `api-workflow`, `case-management`, `execute-connector-activity`, `wait-for-connector`, `wait-for-timer`. Never use plugin folder or CLI names, `external-agent`, `external-workflow`, `document-extraction`, `flow-process`, `wait-for-event`, or other invented values. The unsupported types remain unsupported. See [references/case-schema.md](references/case-schema.md) and the Plugin Index. 17. **Empty lookup gate.** If the same-session ledger has a user `gateDecision`, execute it without asking again: `resolve-at-build` → placeholder; `create-during-build` → inline create; `pick:` → bind it. A missing decision is a default deferral, not consent; run the full gate. For zero matches, use one batched AskUserQuestion grouped by `(name,type)` with: `Force pull and re-resolve`; `Use placeholders for all`; and, only when creatable resources exist and `registry --local` is supported, `Create missing resources inline`. Create only selected `agent` or `api-workflow` resources, invoking `uipath-agents` or `uipath-api-workflow`; never infer Create from SDD content. Other empty types remain placeholder-only. Selected resources with identical I/O may share one build; differing I/O splits later with the anchor retaining the name, and SDD updates require permission. See [registry-discovery.md § 1c](references/registry-discovery.md#1c--dedup-the-selected-builds-one-resource-per-name-and-type), [Create-on-Missing](references/registry-discovery.md#create-on-missing-build-and-rediscovery), and [§ MUST Confirm](references/registry-discovery.md#must-confirm-before-placeholder-fallback). diff --git a/skills/uipath-maestro-case/references/bindings-and-expressions.md b/skills/uipath-maestro-case/references/bindings-and-expressions.md index f1cdcc29fb..fbf55d9b69 100644 --- a/skills/uipath-maestro-case/references/bindings-and-expressions.md +++ b/skills/uipath-maestro-case/references/bindings-and-expressions.md @@ -21,7 +21,7 @@ When using the literal/expression mode, the `--value` string can start with one | Prefix | Meaning | Example | |--------|---------|---------| -| `=metadata.` | Case metadata field — closed schema, see [case-schema.md § 1](case-schema.md#1-top-level--metadata). NOT for arbitrary SDD "Case Metadata" business fields (e.g. Priority) — those are case variables, use `=vars.` | `=metadata.ExternalId` | +| `=metadata.` | Runtime case metadata — exactly four fields: `FolderKey`, `ProcessKey`, `InstanceId`, `ExternalId`; anything else reads `undefined` at runtime. NOT for arbitrary SDD "Case Metadata" business fields (e.g. Priority) — those are case variables, use `=vars.` | `=metadata.ExternalId` | | `=js:` | Inline JavaScript expression | `=js:new Date().toISOString()` | | `=vars.` | Case-level variable | `=vars.inbox_config` | | `=bindings.` | Resource binding (connection, queue, trigger) | `=bindings.slackConnection` | @@ -96,7 +96,7 @@ A task output is `null` until its task runs — and stays null when its task is The lookup-path resolver has NO `=metadata.` branch — plain `=metadata.X` is NOT resolved at runtime. **Always wrap as `=js:metadata.X`** (or `=js:(metadata.X)` if the sink requires parens). The FE design-time picker may classify `=metadata.X` as "variable" type, but that's a UI hint, not a runtime contract. -`metadata.X` is a **closed field set** — see [case-schema.md § 1](case-schema.md#1-top-level--metadata) for the full list (`caseIdentifier`, `slaRules`, `caseExitRules`, …) plus the platform-only runtime field `metadata.ExternalId`. It is NOT a namespace for arbitrary business data. A field the SDD's "Case Metadata" table lists for human-readability (e.g. `Priority`) is authored as a **case variable**, not a `metadata` key — reference it as `=js:vars.priority`, never `=js:metadata.priority` (which resolves to `undefined`). +`metadata.X` in an expression is a **closed runtime field set** of exactly four: `metadata.FolderKey`, `metadata.ProcessKey`, `metadata.InstanceId`, `metadata.ExternalId`. The disk-schema `metadata` block in [case-schema.md § 1](case-schema.md#1-top-level--metadata) (`caseIdentifier`, `slaRules`, `caseExitRules`, …) is authoring configuration and is not readable from expressions. It is NOT a namespace for arbitrary business data. A field the SDD's "Case Metadata" table lists for human-readability (e.g. `Priority`) is authored as a **case variable**, not a `metadata` key — reference it as `=js:vars.priority`, never `=js:metadata.priority` (which resolves to `undefined`). ### Planner-emit form diff --git a/skills/uipath-maestro-case/references/bindings-v2-sync.md b/skills/uipath-maestro-case/references/bindings-v2-sync.md index 1a16e02736..bc123705f0 100644 --- a/skills/uipath-maestro-case/references/bindings-v2-sync.md +++ b/skills/uipath-maestro-case/references/bindings-v2-sync.md @@ -20,14 +20,17 @@ Individual task / rule plugins write bindings to `caseplan.json` per-target as n ## § Regenerate bindings_v2.json -After writing bindings to top-level `bindings[]`, regenerate `bindings_v2.json`. This file uses a **different format**: `caseplan.json` stores two entries per resource (one per property), `bindings_v2.json` stores one entry per resource with properties nested under `value`. +After writing bindings to top-level `bindings[]`, run: -### Procedure +```bash +uip maestro case bindings sync "//caseplan.json" --output json +``` + +It reads the root `bindings[]`, groups entries by `resourceKey`, and writes `bindings_v2.json` next to the plan (full overwrite). Response `Data`: `BindingsPath`, `ResourceCount`, `ConnectionCount`. **Never author or edit `bindings_v2.json` by hand** — a hand-written sidecar with the wrong field names is invisible to `solution resources refresh` and fails silently at deploy. If the installed CLI has no `bindings sync` command, derive the file from the shapes below as a last resort and say so in the completion report. + +### What the command emits -1. Read top-level `bindings[]` from `caseplan.json` -2. Group bindings by `resourceKey` — entries sharing the same key belong to one resource -3. For each group, produce one resource entry using the shapes below -4. Write the full file (always overwrite, never append) to `//bindings_v2.json` +`caseplan.json` stores two entries per resource (one per property); `bindings_v2.json` stores one entry per resource with properties nested under `value`. Reference only — the shapes are here so Check 7 can be understood, not so they can be typed. ### Non-connector resource entry diff --git a/skills/uipath-maestro-case/references/case-commands.md b/skills/uipath-maestro-case/references/case-commands.md index a7a6d50df2..5fba883e83 100644 --- a/skills/uipath-maestro-case/references/case-commands.md +++ b/skills/uipath-maestro-case/references/case-commands.md @@ -206,7 +206,6 @@ Validate a case management JSON file against case management rules. ```bash uip maestro case validate --strict --sdd sdd.md --output json uip maestro case validate --strict --output json -uip maestro case validate --output json uip maestro case validate --skeleton-v2 --output json uip maestro case validate --skeleton --output json ``` @@ -231,6 +230,34 @@ Always name the selected profile in the Phase 2 summary. A legacy `--skeleton` f --- +## uip maestro case format + +Rewrite `caseplan.json` pretty-printed in place (2-space indentation, one key per line). Run after every write of the plan; it is the only sanctioned reformat (Rule 13). + +```bash +uip maestro case format --output json +``` + +| Flag | Description | +|------|-------------| +| `` | **(required)** Path to the case management JSON file | + +Output: `Data.Changed` — `true` when the file was rewritten, `false` when already formatted (idempotent). An unparseable file is refused and left untouched. Key order is preserved; a number re-renders in shortest form and a duplicate key collapses to its last occurrence, which is JSON round-trip behaviour and not corruption. Same verb family as `maestro flow format` and `maestro bpmn format`. + +--- + +## uip maestro case bindings sync + +Derive `bindings_v2.json` from the plan's root `bindings[]` and write it next to the plan. Never author or edit the sidecar by hand. + +```bash +uip maestro case bindings sync --output json +``` + +Output: `Code: CaseBindingsSync` with `Data.BindingsPath`, `Data.ResourceCount`, `Data.ConnectionCount`. `ResourceCount: 0` is still `Result: Success` — an empty sidecar is a faithful derivation of a plan that binds nothing, so the gate is `validate --strict` (`STRICT_BINDINGS_ABSENT`), not the sync result. See [bindings-v2-sync.md](bindings-v2-sync.md). + +--- + ## uip maestro case debug Debug a Case JSON file via a Studio Web debug session. **Requires `uip login`. Executes the case for real — sends emails, posts messages, calls APIs. Only run on explicit user consent.** diff --git a/skills/uipath-maestro-case/references/connector-trigger-impl.md b/skills/uipath-maestro-case/references/connector-trigger-impl.md index f5d60f1662..2ab2a75fa3 100644 --- a/skills/uipath-maestro-case/references/connector-trigger-impl.md +++ b/skills/uipath-maestro-case/references/connector-trigger-impl.md @@ -103,7 +103,7 @@ After splicing the spec subtree (`context` / `inputs` / `outputs` and their nest ### Step 5 — Mint `var` / `id` / `elementId` on inputs and outputs -Per-plugin: each plugin's `impl-json.md` mints these onto `caseShape.inputs[]` / `caseShape.outputs[]` and writes them to its target shape (task vs trigger node). +Per-plugin: each plugin's `impl-json.md` mints these onto `caseShape.inputs[]` / `caseShape.outputs[]` and writes them to its target shape (task vs trigger node). The target's `data.inputs` is the spliced `CaseShape.Inputs` — every envelope entry the spec returns, each with its `Body` object — never `[]`: a `wait-for-connector` or `execute-connector-activity` task with empty `inputs` passes validate and fails at runtime, and it has been the last miss on three otherwise-complete golden builds. Conventions (shared with activity): - **Inputs:** `var` = `v` + 8 alphanumeric chars (unique across the case — see [global-vars/impl-json.md § Uniqueness Rule](plugins/variables/global-vars/impl-json.md#uniqueness-rule)); `id` = same as `var` diff --git a/skills/uipath-maestro-case/references/connector-trigger-planning.md b/skills/uipath-maestro-case/references/connector-trigger-planning.md index f56ee6a0ca..7d29b34e1e 100644 --- a/skills/uipath-maestro-case/references/connector-trigger-planning.md +++ b/skills/uipath-maestro-case/references/connector-trigger-planning.md @@ -277,7 +277,7 @@ A connector-bound rule's condition element records these on its ledger entry (al ```jsonc { - "rule-type": "wait-for-connector", + "rule-type": "wait-for-connector", // ledger field only; the caseplan rule object is keyed "rule" "type-id": "", "connection-id": "", "connector-key": "", diff --git a/skills/uipath-maestro-case/references/implementation.md b/skills/uipath-maestro-case/references/implementation.md index fbe4fa6638..98266b8ae0 100644 --- a/skills/uipath-maestro-case/references/implementation.md +++ b/skills/uipath-maestro-case/references/implementation.md @@ -136,7 +136,7 @@ After Step 6.2, project the declared In/Out arguments onto every `entry-points.j For each stage heading in SDD Section 2 (primary and `Secondary Stage`), execute per [`plugins/stages/impl-json.md`](plugins/stages/impl-json.md). **Capture the generated `StageId` for every stage** into the name → ID map (and into `id-map.json`) — downstream tasks, conditions, and SLA all reference it. -The SDD's **Required for Case Completion** is planning-only metadata; it is not written into the stage node. It is consumed by case-exit-conditions with `rule-type: required-stages-completed` (Step 10). +The SDD's **Required for Case Completion** is planning-only metadata; it is not written into the stage node. It is consumed by case-exit-conditions with `rule-type: required-stages-completed` (Step 10; `rule-type:` is the planning field — the JSON key is `rule`). ## Step 8 — (RETIRED — no edges) @@ -201,7 +201,7 @@ Placeholder tasks integrate with the rest of the graph: ## Step 9.4 — Regenerate bindings_v2.json (batch) -After all non-connector tasks are written (Step 9), regenerate `bindings_v2.json` once per [bindings-v2-sync.md § Regenerate](bindings-v2-sync.md). This single pass converts all root bindings accumulated during Step 9 — no per-task regeneration needed. +After all non-connector tasks are written (Step 9), run `uip maestro case bindings sync "" --output json` once. It derives `bindings_v2.json` from the root `bindings[]` and writes it next to the plan; never author or edit that file by hand ([bindings-v2-sync.md](bindings-v2-sync.md)). Write each resource task's root `bindings[]` entries and its `data.name` / `data.folderPath` `=bindings.` references in the same Edit: a task without them raises `STRICT_BINDINGS_ABSENT`, and a reference whose entry is not yet present raises `STRICT_BINDINGS_REFERENCE_UNRESOLVED` — adding them one at a time makes every intermediate state an error. ## Step 11 — Write SLA and escalation objects (per-target Edit batch) @@ -220,7 +220,7 @@ One Read of `caseplan.json` at Step 10 entry. Group the SDD's condition rows (St | Task entry | one task | `data.entryConditions` on the task object | | Case exit | root | `metadata.caseExitRules` | -Per-scope composition rules live in the matching plugin's `impl-json.md`. Skip the re-Read between sibling Edits; run one validate at section end. +Per-scope composition rules live in the matching plugin's `impl-json.md`. Every rule object is keyed `"rule": ""` — the planning field `rule-type:` becomes the JSON key `rule`, never `ruleType`. Carry the SDD row's **Display Name** cell verbatim onto the condition's `displayName` (never a boilerplate name like `Completion rule 1` or `Entry from previous stage`): the `--sdd` audit joins rows to conditions by that name for the Exit Type / Interrupting / Marks cells, and a renamed row is silently unaudited there. A rule keyed otherwise fails the default profile with `INVALID_RULE_DISCRIMINATOR` (no `--strict` needed); rename the key, keep its value. Skip the re-Read between sibling Edits; run one validate at section end. For every `wait-for-connector` rule, write the canonical stub `uipath` from [`connector-trigger-impl.md § Placeholder fallback`](connector-trigger-impl.md#placeholder-fallback) in Phase 2 **even when its connector resolved in planning**. Do not call `case spec` and do not add Connection/Folder bindings here. Its `id-map.json` value must include `{kind:"condition", id:"", ruleId:"", scope:"", targetId:""}` so Phase 3 can locate the exact stub without matching display text (`targetId` is the stage ID, task ID, or `root`; task-entry entries also retain `stageId`). Phase 3 Step 10.5 upgrades only `rule.uipath`; a truly unresolved connector keeps the same stub and is reported at completion. @@ -277,7 +277,7 @@ Hold all gathered shapes (per-task `caseShape` + root-level Connection + FolderK Copying `caseShape.outputs` unchanged drops every declared extract: `case spec` returns only the connector's own top-level outputs (`response`, curated fields, `Error`), never the SDD's rows. A `->` row reassigns one of those entries; a `=` row adds a `custom: true` entry that no `caseShape` entry corresponds to. -**Phase C — sync + validate.** Populate IS connection cache per [bindings-v2-sync.md § Populate IS connection cache](bindings-v2-sync.md). Regenerate `bindings_v2.json` once per [bindings-v2-sync.md § Regenerate](bindings-v2-sync.md) — single pass includes non-connector bindings from Step 9 and Connection bindings from this step. Run validate. +**Phase C — sync + validate.** Populate IS connection cache per [bindings-v2-sync.md § Populate IS connection cache](bindings-v2-sync.md). Run `uip maestro case bindings sync "" --output json` once — it picks up the non-connector bindings from Step 9 and the Connection bindings from this step. Run validate. On context-compaction mid-gather: re-Read `caseplan.json`, scan for connector tasks without `data.context` populated, re-run Phase A for those only. @@ -302,7 +302,7 @@ Read `caseplan.json` and scan all four condition scopes for `wait-for-connector` For each matched rule whose connector resolved in planning, run the connector-trigger `case spec --type trigger --input-details` procedure, mint its output IDs/element IDs, and gather its root Connection/Folder bindings. Then Edit **only that rule's `uipath` block**. Preserve the enclosing condition array plus the rule's `id`, `rule`, `conditionExpression`, scope, and placement. Apply declared rule-output bindings after the real outputs exist. -If the connector is `` or `case spec` fails, leave the stub unchanged, log it, and list it in the completion report. After all successful upgrades, populate the IS cache and regenerate `bindings_v2.json` once. Re-scan: every resolved rule must be free of `"placeholder"`; any remaining stub must map to a reported unresolved connector. Full procedure and scope-specific `elementId` rules: [`connector-trigger-impl.md § Target: connector-bound condition rule`](connector-trigger-impl.md#target-connector-bound-condition-rule). +If the connector is `` or `case spec` fails, leave the stub unchanged, log it, and list it in the completion report. After all successful upgrades, populate the IS cache and run `uip maestro case bindings sync "" --output json` once. Re-scan: every resolved rule must be free of `"placeholder"`; any remaining stub must map to a reported unresolved connector. Full procedure and scope-specific `elementId` rules: [`connector-trigger-impl.md § Target: connector-bound condition rule`](connector-trigger-impl.md#target-connector-bound-condition-rule). ## Step 11.5 — Resolve in-expression `vars.$xref` markers (whole-file pass) @@ -312,7 +312,7 @@ Runs after bindings (9.8) and connector-rule upgrades (10.5), when every task / > **Algorithm reference:** the per-check pseudocode + AskUserQuestion prompt templates + skill-response-per-pick details all live in [`plugins/variables/io-binding/impl-json.md § Binding Procedure`](plugins/variables/io-binding/impl-json.md#binding-procedure). This step is the orchestration hook; that doc is the algorithm. When in doubt, follow the impl-json doc. -After value bindings (Step 9.8), connector-rule upgrades (Step 10.5), and marker resolution (Step 11.5), **first run `uip maestro case validate "" --strict --sdd sdd.md --output json`** (unknown-option response → SKILL.md Rule 14 version guard). Its `STRICT_*` codes are the machine-checked half of this pass: `STRICT_XREF_UNRESOLVED` is Check 4, `STRICT_INPUT_UNBOUND` / `STRICT_INPUT_REF_FORM` are Check 1, `STRICT_OUTPUT_*` is Checks 8 and 10, `STRICT_CONNECTOR_*` is Check 12, `TASK_NOT_CONFIGURED` (a warning on every profile: a task with `data: {}`) is Check 9's raw signal, and `--sdd` refines it — `STRICT_SDD_PLACEHOLDER_RESOLVED` (error) when the SDD resolved that resource, `STRICT_SDD_PLACEHOLDER_TASK` (warning) when the SDD left it unresolved, in which case leave the `data: {}` alone, and `STRICT_STAGE_NO_TASKS` means Step 9 never ran for that stage. Repair every reported element with a targeted Edit and re-run until `Status: "Valid"` with `Profile: "strict"`; max 3 rounds, then **AskUserQuestion** with the remaining codes. If the installed CLI rejects `--strict`, run the default profile and say so in the completion report. Then invoke the end-of-Phase-3 validator — Checks 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 — for everything strict does not cover (producer presence, type mismatch, selector integrity, entry-rule presence, sidecar parity). Phase 2 conditions and SLA remain in place throughout. +After value bindings (Step 9.8), connector-rule upgrades (Step 10.5), and marker resolution (Step 11.5), **first run `uip maestro case validate "" --strict --sdd sdd.md --output json`** (unknown-option response → SKILL.md Rule 14 version guard). Its `STRICT_*` codes are the machine-checked half of this pass: `CASE_MGMT_XREF_UNRESOLVED` (an error on every profile, as is `CASE_MGMT_PLANNING_NOTATION` for a `<-`/`->` input value) is Check 4, `STRICT_INPUT_UNBOUND` (empty value, warning) / `STRICT_INPUT_REF_FORM` / `CASE_MGMT_REFERENCE_UNBOUND` (a `vars.` that matches no variable or output — an error on every profile) / `STRICT_SDD_PRODUCER_MISMATCH`, `STRICT_SDD_INPUT_FORM_MISMATCH`, `STRICT_SDD_EXPRESSION_MISMATCH` (the row's expression, with its `$xref` markers resolved, differs from the plan's beyond whitespace/quote style — Rule 6 carries expressions verbatim) `CASE_MGMT_INPUT_BODY_ON_PLAIN_TASK` (an input on any non-connector task carries `body` — only connector envelopes have a `body`; every other task's input value lives in `value`, and an input with no `value` key is `STRICT_SDD_INPUT_EMPTY` under `--sdd` — an error on every profile), `STRICT_SDD_LITERAL_MISMATCH` (an input whose SDD row carries an object literal arrives with fields absent — an error naming the field count and the first missing key; a present field holding a different value is a warning — carry the row's literal whole, never a subset) and `STRICT_SDD_INPUT_EMPTY` (errors under `--sdd`: an input not wired to the producer its SDD row names, wired in a different form, or left empty/absent when the row carries a value — only `--sdd` can tell an unfinished plan from a finished one that omits things, which is why an empty input is merely `STRICT_INPUT_UNBOUND`, a warning, under bare `--strict`) are Check 1, `STRICT_OUTPUT_*` (a missing output type or a self-referencing output), `CASE_MGMT_OUTPUT_ID_MISSING` (an output with no `id`), `CASE_MGMT_OUTPUT_VAR_ID_CASE_MISMATCH` (an output whose `id` and `var` differ only in letter case — a bare output declares one name once, so `AgentExpenseRequest` / `agentExpenseRequest` is a slip, not a rename; a real `->` rename changes the word and is legitimate), `CASE_MGMT_OUTPUT_ID_DUPLICATE` (one output `id` on two tasks — the id is the write target, so the second write lands on the first task's variable; both errors on every profile) and `CASE_MGMT_OUTPUT_VAR_ID_MISMATCH` (an output whose `var` differs from its `id` beyond a collision suffix) are Checks 8 and 10, `STRICT_CONNECTOR_*`, `CASE_MGMT_CONNECTOR_INPUT_FLATTENED`, `CASE_MGMT_CONNECTOR_INPUT_STRINGIFIED`, `CASE_MGMT_CONNECTOR_INPUT_VALUE_NOT_BODY`, `CASE_MGMT_CONNECTOR_INPUT_TARGET_MISMATCH` `CASE_MGMT_CONNECTOR_RESOURCE_KEY_UNRESOLVED` (the context entry `resourceKey` carries the connection key itself, never a binding id or a `=bindings.` reference — the `connection` entry may reference a binding, `resourceKey` may not) and `CASE_MGMT_CONNECTOR_RESOURCE_KEY_MISMATCH` (that `resourceKey` equals the resolved key of the binding its own `connection` entry names — on tasks and on connector rules. The finding says which binding owns the key it found: when the key belongs to another declared connection, the `connection` entry and the `resourceKey` disagree about which connector the context is for — decide from the SDD row which connection this task or rule waits on and make both fields name it; never copy the named binding's key over a `resourceKey` that was right, that repairs the plan into one that is consistently wrong. When the key belongs to nothing, it is the objectName copied into the slot — set it from the cached spec's connection key) (errors on every profile: a connector task's `data.inputs[]` are exactly the spec's envelope entries — `pathParameters`, `queryParameters`, `body`, each with `name` equal to `target` and its fields as an object under `body`, never under `value` and never as a JSON string) are Check 12. **Container placement is the skill's check, not the CLI's:** the plan does not record which container each field belongs to, so populate exactly the envelope entries whose `CaseShape.Inputs[].Body` is non-empty in the cached `case spec` response (`tasks/spec-cache*.json`), copy that `Body` object field-for-field, and leave the other containers `{}` — for Outlook `Get Email List` the spec puts `parentFolderId`, `limit` and `filter` in `body` and leaves `queryParameters` empty; splitting or moving them passes every CLI rule and fails at runtime. `CASE_MGMT_BINDING_KEY_SHARED` (an `agent`/`process`/`rpa` task pair sharing one `resourceKey` — three resources cannot be one binding; two `action` tasks on one app is legitimate reuse) is Check 11, `CASE_MGMT_BINDING_KEY_MISMATCH`, `STRICT_BINDINGS_TASK_UNBOUND` (a task with resolved identity whose `name`/`folderPath` are not `=bindings.` references), `STRICT_BINDINGS_ID_DUPLICATE` (two root binding entries under one id — `=bindings.` resolves to the first match by array order), `CASE_MGMT_BINDING_PAIR_INCOMPLETE` (a non-connector `resourceKey` must be shared by exactly one `name` entry and one `folderPath` entry — never one key per entry), `CASE_MGMT_ACTION_RECIPIENT_SHAPE` (an action task's `recipient` is an object `{Type, Value}`, never a bare string), `CASE_MGMT_RESOURCE_TASK_LITERAL_BINDING` (a resource task's `name`/`folderPath` are `=bindings.` references, never literal strings), `STRICT_SDD_SLA_EXTRA` (more SLA rules on a scope than the SDD declares — one declared SLA with two escalations is one rule with two `escalationRule` entries, not two rules), `CASE_MGMT_SLA_RULE_UNKNOWN_KEY` (an SLA rule's keys are exactly `id, displayName, expression, count, unit, escalationRule` — `duration`/`type` are not keys; the duration is `count` + `unit`), `CASE_MGMT_SLA_ID_DUPLICATE` (one SLA rule `id` on two holders — a stage, a task, or the case level; `sla-status-change` rules key on `slaId`, so a shared id is ambiguous at runtime: mint a fresh `sla_` id per entry, never copy an SLA rule between holders — an error on every profile), `STRICT_SDD_SLA_DURATION_MISMATCH` (`count`/`unit` vs the SDD's Case Metadata `Case-Level SLA` row or a stage's SLA duration) and `STRICT_SDD_BINDING_FOLDER_MISMATCH` (a folderPath default that is not the task's `**Folder Path:**` / `**Deployment Folder:**`, or a folder key GUID where a path belongs) are Check 11, `STRICT_SDD_VARIABLE_EXTRA` (a root case variable the SDD declares neither in Case Variables nor through an Outputs `->`/`=` cell) is Check 1, `STRICT_SDD_CONDITION_EXPRESSION_MISMATCH` (error: a rule's `conditionExpression` differs from its SDD row's IF cell; parentheses count), `STRICT_SDD_CONDITION_MISSING` (a row whose resolved IF expression matches no rule on the target), `STRICT_SDD_CONDITION_RULE_MISMATCH` / `STRICT_SDD_CONDITION_SELECTOR_MISSING` / `STRICT_SDD_CONDITION_SELECTOR_MISMATCH` (WHEN cell vs `rule` and its selector — a `selectedStageId`/`selectedTasksIds` that points at a different stage or task than the cell names), `STRICT_SDD_CONDITION_EXIT_TYPE_MISMATCH` / `STRICT_SDD_CONDITION_FLAG_MISMATCH` (Exit Type, Interrupting, Marks cells) and `STRICT_SDD_CONDITION_EXPRESSION_UNDECLARED` (a `conditionExpression` on a rule whose SDD row's IF cell is `—`: the SDD entered or exited ungated, the plan added a gate) are Check 13 — rows are joined to rules by the WHEN cell (predicate plus target), not by Display Name, because builders renumber boilerplate names; `STRICT_SDD_TIMER_VALUE_MISMATCH` / `STRICT_SDD_TIMER_TYPE_MISMATCH` (a `wait-for-timer` task's `timeDuration` / `timerType` vs the task block's `**Value:**` / `**Timer:**`) are Check 9, `TASK_NOT_CONFIGURED` (a warning on every profile: a task with `data: {}`) is Check 9's raw signal, and `--sdd` refines it — `STRICT_SDD_PLACEHOLDER_RESOLVED` (error) when the SDD resolved that resource, `STRICT_SDD_PLACEHOLDER_TASK` (warning) when the SDD left it unresolved, in which case leave the `data: {}` alone, and `STRICT_STAGE_NO_TASKS` means Step 9 never ran for that stage. Repair every reported element with a targeted Edit and re-run until `Status: "Valid"` with `Profile: "strict"`; max 3 rounds, then **AskUserQuestion** with the remaining codes. If the installed CLI rejects `--strict`, run the default profile and say so in the completion report. Then invoke the end-of-Phase-3 validator — Checks 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 — for everything strict does not cover (producer presence, type mismatch, selector integrity, entry-rule presence, sidecar parity). Phase 2 conditions and SLA remain in place throughout. - **Check 1** — Resolve every `=vars.X` reference against `variables.{inputs, inputOutputs}[].id`. Scan all task input `value` fields, entry/exit condition expressions (stage and task), case-exit and trigger rule expressions, SLA expressions, and `=js:` expressions anywhere they appear. On unresolved → **AskUserQuestion** offering: (a) name the intended variable, (b) remove the reference, (c) continue with best-effort emit (entry logged under Open Items, runtime returns undefined). - **Check 2 — Out-arg producer presence** — For every formal Out-arg in `variables.outputs[]`, verify the producer/Default situation per [`io-binding/impl-json.md` § Check 2](plugins/variables/io-binding/impl-json.md): @@ -323,11 +323,11 @@ After value bindings (Step 9.8), connector-rule upgrades (Step 10.5), and marker - **Check 4 — No surviving `$xref` markers** — Scan every string value in `caseplan.json` for the literal `$xref(`. Step 11.5 resolves all; any survivor means its name-triple or output reference ID failed — the same class of failure as a Check 1 unresolved `=vars.X`, so it gets the same interactive remediation. On unresolved → **AskUserQuestion** (present the outputs that DO exist on the named task as candidates): (a) name the intended source output — skill rewrites the triple, re-resolves, substitutes `vars.`; (b) edit the SDD expression + re-run the Phase 1 dispatcher (when the output genuinely doesn't exist); (c) continue with best-effort emit (token left unsubstituted, entry logged under Open Items; `vars.$xref(...)` throws at runtime until fixed). Detail: [`io-binding/impl-json.md` § Check 4](plugins/variables/io-binding/impl-json.md). - **Check 5 — Resolved-resource I/O completeness** — For each task with a persisted contract in `tasks/registry-resolved.json`, verify every **required** declared input has a bound `value` and every extract output `Field` exists in the resolved output contract. An upstream-output-fed input (`=vars.` / resolved `$xref`) counts as bound with NO §1.5 row. On unbound-required-input or phantom-output-field → **AskUserQuestion**: (a) bind / re-point, (b) ``+review-item / drop row, (c) continue with best-effort emit (entry logged under Open Items; runtime null until fixed). Tasks with no contract (placeholder / ``) are skipped. Detail: [`io-binding/impl-json.md` § Check 5](plugins/variables/io-binding/impl-json.md#check-5--resolved-resource-io-completeness). - **Check 6 — Entry-point schema parity** — Verify every `entry-points.json` entry's `input`/`output` matches the In/Out args projected at Step 6.3 (keys, type mapping, `required`, `file`/`jsonSchema` shapes), plus unique `filePath` fragments and no orphaned `inputs[].elementId`. **Non-interactive:** on mismatch re-run the Step 6.3 refresh once; if still divergent (or a uniqueness/orphan finding) log to `## Open Items for User` and continue. No AskUserQuestion. Algorithm: [`entry-points-sync.md § Check 6`](entry-points-sync.md#check-6--entry-point-schema-parity-step-12-validator). -- **Check 7 — Bindings sidecar parity** — Compare `bindings_v2.json.resources[]` with the complete projection of top-level `caseplan.json.bindings[]` using [`bindings-v2-sync.md`](bindings-v2-sync.md). If they differ — including non-empty bindings with empty resources — regenerate the full sidecar once and re-check. If they still differ, halt before Phase 4. This check is non-interactive. +- **Check 7 — Bindings sidecar current** — Run `uip maestro case bindings sync "" --output json` once more so `bindings_v2.json` reflects the final root `bindings[]`. The sync response alone is not the gate: `ResourceCount: 0` is still `Result: Success` (an empty sidecar is a faithful derivation of a plan that binds nothing). Then run `uip maestro case validate "" --strict --sdd sdd.md --output json`: `STRICT_BINDINGS_ABSENT` means resource tasks exist without root bindings — add the binding entries in `caseplan.json`; `STRICT_BINDINGS_SIDECAR_STALE` means the sidecar disagrees with the plan — the fix is always to re-run `bindings sync`. `ResourceCount` must equal the number of distinct `resourceKey` values in `bindings[]` (and `ConnectionCount` the distinct connection ids); a mismatch means a binding entry is malformed — repair the binding in `caseplan.json`, never the sidecar, and re-run. This check is non-interactive. - **Check 8 — Global generated-output ID uniqueness** — Read the completed `caseplan.json` and build one owner-keyed uniqueness pool from root variables plus every task, trigger, and connector-rule output across all condition scopes. Include unused and schema-generated outputs such as `Error` and `response`. Apply the [global uniqueness rule](plugins/variables/global-vars/impl-json.md#uniqueness-rule): on collision, suffix the later producer, update only that producer's fields and consumers by producer ownership, then re-run the affected binding and marker-resolution steps. Re-read and re-scan the complete pool; halt before Phase 4 if any duplicate generated `id` or `var` remains. `uip maestro case validate` success does not satisfy this check. - **Check 9 — Resolved-resource emission and repair preservation** — Read `tasks/registry-resolved.json`, `sdd.md`, `caseplan.json`, and `bindings_v2.json`. For every registry entry with a non-null `selected`, locate its declared `(stage, task)` in `caseplan.json`. The task MUST exist and MUST NOT have `data: {}`. For non-connector task types, `data.name` and `data.folderPath` MUST each be `=bindings.` references to complete root binding entries (all required fields present) — Check 7 covers their projection into `bindings_v2.json.resources[]`. A selected resource is never eligible for a placeholder fallback. Any whole-file Write used to repair a finding follows the repair-preservation contract in [`case-editing-operations.md § Per-section batch write contract`](case-editing-operations.md#per-section-batch-write-contract--canonical) — a dropped stage, task, root binding, or selected-resource task is a hard failure. Repair only the named task/binding with a targeted Edit, then repeat Checks 7 and 9. Do not enter Phase 4, report completion, or downgrade this finding to an Open Item while it remains unresolved; `uip maestro case validate` success does not satisfy this check. - **Check 10 — Formal-arg slot ID format** — For every entry in `variables.inputs[]` and `variables.outputs[]`, verify `id` matches `^v[A-Za-z0-9]{8}$` per [`global-vars/impl-json.md` § Formal-arg slot ID format](plugins/variables/global-vars/impl-json.md#formal-arg-slot-id-format). The most common violation is copying the human-readable companion name into the formal slot (e.g. `variables.inputs[].id: "applicantName"` instead of `"vK3mNp9Qx"`) — `uip maestro case validate` does not catch this, so it silently produces a case whose BPMN packaging can reject the id. **Non-interactive repair:** mint a replacement `v`+8-chars id, deduplicated against the Check 8 global pool; update the `variables.inputs[]`/`variables.outputs[]` entry's `id` to the new value; for an `inputs[]` (In-arg) entry, also find its bound trigger node's `data.inputs.outputs[]` bridge entry whose `source == "=vars."` and rewrite it to `"=vars."` (skip this sub-step when the bound trigger is a placeholder — no bridge was ever written, per [global-vars/impl-json.md § In argument](plugins/variables/global-vars/impl-json.md#in-argument)). Leave `name`, `var`, and the `inputOutputs[]` companion's `id` unchanged — only the formal slot's `id` (and, for In-args, the bridge's `source`) are rewritten. Re-scan `variables.inputs[]`/`variables.outputs[]` after repair; halt before Phase 4 if any entry still fails the format after one repair pass. -- **Check 11 — resourceKey self-consistency (non-connector tasks)** — For every top-level `bindings[]` pair sharing a `resourceKey` on a non-connector task (`process`, `agent`, `rpa`, `api-workflow`, `case-management`, `action`), verify `resourceKey` is internally consistent with the pair's own `default` fields per [`bindings/impl-json.md` § resourceKey construction](plugins/variables/bindings/impl-json.md#resourcekey-construction--non-connector-tasks): normally `resourceKey == "."`; for an inline-built sibling (agent/api-workflow whose `folderPath` binding `default` is `""`), `resourceKey == "solution_folder."` instead. The most common violation is copying a tenant identity value — the SDD's "Resource Identity" column, a `tasks describe --id` argument, or a registry `entityKey` — directly into `resourceKey` instead of constructing the composite string. `uip maestro case validate` does not catch this: it silently produces an unresolvable process reference that only faults at `case debug`. **Non-interactive repair:** recompute the correct `resourceKey` from the pair's own `default` fields and rewrite both bindings in the shared pair (a pair's two `resourceKey` values must stay identical), then re-run Check 7 to resync `bindings_v2.json`. Re-scan `bindings[]` after repair; halt before Phase 4 if any pair still fails after one repair pass. +- **Check 11 — resourceKey self-consistency (non-connector tasks)** — `CASE_MGMT_BINDING_KEY_MISMATCH` (an error on every profile) is this check's machine half: a root binding pair's `resourceKey` must equal the `folderPath` and `name` its own entries declare; connector pairs (`ConnectionId`/`folderKey`) carry no such pair and are outside it, as is a `solution_folder.` key for a sibling built inside the same solution. For every top-level `bindings[]` pair sharing a `resourceKey` on a non-connector task (`process`, `agent`, `rpa`, `api-workflow`, `case-management`, `action`), verify `resourceKey` is internally consistent with the pair's own `default` fields per [`bindings/impl-json.md` § resourceKey construction](plugins/variables/bindings/impl-json.md#resourcekey-construction--non-connector-tasks): normally `resourceKey == "."`; for an inline-built sibling (agent/api-workflow whose `folderPath` binding `default` is `""`), `resourceKey == "solution_folder."` instead. The most common violation is copying a tenant identity value — the SDD's "Resource Identity" column, a `tasks describe --id` argument, or a registry `entityKey` — directly into `resourceKey` instead of constructing the composite string. `uip maestro case validate` does not catch this: it silently produces an unresolvable process reference that only faults at `case debug`. **Non-interactive repair:** recompute the correct `resourceKey` from the pair's own `default` fields and rewrite both bindings in the shared pair (a pair's two `resourceKey` values must stay identical), then re-run Check 7 to resync `bindings_v2.json`. Re-scan `bindings[]` after repair; halt before Phase 4 if any pair still fails after one repair pass. - **Check 12 — Connector node resolution completeness** — Checks 9 and 11 exempt connector nodes; this check covers them. Read `tasks/registry-resolved.json` and `caseplan.json`. Enumerate every **connector node**: tasks typed `wait-for-connector` / `execute-connector-activity`, the case-level `Intsvc.EventTrigger` node, and every `wait-for-connector` rule across all 4 condition scopes (stage-entry / stage-exit / task-entry, plus case-exit under `metadata.caseExitRules`). For each whose registry entry has a **non-null `selected`** — i.e. the connector resolved in planning — verify its connector block (`data` for a task, `data.inputs` for a trigger node, `uipath` for a rule): 1. `context` is present and non-empty. A block carrying only `serviceType` + `typeId` + `connectionId` is the Phase 2 / `case spec`-failed shape ([connector-trigger/impl-json.md § Graceful degradation](plugins/tasks/connector-trigger/impl-json.md#graceful-degradation)) and is a **failure** here — the spec call succeeded, so the populated `caseShape` must be spliced in. 2. `context[name="connectorKey"].value` equals `selected.connectorKey`, and a `context[name="connection"]` entry exists whose `value` is `=bindings.`. diff --git a/skills/uipath-maestro-case/references/phased-execution.md b/skills/uipath-maestro-case/references/phased-execution.md index eceba11674..e85f018ecc 100644 --- a/skills/uipath-maestro-case/references/phased-execution.md +++ b/skills/uipath-maestro-case/references/phased-execution.md @@ -13,7 +13,7 @@ The skill emits the `27.0.0` top-level shape (`{ id, version, name, metadata, bi | Phase | Behavior | |---|---| | 2 — Prototyping | Informational validate, no halt on errors. | -| 4 — Validate | Authoritative — `uip maestro case validate` accepts the top-level shape. Retry-and-fix on failure, 3-retry cap, hard stop on 3rd failure. | +| 4 — Validate | Authoritative — `uip maestro case validate` accepts the top-level shape. Retry-and-fix on failure while each fix reduces the error count; hard stop only when two consecutive fix→validate rounds leave the count unchanged, or at 12 rounds. | | 5 — Publish | Before the AskUserQuestion, print plain-text warning: `> uip solution upload may reject the top-level shape until the CLI catches up. Failure non-fatal — caseplan.json still valid.` On failure, re-run the upload once without `--output-filter` and dump that unfiltered response to `tasks/upload-response.json`, re-show Phase 5 prompt. | | 6 — Debug | Before the AskUserQuestion, print plain-text warning: `> uip maestro case debug may reject the top-level shape. Failure does not invalidate caseplan.json.` On failure, note `caveat: CLI may reject schema — failure may be schema-related not case-bug-related` in build-issues.md. | | 7 — Publish to Orchestrator | Packs and publishes the whole solution, so the case's top-level shape is carried through unvalidated by this step. On `pack`/`publish` failure, report the CLI error verbatim, note it in build-issues.md, and re-show the Phase 7 prompt. | @@ -185,7 +185,7 @@ End of detail mutations. Run strict validate with the SDD audit: uip maestro case validate "" --strict --sdd sdd.md --output json ``` -`--strict` runs the default profile plus the case-wide and per-task checks that `full` cannot see: a stage with no tasks (`STRICT_STAGE_NO_TASKS`), a surviving `$xref(` marker (`STRICT_XREF_UNRESOLVED`), a `conditionExpression` hoisted onto the condition instead of a rule (`STRICT_CONDITION_EXPR_HOISTED`), a connector task whose `caseShape.context` is incomplete or lacks its Activity Type ID (`STRICT_CONNECTOR_*`), a task with `data: {}` (`TASK_NOT_CONFIGURED`, a warning; with `--sdd` it becomes the error `STRICT_SDD_PLACEHOLDER_RESOLVED` when the SDD resolved that resource), a malformed output shape or formal-argument slot (`STRICT_OUTPUT_*`), and a task input that is unbound or not in `=vars.` form (`STRICT_INPUT_UNBOUND` / `STRICT_INPUT_REF_FORM`). `--sdd ` implies `--strict` and adds the completeness audit: every stage, task, task type, condition row, SLA, trigger and case variable the SDD declares must be present (`STRICT_SDD_*`). Each failure carries its code in `Data.Issues[]` with the element path — fix the named element with a targeted Edit and re-run. `--strict` cannot be combined with `--skeleton` / `--skeleton-v2`. If the installed CLI rejects `--strict` as an unknown option, re-run without it and record `strict validate unavailable` in the completion report; a `Valid` without `--strict` is not evidence the strict checks passed. Both flags exist from CLI 1.202; an `invalid_argument` naming them as unknown options is the only reason to run plain `validate` — apply the SKILL.md Rule 14 version guard and log the fallback. +`--strict` runs the default profile plus the case-wide and per-task checks that `full` cannot see: a stage with no tasks (`STRICT_STAGE_NO_TASKS`), a surviving `$xref(` marker or a `<-`/`->` planning-notation input value or a `vars.` reference that resolves to nothing (`CASE_MGMT_XREF_UNRESOLVED`, `CASE_MGMT_PLANNING_NOTATION`, `CASE_MGMT_REFERENCE_UNBOUND`), a `conditionExpression` hoisted onto the condition instead of a rule (`CASE_MGMT_CONDITION_EXPR_HOISTED`) an output `id` shared by two tasks (`CASE_MGMT_OUTPUT_ID_DUPLICATE`) and an SLA rule `id` shared by two holders (`CASE_MGMT_SLA_ID_DUPLICATE`) — these six fail every profile, not only strict — a connector task whose `caseShape.context` is incomplete or lacks its Activity Type ID (`STRICT_CONNECTOR_*`), a task with `data: {}` (`TASK_NOT_CONFIGURED`, a warning; with `--sdd` it becomes the error `STRICT_SDD_PLACEHOLDER_RESOLVED` when the SDD resolved that resource), a malformed output shape or formal-argument slot (`STRICT_OUTPUT_*`), and a task input that is unbound or not in `=vars.` form (`STRICT_INPUT_UNBOUND` / `STRICT_INPUT_REF_FORM`). `--sdd ` implies `--strict` and adds the completeness audit: every stage, task, task type, condition row, SLA, trigger and case variable the SDD declares must be present (`STRICT_SDD_*`). Each failure carries its code in `Data.Issues[]` with the element path — fix the named element with a targeted Edit and re-run. `--strict` cannot be combined with `--skeleton` / `--skeleton-v2`. If the installed CLI rejects `--strict` as an unknown option, re-run without it and record `strict validate unavailable` in the completion report; a `Valid` without `--strict` is not evidence the strict checks passed. Both flags exist from CLI 1.202; an `invalid_argument` naming them as unknown options is the only reason to run plain `validate` — apply the SKILL.md Rule 14 version guard and log the fallback. On success: `{ Result: "Success", Code: "CaseValidate", Data: { File, Status: "Valid", Profile: "strict" } }` — proceed to the Phase 4 issue-log summary step. @@ -197,7 +197,7 @@ On failure: output lists `[error]` and `[warning]` entries with path and message ### Retry policy -Up to **3 validation retries** per session — each retry MUST be preceded by a fix edit (validate-loop guard above). After 3rd failure, halt and ask user with **AskUserQuestion**: show remaining errors and options: +**Keep repairing while the errors are falling.** Each retry MUST be preceded by a fix edit (validate-loop guard above). Compare the error count of each `--strict --sdd` run to the previous one: while it falls, continue — a complete build has needed six to nine rounds in practice, and stopping at three leaves a plan that is honestly incomplete. Halt only when two consecutive fix→validate rounds leave the error count unchanged (the same findings are being routed around, not repaired), or after 12 rounds. Never drop `--strict --sdd` to make a run pass: a plain-profile `Valid` is not progress. On halt, ask the user with **AskUserQuestion**: show remaining errors and options: - `Retry with fix` — agent attempts fix, re-runs validate (counter does not reset). - `Pause for manual edit` — exit skill mid-flight; user edits `caseplan.json` directly and re-runs skill. diff --git a/skills/uipath-maestro-case/references/placeholder-tasks.md b/skills/uipath-maestro-case/references/placeholder-tasks.md index caee31dab5..821a9860f5 100644 --- a/skills/uipath-maestro-case/references/placeholder-tasks.md +++ b/skills/uipath-maestro-case/references/placeholder-tasks.md @@ -166,7 +166,7 @@ Wire each input per the `io-binding` plugin — see [`plugins/variables/io-bindi ### 6. Re-validate ```bash -uip maestro case validate --output json +uip maestro case validate --strict --sdd sdd.md --output json ``` The "task with no configuration" warning disappears once `data` is populated. diff --git a/tests/tasks/uipath-maestro-case/golden_rebuild/cm_golden_expense/cm_golden_expense.yaml b/tests/tasks/uipath-maestro-case/golden_rebuild/cm_golden_expense/cm_golden_expense.yaml index 5c6fb8b8bc..79aeb62839 100644 --- a/tests/tasks/uipath-maestro-case/golden_rebuild/cm_golden_expense/cm_golden_expense.yaml +++ b/tests/tasks/uipath-maestro-case/golden_rebuild/cm_golden_expense/cm_golden_expense.yaml @@ -81,6 +81,16 @@ success_criteria: weight: 3.0 pass_threshold: 1.0 + - type: run_command + description: "caseplan is complete against the staged sdd.md under validate --strict --sdd — a plain-profile Valid does not close the golden" + command: >- + uip maestro case validate CMGoldenExpense/CMGoldenExpense/caseplan.json + --strict --sdd $(find . -name sdd.md -not -path '*/.venv/*' | head -1) --output json + timeout: 60 + expected_exit_code: 0 + weight: 3.0 + pass_threshold: 1.0 + - type: run_command description: "caseplan preserves the golden topology: 8 stages, secondary rework lane, condition-derived transitions, case exits, 15 tasks across all 9 types, run-once timer, runtime flags, SLA escalation" command: "python3 $TASK_DIR/check_cm_golden_case.py" @@ -120,9 +130,16 @@ success_criteria: weight: 3.0 pass_threshold: 1.0 + - type: command_not_executed + description: "Agent did not edit caseplan.json in place with a script (Rule 13: Write/Edit only; validator findings are repaired by hand, not perl -pi)" + tool_name: "Bash" + command_pattern: '(perl|sed)\s+-\S*i\S*\s[^\n]*caseplan\.json|(python3?|node|ruby)\b[^\n]*(write_text|writeFile|File\.write|open\([^\n]*[''"]w[''"])[^\n]*caseplan\.json' + weight: 2.0 + pass_threshold: 1.0 + - type: command_not_executed description: "Agent did not run case debug or publish (case suspends; publish is out of scope)" tool_name: "Bash" - command_pattern: '(uip|\$UIP)\s+maestro\s+case\s+(debug|publish)\b' + command_pattern: '(^|[;&|]\s*)(uip|\$UIP)\s+maestro\s+case\s+(debug|publish)\b(?![^;&|\n]*--help)' weight: 1.0 pass_threshold: 1.0