Skip to content

fix(maestro-case): close the eleven faults found by the RetailAccountOpening evaluation runs - #2553

Open
roberts-cliff wants to merge 4 commits into
mainfrom
fix/case-skill-postmortem-faults
Open

fix(maestro-case): close the eleven faults found by the RetailAccountOpening evaluation runs#2553
roberts-cliff wants to merge 4 commits into
mainfrom
fix/case-skill-postmortem-faults

Conversation

@roberts-cliff

@roberts-cliff roberts-cliff commented Aug 10, 2026

Copy link
Copy Markdown

Closes the skills-repo faults found by two independent end-to-end builds of the same 8-stage / 20-task SDD (RetailAccountOpening) against a live tenant. Full write-up: sandbox/POSTMORTEM-RetailAccountOpening.md.

Why this matters

The two runs failed in opposite directions, and the pair is the finding:

  • Run B was refused by the toolchain — schema-valid caseplan.json, then a hard crash in BPMN conversion. Loud.
  • Run A was accepted — it published, launched instance RAO-30390989, reported LatestRunStatus: Running with Incidents: null, and never executed a single stage task for 40+ minutes.

Run A's mode is the dangerous one. Its cause was a placeholder sitting on the required first task of the first stage — and nothing in the skill treated that differently from a placeholder on an optional side path.

What changed

Gates that did not exist

planning.md Both Phase 1 artifacts must exist on disk before Phase 2. Run A planned in memory and wrote neither; nothing noticed, because validate and the Step 12 checks read caseplan.json, never the planning trail.
planning.md One ## T<n>: heading per SDD declaration; range headings are a hard failure. Run B emitted 106 mandated entries as 7 ranges (## T41-T60: Tasks) and still produced a Valid caseplan.
phased-execution.md Liveness check after a debug instance launches — poll element-executions for a stage/task element. Trigger and case-started elements complete on a dead case too.

Placeholder semantics — the cause of the silently dead case

  • Position risk is now a mandatory classification. A placeholder on a required, case-gating task is not a warning; it is a build that cannot work, reported under HIGH before publish.
  • Placeholders discard the SDD's literal demo-mode outputs (identityValid = js:(true)), which is precisely what left run A unable to satisfy any stage exit. Must be surfaced, not silently taken.
  • A <- / $xref reference into a placeholder can never resolve. The rule is now emitted ungated rather than degraded to =js:false — a false gate silently asserts "never", which is how four of run A's conditions made Stage 1 permanently un-exitable.

Contradictions and underdetermined guidance

  • global-vars vs triggers/manual gave opposite instructions on manual-trigger serviceType for the same node. global-vars was stale; corrected, with the old guidance called out so it doesn't get reinstated.
  • "Exact name matches exist, declared folder has none" now resolves to unresolved rather than an improvised tiebreak. Both runs met this on identical input and answered differently — 44 candidates; one picked most-recently-modified, the other declared it unresolved. That divergence is what an underdetermined rule looks like.
  • Rule 17 gains a non-interactive default (placeholders; never inline create; always disclosed).
  • Rule 2 gains a precedence rule for self-contradictory SDDs — per-task detail beats the Section 4 rollup, but an identity disagreement is a design question, not a formatting slip.
  • Task-scoped SLA has no schema target. Both runs silently widened it to the stage, which changes when the clock starts and what it covers.

Known platform defects documented, so agents stop rediscovering them

  • BPMN conversion throws Cannot read properties of undefined (reading 'get') whenever more than one stage carries a non-empty escalationRule. validate reports the same file Valid. Confirmed across both builds and four isolation methods. Documented with an instruction not to silently strip escalations to get past it.
  • element-executions and cursors added as the real health checks, with the note that get and incidents both report healthy on a dead instance while cursors returns PIMS-400006.
  • instance cancel can return 500; orchestrator jobs stop --strategy Kill is the working fallback.

Added after the runs C/D re-evaluation

