Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions skills/uipath-maestro-case/SKILL.md

Large diffs are not rendered by default.

21 changes: 18 additions & 3 deletions skills/uipath-maestro-case/references/connector-trigger-impl.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ A `wait-for-connector` rule inside a condition (`…conditions[].rules[i][j]`) b
### Condition-rule phase contract

- **Phase 2 Step 10:** write every `wait-for-connector` rule with the canonical stub from [§ Placeholder fallback](#placeholder-fallback), even when the connector resolved in planning. The enclosing condition, rule ID, expression, scope, and placement are final at this point. Do not run `case spec`, add connector bindings, or dispatch outputs.
- **Phase 3 Step 10.5:** for a resolved connector, run the procedure below and replace only `rule.uipath`. Preserve all enclosing Phase 2 state. For an unresolved connector or failed `case spec`, keep the stub, log it, and report it as not runnable.
- **Phase 3 Step 10.5:** for a resolved connector, run the procedure below and replace only `rule.uipath`. Preserve all enclosing Phase 2 state. For an unresolved connector or failed `case spec`, keep the stub and log it — then **halt at Check 15** (see [§ Placeholder fallback](#placeholder-fallback)); a surviving stub is a build failure, not a reportable open item.

The same stub therefore has two lifetimes: temporary for a resolved connector awaiting Phase 3, permanent for an unresolved connector. Only the permanent case is an unresolved-resource issue.
The same stub therefore has two lifetimes: temporary for a resolved connector awaiting Phase 3, permanent for an unresolved connector. The permanent case is not merely an unresolved-resource issue — it makes the whole case non-startable, so it is the one unresolved-resource class the skill must NOT ship.

### Procedure (Phase 3)

Expand Down Expand Up @@ -197,7 +197,22 @@ Emit a **stub `uipath`**, never a bare rule. The stub is the minimum shape accep
}
```

This stub is a **deliberate mock**. While temporary, it is simply Phase 2 build state. If it remains after Phase 3, Studio Web flags it and the rule **fails at debug/run**. A remaining stub has no real outputs, Connection/Folder bindings, IS-cache entry, or rule-specific `bindings_v2` resource. Stamp unresolved `tasks.md` entries with Rule 8 markers, log them, and list them in the completion report as **"replace the `placeholder` connector values before debug / publish-to-run."** Upgrade later by re-running the [§ Procedure](#procedure-phase-3).
This stub is a **deliberate mock**, and it is safe ONLY while temporary — as Phase 2 build state awaiting the Phase 3 upgrade.

> **A stub that survives Phase 3 is case-fatal, not rule-local.** Connector-event subscriptions are registered at **case start**, before any stage is entered, so ONE unresolved stub anywhere in the case makes the ENTIRE case non-startable — including stages that never reference it. The failure surfaces as the case's own start event failing (`trigger_1` → `Failed`, `finalStatus: Faulted`, **1 element executed**), which looks nothing like the rule that caused it. `uip maestro case validate` reports `Valid` throughout. Never emit a surviving stub and call the build complete — halt per [implementation.md § Step 12 Check 15](implementation.md#step-12--end-of-phase-3-validator-pass).
>
> Measured on `uip 1.198`, same case, one field changed (2026-08-12):
>
> | Rule `uipath` state | Start event | Elements executed | `validate` |
> |---|---|---|---|
> | `connectorKey`/`operation` = `"placeholder"` | **Failed** | **1** | `Valid` |
> | resolved connector (spliced `caseShape`) | Completed | 25 | `Valid` |
>
> Placeholder **tasks** (`data: {}`, Rule 8) are NOT affected — a case with placeholder tasks starts and runs normally. The fatal shape is specific to connector-bound **condition rules**.
>
> **"Must not ship" is not "must not build."** When planning finds the connector unresolvable, still emit this stub and build the whole case — the halt belongs at Check 15, not at discovery. Aborting early yields no `caseplan.json`, no `tasks.md`, and no `build-issues.md`, so the author gets prose instead of a reviewable artifact, and Check 15's remediation (b) — *remove the rule, ship the working remainder* — never gets offered. Build it, then refuse to ship it.

A remaining stub has no real outputs, Connection/Folder bindings, IS-cache entry, or rule-specific `bindings_v2` resource. Stamp unresolved `tasks.md` entries with Rule 8 markers and log them, but do NOT downgrade the finding to a completion-report note — Check 15 halts the build. Upgrade by re-running the [§ Procedure](#procedure-phase-3).

---

Expand Down
40 changes: 37 additions & 3 deletions skills/uipath-maestro-case/references/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@

## Step 6 — Create the Case project structure

The case file must live inside a solution + project. The case plugin owns project scaffolding **and** the root caseplan write. Solution setup and project registration are the only CLI calls. **Never use `uip maestro case cases add` (or another case mutation command) to create the root caseplan** — execute the T01 direct-JSON recipe so required root metadata such as `caseDirectlyPassTaskOutputs` is emitted. **Never use `uip maestro case init`** — T01 writes the same 5 files, and run outside `<SolutionDir>` (which includes the `solution init && case init` chain) it auto-creates a second solution and forks the working root — see [`case-commands.md` § uip maestro case init](case-commands.md#uip-maestro-case-init).

Check warning on line 91 in skills/uipath-maestro-case/references/implementation.md

View workflow job for this annotation

GitHub Actions / uipath-maestro-case

Possibly stale `uip maestro case cases add` (valid prefix: `maestro case cases`)

1. **Step 6.0 (CLI)** — `uip solution init <SolutionName>` — creates the solution directory + `.uipx`. **Idempotent w.r.t. a Phase 1 Create:** if the Rule 17 **Create** flow already scaffolded the solution in Phase 1 (per [registry-discovery.md § Create-on-Missing → 0 Prerequisite](registry-discovery.md#create-on-missing-build-and-rediscovery)), the `.uipx` already exists — **skip this call iff that exact `<SolutionDir>/<SolutionName>.uipx` is present** (same canonical name + working-root location — [plugins/case/planning.md § Naming](plugins/case/planning.md#project-structure-prerequisites)). Re-running `init` over an existing solution errors, and a differently-named or -located `init` would fork the solution.
2. **T01 (plugin)** — execute [`plugins/case/impl-json.md`](plugins/case/impl-json.md) in full:
Expand Down Expand Up @@ -268,7 +268,7 @@

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 `<UNRESOLVED>` 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 `<UNRESOLVED>` or `case spec` fails, leave the stub unchanged and log it — then let **Check 15** halt the build. Do NOT list it in the completion report and proceed: a surviving stub makes the whole case non-startable ([connector-trigger-impl.md § Placeholder fallback](connector-trigger-impl.md#placeholder-fallback)). After all successful upgrades, populate the IS cache and regenerate `bindings_v2.json` once. Re-scan: every rule must be free of `"placeholder"`. 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)

Expand Down Expand Up @@ -311,7 +311,23 @@

**Non-interactive repair:** re-encode in place — `{"a":1}` → `"{\"a\":1}"`, `5` → `"5"`, `true` → `"true"` (lowercase JSON, not Python `True`), `{}` → `"{}"`. Do not drop the value and do not change the variable's `type`. Re-scan once; halt before Phase 4 if any non-string `default` remains.

**Build-with-best policy:** for any user pick of "continue with best-effort emit" on a Check 1, Check 2, Check 4, Check 5, or Check 13 AskUserQuestion, append a `## Open Items for User` entry to `tasks/build-issues.md` and proceed to Phase 4. Check 14 has no best-effort escape — a deleted default is not a partial result. AskUserQuestion is the surface; build-with-best is the escape. The skill conservatively emits what it has; Phase 4 validate stays green (structural validity is intact); runtime concerns are listed for pre-publish review.
- **Check 15 — No surviving connector-rule placeholder stub (CASE-FATAL, halts)** — Scan every rule across all 4 condition scopes (stage-entry / stage-exit / task-entry, plus case-exit under `metadata.caseExitRules`) for a `wait-for-connector` rule whose `uipath.context` still carries `connectorKey: "placeholder"` / `operation: "placeholder"`. **Every survivor is a build failure**, independent of its registry entry — this check does NOT exempt `selected: null` the way Check 12 does, because an unresolved connector rule is exactly the fatal case.

**This check is the halt point — do not pre-empt it.** An unresolvable connector found during Phase 1 planning or Phase 3 Step 10.5 does NOT abort the run early. Emit the Rule 8 stub, build the full structure, and arrive here. Bailing at discovery leaves no `caseplan.json`, no `tasks.md`, and no `build-issues.md` — the author gets an explanation instead of an artifact — and it silently removes remediation (b) below, *remove the rule and ship the working remainder*, which is normally the only option that unblocks them without waiting on the connector. Build it, then refuse to ship it.

**Why it halts rather than degrading.** Connector-event subscriptions register at **case start**, before any stage is entered. One surviving stub anywhere makes the ENTIRE case non-startable — including when it sits on a non-required secondary stage that nothing routes to. The observable failure is the case's own start event failing (`finalStatus: Faulted`, **1 element executed**), which points nowhere near the offending rule. `uip maestro case validate` reports `Valid` at every step, so this check is the ONLY build-time gate. Measured evidence + the one-field control/variant table: [connector-trigger-impl.md § Placeholder fallback](connector-trigger-impl.md#placeholder-fallback).

**Remediation — AskUserQuestion, no best-effort option.** Name the stage, condition, and rule, then offer exactly three picks: (a) **resolve the connector now** — supply/choose the connector + connection, re-run Step 10.5 for that rule, re-scan; (b) **remove the rule** — delete it and, when it was the condition's only rule, the condition too (if that leaves a stage with no entry condition, remove the stage and every reference to it, then re-run Checks 8 and 13); (c) **abort the build** — leave `caseplan.json` on disk and stop.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No non-interactive path, and this PR ships a task that can't take the interactive one. Check 14 directly above has an explicit Non-interactive repair:; so do 6, 7, 10, 11, 13. Rule 11, Rule 17, registry-discovery.md § 1b, connector-integration.md § 4 and phased-execution.md all define non-interactive fallbacks. This is the only halting check without one.

experiments/default.yaml doesn't grant AskUserQuestion, and context_scale_claim_settlement.yaml in this PR both omits it from allowed_tools and says "Do NOT call AskUserQuestion" — while its own description notes the design nondeterminism that decides whether the withdrawal path becomes a wait-for-connector rule at all. Some runs land here with no defined behavior.

Cheapest fix is naming (c) the non-interactive default: abort, leave caseplan.json, write the BLOCKED: marker. That's already what the marker is for.


**On abort (or any exit while a stub survives), `tasks/build-issues.md` MUST carry a literal line of this exact form**, above `## Open Items for User`:

```
BLOCKED: case is not startable — <N> unresolved wait-for-connector rule(s) still carry the placeholder stub.
```

Write `rule(s)` literally, regardless of N — the marker is matched mechanically, so do not pluralize it. List each offending `(scope, stage, condition, rule id, connector)` beneath it. This line is the machine-readable halt marker: its presence means "an artifact exists but must not be run or published." The completion report MUST reproduce it verbatim and MUST NOT describe the build as complete, successful, or ready. "Continue with best-effort emit" is NOT offered: unlike Checks 1/2/4/5/13, the artifact is not partially working — it cannot start at all, so emitting it produces a case that is 100% dead while reporting success. **Never enter Phase 4, publish, debug, or report completion while any stub survives.**

**Build-with-best policy:** for any user pick of "continue with best-effort emit" on a Check 1, Check 2, Check 4, Check 5, or Check 13 AskUserQuestion, append a `## Open Items for User` entry to `tasks/build-issues.md` and proceed to Phase 4. **Check 14 and Check 15 have no best-effort escape** — a deleted default is not a partial result, and a case that cannot start is not a partial build. AskUserQuestion is the surface; build-with-best is the escape. The skill conservatively emits what it has; Phase 4 validate stays green (structural validity is intact); runtime concerns are listed for pre-publish review.

**Reporting:** at end of Phase 4, count entries in the `## Open Items for User` section of `tasks/build-issues.md` (read the file after writing). If count > 0, the completion report MUST include a literal line of the form:

Expand Down Expand Up @@ -339,7 +355,25 @@

If `tasks/build-issues.md` is absent here, the incremental flush was skipped: reconstruct from on-disk artifacts and stamp the `NOTE:` line per [§ Recovery](plugins/logging/impl-json.md). A build carrying `<UNRESOLVED>` markers or placeholder tasks must not reach Phase 5 with no log.

On Phase 4 success → proceed to Phase 5.
## Step 12.2 — Issue-log completeness gate (Check 16) — PHASE 4 EXIT

Runs immediately after the Step 12.1 summary; gates entry to Phase 5. Unlike Checks 1–15 this cannot live in the Step 12 validator pass — it inspects a file that Step 12.1 is responsible for completing.

**Predicate.** The build **carries unresolved work** when ANY of these hold:

1. `tasks/tasks.md` contains one or more `<UNRESOLVED` markers, OR
2. any task in `caseplan.json` is a placeholder (`data: {}`), OR
3. any `wait-for-connector` rule still carries the placeholder stub (Check 15 abort path).

When the build carries unresolved work, `tasks/build-issues.md` MUST exist and MUST contain at least one issue entry — a header-only or empty file fails this gate. When the build carries none, the file is optional.

**Why this gate exists.** Nothing else in the pipeline reads the issue log. Checks 1–15 inspect `caseplan.json` and its sidecars; the Step 12 **Reporting** clause *presumes* the file exists ("read the file after writing"). The journal is flushed at each section boundary and Step 12.1 recovers it from artifacts if that flush was skipped — but neither step refuses to continue, so a build can still reach Phase 5 with no log, or with a header and no entries, while every other gate passes. This check is the one place that refuses.

**Non-interactive repair.** Do not prompt. Step 12.1 § Recovery already defines the reconstruction and its `NOTE:` stamp — re-run that once, then re-scan. Do not invent a second marker here.

Halt before Phase 5 if the file is still absent or entry-less after one repair pass. `uip maestro case validate` success does not satisfy this gate — a case full of unwired placeholders validates clean.

On success → proceed to Phase 5.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ Case-level event triggers (`type: "uipath.case.trigger"` with `data.inputs.servi

### Connector condition rules

When a `wait-for-connector` rule's connector hasn't resolved at write-time, emit the rule with a **stub `uipath`** (`serviceType` + 2 `"placeholder"` context fields: `connectorKey` + `operation`) — a deliberate mock that validates clean but fails at Studio Web / debug / run until replaced. Full recipe + skip behavior + upgrade path: [connector-trigger-impl.md § Placeholder fallback](connector-trigger-impl.md#placeholder-fallback).
When a `wait-for-connector` rule's connector hasn't resolved at write-time, emit the rule with a **stub `uipath`** (`serviceType` + 2 `"placeholder"` context fields: `connectorKey` + `operation`). Full recipe + skip behavior + upgrade path: [connector-trigger-impl.md § Placeholder fallback](connector-trigger-impl.md#placeholder-fallback).

> **This is the one placeholder the skill may NOT ship.** Unlike a placeholder task, a surviving connector-rule stub is **case-fatal**: subscriptions register at case start, so one stub anywhere makes the entire case non-startable (start event fails, 1 element executed) while `validate` still reports `Valid`. It is legal as Phase 2 build state only. If it survives Phase 3, [Step 12 Check 15](implementation.md#step-12--end-of-phase-3-validator-pass) halts the build — it is never downgraded to an Open Item. **Still build the case**: an unresolvable connector found in planning is not a reason to skip Phase 2. The stub is emitted, the structure lands, and the refusal happens at Check 15 — so the author gets a reviewable artifact plus the option to remove the rule and ship the remainder. Evidence table: [connector-trigger-impl.md § Placeholder fallback](connector-trigger-impl.md#placeholder-fallback).

## `tasks.md` Planning-Entry Shape

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,6 @@ In Phase 2, always write the canonical stub from [connector-trigger-impl.md § C

Confirm `metadata.caseExitRules[]` contains the new object with `id`, non-empty `displayName` (SDD value or `Complete Rule {N}` / `Exit Rule {N}` default keyed to `marksCaseComplete`), `marksCaseComplete` matching the T-entry, and `rules` carrying the expected `rule` value plus any required side field. Verify no `root` key exists at the top level.

For `wait-for-connector`, Phase 2 verification expects the exact two-entry placeholder context plus empty inputs/outputs/bindings. After Phase 3, a resolved rule must have no `"placeholder"` values, inputs/outputs must use `root-<ruleId>`, and ConnectionId + FolderKey root bindings must exist; a remaining stub must map to a reported unresolved connector.
For `wait-for-connector`, Phase 2 verification expects the exact two-entry placeholder context plus empty inputs/outputs/bindings. After Phase 3, EVERY such rule must have no `"placeholder"` values, inputs/outputs must use `root-<ruleId>`, and ConnectionId + FolderKey root bindings must exist. **A stub surviving Phase 3 is case-fatal, not a reportable open item** — it makes the whole case non-startable and halts the build at [implementation.md § Step 12 Check 15](../../../implementation.md#step-12--end-of-phase-3-validator-pass).

<!-- END: impl-json.md -->
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,6 @@ In Phase 2, always write the canonical stub from [connector-trigger-impl.md § C

## Post-Write Verification

Confirm target stage's `data.entryConditions[]` contains the new object with `id`, non-empty `displayName` (SDD value or `Entry Rule {N}` default), `isInterrupting` matching the T-entry, and `rules` carrying the expected `rule` value plus any required side field. For `sla-status-change`, verify `slaId` resolves to an object on the declared SLA target and `isInterrupting` matches the declared response. Check `escalationId` **against the T-entry's status, not for its presence**: an at-risk T-entry must carry one that resolves on that same SLA; a breach T-entry must carry **none**. A missing `escalationId` on a breach rule is correct and complete — do **not** "repair" it by adding one, which silently converts the rule to at-risk ([sla-response-shapes.md § defects `validate` cannot see](../../../sla-response-shapes.md)). For `wait-for-connector`, Phase 2 expects the exact stub; after Phase 3, a resolved rule must have no `"placeholder"` values, use `<stageId>-<ruleId>` on inputs/outputs, and carry root bindings. A remaining stub must map to a reported unresolved connector.
Confirm target stage's `data.entryConditions[]` contains the new object with `id`, non-empty `displayName` (SDD value or `Entry Rule {N}` default), `isInterrupting` matching the T-entry, and `rules` carrying the expected `rule` value plus any required side field. For `sla-status-change`, verify `slaId` resolves to an object on the declared SLA target and `isInterrupting` matches the declared response. Check `escalationId` **against the T-entry's status, not for its presence**: an at-risk T-entry must carry one that resolves on that same SLA; a breach T-entry must carry **none**. A missing `escalationId` on a breach rule is correct and complete — do **not** "repair" it by adding one, which silently converts the rule to at-risk ([sla-response-shapes.md § defects `validate` cannot see](../../../sla-response-shapes.md)). For `wait-for-connector`, Phase 2 expects the exact stub; after Phase 3, EVERY such rule must have no `"placeholder"` values, use `<stageId>-<ruleId>` on inputs/outputs, and carry root bindings. **A stub surviving Phase 3 is case-fatal, not a reportable open item** — it makes the whole case non-startable and halts the build at [implementation.md § Step 12 Check 15](../../../implementation.md#step-12--end-of-phase-3-validator-pass).

<!-- END: impl-json.md -->
Loading
Loading