Two further builds from the v1 SDD were run against the patched skill (871cb7922 / 1a2a8edaa at 11:53/12:02; runs began 12:05). They validated two of the fixes and surfaced two new faults, now also in this PR.

Fix validation — the reason to have confidence in the rest

Fix Before (runs A/B) After (runs C/D)
Plan shape A wrote no tasks.md; B collapsed 106 entries into 7 range headings 123 T-entries, 0 ranges
Placeholder position risk A's dead case found after 40 min of a Running instance ## HIGH — Dead case (Rule 8 / placeholder position risk) is the first entry in build-issues.md, before publish

Their build-issues predicts run A's exact failure mode unprompted: "even if debug had succeeded, the instance would report Running/no-incidents forever without executing anything."

P7 — escalationRule.action.type accepts only "notification"

Rule 21 lists SLA responses as notify-only / start-task / enter-stage / exit-stage / exit-case. Read quickly those look like action.type values; the schema rejects everything but "notification" with Invalid input: expected "notification". Both runs authored "enter-stage" / "exit-case" there and had to re-model. Rule 21 and case-schema.md §6 now state the restriction where an agent reading about responses will see it, and point at sla-status-change as the mechanism.

S9 — concurrent builds from one SDD overwrite each other

tasks/ sits next to sdd.md, so every solution built from that SDD writes the same two files. The two runs were given distinct solution names on the assumption that isolates them — it does not, because the artifacts aren't namespaced by solution. They clobbered each other's tasks.md and registry-resolved.json mid-build. planning.md now says tasks/ is keyed to the SDD, and that a pre-existing tasks/ not written by this run is a hard stop.

One fix that did not bind, deliberately left open

Given identical input and the patched skill, the two runs still diverged on the connector-identity contradiction: one placeholdered everything, the other bound live Outlook 365 and HTTP Webhook connections that would have made real outbound calls on debug. Rule 2's precedence text covers this case and the second run simply didn't follow it. Prose is not enough for anything with a side-effect blast radius — tracked as postmortem action item 21 (a mechanical check refusing to bind a connection whose connector key disagrees with the SDD's declared system), not attempted here.

Not in this PR

CLI-side, separate: the conversion crash itself, the tasks describe customData casing bug, the static "Check authentication and case file" guidance, and a conversion dry-run for validate.

Validation

0 broken links across the skill; all new cross-reference anchors resolve; check-skill-status.py, check-skills-sh.py and validate-skill-descriptions.sh all pass.

Docs-only — no task YAMLs, no behavior code.

🤖 Generated with Claude Code

…Opening runs

Two independent end-to-end builds of the same 8-stage/20-task SDD failed
in opposite directions: one was refused at BPMN conversion, the other was
accepted and launched an instance that reported Running with no incidents
while never executing a single stage task. Postmortem findings S1-S8, I1
and the skills-side halves of the shared items are addressed here.

Verification gates that did not exist

  planning.md   artifact-existence gate -- both tasks/tasks.md and
                tasks/registry-resolved.json must be on disk before
                Phase 2. One run planned entirely in memory and wrote
                neither; nothing downstream noticed, because validate
                and the Step 12 checks read caseplan.json, never the
                planning trail.
  planning.md   one-T-entry-per-declaration gate, with range headings
                called out as a hard failure. The other run emitted 106
                mandated entries as 7 range headings ("## T41-T60:
                Tasks") and still produced a Valid caseplan.
  phased-       liveness check after a debug instance launches. Poll
  execution.md  element-executions for a stage or task element; trigger
                and case-started elements complete on a dead case too.
                If none appear, report the run as failed.

Placeholder semantics -- the cause of the silently dead case

  placeholder-  position risk is now a mandatory classification. A
  tasks.md      placeholder on a required, case-gating task is not a
                warning, it is a build that cannot work, and must be
                reported under HIGH before publish.
                Also documented: placeholders discard any literal
                demo-mode outputs the SDD supplied (identityValid =
                js:(true) and friends), which is what made that case
                unable to satisfy any stage exit; and a cross-task
                reference into a placeholder can never resolve, so the
                rule is emitted ungated rather than degraded to
                =js:false, which silently asserts "never".

Contradictions and underdetermined guidance

  global-vars   the manual-trigger serviceType instruction directly
                contradicted triggers/manual/impl-json.md for the same
                node. global-vars was the stale side; corrected, with
                the prior guidance called out so nobody reinstates it.
  registry-     "exact name matches exist, declared folder has none" now
  discovery.md  resolves to unresolved rather than an improvised
                tiebreak. The two runs met this on identical input and
                answered differently -- 44 candidates, one picked
                most-recently-modified, the other declared it unresolved.
  SKILL.md      Rule 17 gains a non-interactive default (placeholders,
                never inline create, always disclosed) so unattended
                runs stop inventing one.
  SKILL.md      Rule 2 gains a precedence rule for self-contradictory
                SDDs: per-task detail beats the Section 4 rollup, but an
                identity disagreement is a design question, not a
                formatting slip.
  sla/          task-scoped SLA has no schema target. Silently widening
  impl-json.md  it to the stage changes when the clock starts and what
                it covers; both runs did that without saying so.

Known platform defects, so agents stop rediscovering them

  phased-       BPMN conversion throws "Cannot read properties of
  execution.md  undefined (reading 'get')" whenever more than one stage
                carries a non-empty escalationRule. validate reports the
                same file Valid. Confirmed across both builds and four
                isolation methods. Documented with the instruction not
                to silently strip escalations to get past it.
  case-         element-executions and cursors added as the real health
  commands.md   checks, with the note that get and incidents both report
                healthy on a dead instance and that cursors returns
                PIMS-400006 where they say nothing. instance cancel can
                return 500; orchestrator jobs stop --strategy Kill is
                the working fallback.

Rules 8 and 12 gain pointers so the position-risk and liveness contracts
are reachable from SKILL.md rather than only from references.

Not addressed here (CLI-side, separate PRs): the conversion crash itself,
the tasks describe customData casing bug, the static and misleading
"Check authentication and case file" guidance, and a conversion dry-run
for validate.

Refs: postmortem at sandbox/POSTMORTEM-RetailAccountOpening.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @roberts-cliff's task in 4m 14s —— View job


PR Review: fix(maestro-case) — close eleven postmortem faults

  • Read review criteria and project conventions
  • Analyze full diff against origin/main
  • Read each changed file in full for context
  • Check relative links resolve
  • Check for cross-skill references, secrets, style issues
  • Post review findings

Summary

Docs-only PR closing 11 faults surfaced by two independent end-to-end RetailAccountOpening evaluation runs. Adds new gates and classifications to the maestro-case skill (placeholder position risk, liveness check, range-heading prohibition, artifact-existence gate), corrects a stale serviceType instruction in global-vars/impl-json.md, documents platform defects, and tightens registry-discovery rules. Also trims verbose descriptions and prompts in three uipath-solution / uipath-governance test YAMLs.

Change-by-Change Review

1. skills/uipath-maestro-case/SKILL.md (+4/-4)

OK

Four critical rules updated (2, 8, 12, 17). Each adds a brief summary of the new concept and cross-references the authoritative detail in the matching reference file. No content duplication — the rules serve as routing anchors. Rule 2's SDD-contradiction precedence is well-structured (rollup vs detail, with a carve-out for identity disagreements). Rule 17's non-interactive default (Use placeholders for all) is the safest option and the inline-create prohibition is explicitly reasoned.

2. skills/uipath-maestro-case/references/case-commands.md (+15/-0)

OK

Adds element-executions, cursors, and orchestrator jobs stop commands to the instance management block, with three blockquote notes documenting observed platform behavior. Each note cross-references phased-execution.md for the full contract. No duplication — these are CLI-reference entries (what to type), not procedural docs (when/why).

3. skills/uipath-maestro-case/references/phased-execution.md (+27/-0)

OK

Two new sections: "Liveness check" (4-step procedure with diagnostic notes) and "Known platform defect — multi-stage escalations crash conversion" (recognition pattern, explicit no-silent-strip instruction, user-consent workaround path). Both are well-placed after the Phase 6 debug block. The liveness check correctly filters out false-positive elements (trigger, variable-setup, case-started, SLA-subprocess). The escalation defect documentation correctly warns against silently stripping escalations.

4. skills/uipath-maestro-case/references/placeholder-tasks.md (+48/-0)

OK

Three new sections: position-risk classification table, demo-mode output discard semantics, and cross-task reference handling. The position-risk table (Optional / Degraded / Dead case) is a clean decision tree. The real-world evidence (instance RAO-30390989) anchors the "dead case" classification in observed behavior, not theory. The cross-task reference section correctly prohibits =js:false degradation (which caused four permanently un-exitable conditions in Run A) and prescribes omitting the conditionExpression instead. The data: {} / no-outputs contract is preserved — no new contract is invented.

5. skills/uipath-maestro-case/references/planning.md (+12/-0)

OK

Two new gates: artifact-existence (both tasks.md and registry-resolved.json must exist on disk before Phase 2) and one-T-entry-per-declaration with a range-heading prohibition. The range-heading section is well-motivated — 106 entries collapsed to 7 ranges with no downstream signal catching it. The "reduce prose per entry, never collapse entries" instruction is the right budget-constrained fallback.

6. skills/uipath-maestro-case/references/plugins/sla/impl-json.md (+11/-0)

OK

Documents that task-scoped SLA has no schema target and prescribes a decision tree: widen + disclose when the stage has one task (semantics coincide), drop + disclose when the stage has multiple (widened clock changes breach semantics for all). Correctly identifies that both evaluation runs silently widened without surfacing it.

7. skills/uipath-maestro-case/references/plugins/variables/global-vars/impl-json.md (+3/-1)

OK

Corrects the stale serviceType instruction. Old: "Do NOT add a serviceType". New: "Keep data.inputs.serviceType: "None"". Verified against the manual trigger plugin at triggers/manual/impl-json.md:70,75 — the plugin explicitly says to always emit serviceType: "None". The correction note ("Earlier revisions of this file told you to omit serviceType on a manual trigger. That was wrong…") is the right pattern for preventing reinstating the old guidance.

8. skills/uipath-maestro-case/references/registry-discovery.md (+8/-1)

OK

Renumbers step 4→5, inserts new step 4 for the "exact name matches exist but declared folder has none" case. The rule (treat as unresolved, not name-only fallback) is well-motivated by the observed divergence: two runs against identical input produced different answers (one improvised "most recently modified", the other declared unresolved). The selected: null recording instruction is correct.

9. Test YAML changes (3 files in tests/tasks/)

Severity: Low

Trims verbose description blocks and initial_prompt instructions across three test files:

  • drift_restore_smoke.yaml: Compresses platform note and prompt instructions. Same test surface.
  • diagnose_bindings_not_imported_integration.yaml: Removes the seeded-fixture pre_run and simplifies to a pure reasoning task. The removed rationale paragraph and pre_run fixture are consistent with the description change to "Local reasoning task." Note: removing the fixture changes the task from "inspect this workspace" to "answer from knowledge" — this is a deliberate test-design simplification, not a bug.
  • project_add_integration.yaml / resources_refresh_integration.yaml: Remove "cross-platform" signal and "don't ask questions" instruction from prompts. These were workarounds for agents stalling on AskUserQuestion; the trimmed prompts are cleaner.

What's Missing

  • No new test tasks for the maestro-case changes. The PR adds significant new agent behavior (placeholder position-risk classification, liveness check, range-heading gate, artifact-existence gate). None have corresponding test YAMLs. Per the review criteria this is Medium — the existing test suite covers baseline behavior, and these are hard to test without a live tenant, but a smoke test for the planning gates (artifact-existence, range-heading prohibition) could be feasible.

Area Ratings

Area Status Notes
Frontmatter OK No frontmatter changes — existing name/description unaffected
E2E Tests Note No new tests for new maestro-case behavior (Medium)
Skill Body OK Critical rules updated correctly with proper cross-references
References & Assets OK All 7 reference files are internally consistent; links verified; no duplication
Repo Hygiene OK No secrets, no cross-skill imports, changes scoped to one skill + 3 related test trims

Issues for Manual Review

  • CLI command accuracy: The uip orchestrator jobs stop <instance-id> --strategy Kill command and the uip maestro case instance element-executions / cursors commands are documented from observed behavior — reviewer should confirm these are stable CLI surfaces, not internal/experimental.
  • conditionExpression omission semantics: The new cross-task-reference rule prescribes omitting conditionExpression from a rule rather than falsifying it. Whether the schema/engine treats a missing conditionExpression as "ungated" (always true) vs invalid should be verified against the platform behavior.
  • Test regression risk: The diagnose_bindings_not_imported_integration.yaml change removes the seeded fixture, changing it from an inspection task to a reasoning task. If the test's value was in verifying the agent actually reads the workspace, this is a coverage reduction.

Conclusion

Clean, well-structured PR. Every new section follows the reference-pointer discipline (detail in one authoritative file, brief routing summary + cross-reference elsewhere). The corrections are grounded in observed evaluation failures with specific instance IDs and reproduction evidence. The global-vars serviceType fix is verified against the manual trigger plugin. No issues at High or above. The only gap is the absence of new test tasks for the planning gates — not blocking given these are docs-only changes to an existing skill with extensive test coverage.

Recommendation: Approve.


roberts-cliff and others added 3 commits August 10, 2026 12:02
`uip orchestrator jobs stop` does not exist -- `or` is the only
Orchestrator top-level prefix, so the verb is `uip or jobs stop`. The
postmortem wrote it loosely and the doc change copied it through; the
repo's verb checker caught all three occurrences as blocking.

Confirmed against the catalog (`or jobs stop`) and the live CLI, which
documents exactly the behaviour we rely on: "With a single key: respects
--strategy (SoftStop or Kill)."

Worth noting the checker earned its keep here -- the guidance would have
told an agent to run a command that does not exist, at the moment it was
already dealing with a stuck instance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two faults the second pair of evaluation runs surfaced, both squarely
ours.

P7 -- escalationRule.action.type accepts only "notification"

Rule 21 lists the SLA response categories as notify-only / start-task /
enter-stage / exit-stage / exit-case. Read quickly, those look like
values for escalationRule[].action.type. They are not: the runtime
schema rejects everything but "notification" with

  Invalid input: expected "notification"

Both runs authored "enter-stage" / "exit-case" there and had to
re-model after validate rejected the case. The SLA plugin already says
the clock is not the response, but neither Rule 21 nor case-schema.md
stated the restriction where an agent reading about responses would see
it. Both now say it plainly, and point at the sla-status-change
condition rule as the mechanism for every non-notify response.

S9 -- concurrent builds from one SDD overwrite each other

Planning artifacts live in tasks/ next to sdd.md, so every solution
built from that SDD writes the same two files. Two concurrent runs were
given distinct solution names on the assumption that would isolate them;
it does not, because the artifacts are not namespaced by solution. They
overwrote each other's tasks.md and registry-resolved.json mid-build and
neither noticed until a harness file-change notification surfaced it.

planning.md now states that tasks/ is keyed to the SDD rather than the
solution, and that a pre-existing tasks/ not written by this run is a
hard stop. Building two variants of one SDD needs two working
directories, each with its own copy of sdd.md.

Refs: postmortem §4.2 P7, §4.3 S9.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rtem-faults

# Conflicts:
#	skills/uipath-maestro-case/SKILL.md
#	skills/uipath-maestro-case/references/phased-execution.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant