# Runtime Verification Guide

Step 6 of the workflow, after the build passed. A run of the migrated project, performed only after the user says yes, shows whether the output runs and attributes a failure to the migration or to something else. When the failure is migration-related, the fix and rerun loop below repairs it one fix at a time, each behind one yes/no. The build verification guide proves the output compiles; this guide is the only runtime evidence the skill produces.

## Offer

Offer the run when all of these hold:

- the build passed;
- `uip` is available;
- the routed packages are UIA only: a project routed to the Mail, GSuite or Microsoft.Activities guide gets no offer;
- `project.json` has `"outputType": "Process"`; a library has nothing to run.

Ask one yes/no question: run `<MAIN>` in `<OUTPUT_DIR>` once now, against the real applications on this machine? Default no. Do not propose durations or time limits. When `<MAIN>` declares `In` arguments without defaults, ask for their values in the same question or skip the run. When the user already asked for the run earlier in the task, that is the yes (SKILL.md Rule 11): do not ask again, but still ask for missing `In` argument values.

| Placeholder | Meaning |
|---|---|
| `<MAIN>` | The `main` entry of `project.json` |
| `<RUN_LOG>` | `<PROJECT_DIR>/.upgrade/run-latest.log`, or `<MIGRATED_DIR>/.upgrade/run-latest.log` in fix-only mode |
| `<LEDGER>` | The summarizer's `--json` output for the upgrade SARIF: `uia.migratedItems` lists every activity the tool rewrote, `uia.notMigrated` and `uia.partial` those it left classic |

## Starting state

The run drives real applications, and a rerun must start from the state the first run started from.

1. **Before the first run**, take the baseline:
   1. Take a top-level snapshot with the UIA package's Window Baseline procedure (§ Window Baseline of the package guide `ui-automation-guide.md`).
   2. The guide ships inside the package: always at `%USERPROFILE%\.nuget\packages\uipath.uiautomation.activities\<version>\content\docs\` once Step 5 restored the project, `<version>` being the exact `UiPath.UIAutomation.Activities` version in `<OUTPUT_DIR>/project.json`; and at `<OUTPUT_DIR>/.local/docs/packages/UiPath.UIAutomation.Activities/` once Studio or a run has materialized it there. Neither folder's presence decides whether the snapshot works; only the snapshot command's own answer does. When neither folder holds the guide, or the guide has no Window Baseline section, there is no snapshot: proceed exactly as item 4 says.
   3. Its snapshot CLI is a `uip rpa` command: run it with the `env -u UIPATH_STUDIO_PID` prefix and `--project-dir "<OUTPUT_DIR>"` like every other one, with a folder under the scratchpad for its artifacts, and without `--output`, which it rejects.
   4. The snapshot CLI needs the UIAutomation package's CLI support. When it answers that it requires the `UiPath.UIAutomation.CLI` package, as 25.10 targets do, there is no snapshot: note the applications and URLs the project's XAML names instead, continue, and use the "Without a snapshot" branch of item 2 from then on. `unknown command 'snapshot'` is a different answer: the `uia` verbs come from the package and exist only when `--project-dir` is given, so the command, its `--help` included, ran without it; rerun it with `--project-dir "<OUTPUT_DIR>"`. Only the answer naming `UiPath.UIAutomation.CLI` means there is no snapshot.
   5. With a snapshot, the baseline is the titles, processes and URLs in the snapshot file, never the refs, which every capture re-mints. Keep the baseline for the whole loop.
   6. Never infer window state from `Get-Process` or any other process listing: they report processes, not windows, and hide every window but one of a browser.
2. **Before every rerun**, restore the starting state. The project's applications are what the XAML names in any activity, whatever the activity type: every `app=` attribute in a selector, every executable name in a property, every URL in a property; the run log's `Audit: Using … App` lines confirm which of them the run drove.

   **With a snapshot:**
   1. Capture again and diff against the baseline, following the same section's "Diff and close leaked windows" part.
   2. A new window or a new browser tab whose title, process or URL the project's XAML in `<OUTPUT_DIR>` accounts for is a leftover of the failed run: close it by its ref from the latest snapshot: a new window by its window ref; a new tab inside a baseline window by its tab ref, so a leaked tab inside the user's own browser window goes without touching that window.
   3. Windows that carry the project's name but are not the project's applications are never leftovers: the user's Studio, process `uipath.studio.exe` or `uipath.studio.project.exe`, titled `<project name> - UiPath Studio` or `<project name>`, and the UI Automation driver windows of `uipath.uiautomation.exe` that every run and snapshot spawns. Never close them, never list them. The headless host the skill runs in has no top-level window.
   4. A new window or tab that no XAML property accounts for, for example one started by a script or command activity, is listed and left to the user.
   5. Any other new window is the user's, opened while the skill worked: never close it, never mention it.

   **Without a snapshot:**
   1. Before every rerun tell the user which applications and URLs the failed run drove, taken from the run log's `Audit: Using … App` lines, and ask them to close what it left open before confirming the rerun.
   2. The skill closes nothing itself and never lists processes.
3. **What the skill cannot restore.** A baseline window that is gone, or an application the project attaches to that is not running or not signed in, is something the skill cannot restore. Stop, tell the user what is missing, and rerun only after the user confirms it is back.

## Run

```bash
env -u UIPATH_STUDIO_PID uip rpa run --file-path "<MAIN>" --project-dir "<OUTPUT_DIR>" --output json > "<PROJECT_DIR>/.upgrade/run-latest.log" 2>&1
```

The redirect target is `<RUN_LOG>`: `<PROJECT_DIR>/.upgrade/run-latest.log`, the source project's `.upgrade` folder, never a folder under `<OUTPUT_DIR>`; in fix-only mode it is `<MIGRATED_DIR>/.upgrade/run-latest.log`. Every run, reruns included, writes to that same file and overwrites it: never a numbered copy, never a second file. The previous run's verdict is already in the report and in the fix's backup folder.

1. Every `uip rpa` command in this skill runs with the host Studio pin cleared, `env -u UIPATH_STUDIO_PID`, as the blocks show; here it matters most. Inside Studio's integrated terminal that variable makes the rpa tool run the workflow in the user's Studio and open `<OUTPUT_DIR>` there first; a project other than the one already open replaces it and ends the terminal session. Cleared, the run goes to the headless Studio.
2. Never pass `--skip-build`. It assumes the headless Studio instance built the project itself; `uip rpa build` runs outside that instance, so the first run fails with "The Main.xaml workflow cannot be found".
3. Pass `--project-dir` with the same absolute spelling on every command in this guide. The headless Studio keys its instance on that string; another spelling starts a second instance.
4. The command blocks until the workflow completes or faults, however long that takes, and streams the workflow's log into `<RUN_LOG>` as `[Information] <message>` lines before the verdict JSON.
   - Run it in the background when the host supports that and wait for it to finish.
   - Without background execution, run it in the foreground with the longest timeout the host allows; a client killed by that timeout leaves the execution running (rule 7).
5. Progress while waiting:
   - `env -u UIPATH_STUDIO_PID uip rpa instances list --output json` lists the instance whose `ProjectDirectory` is `<OUTPUT_DIR>` (compare case-insensitively) with `ExecutionStatus: "ToolExecution"` while the run is in flight and `"Available"` once it ended.
   - The tail of `<RUN_LOG>` names the last logged step.
   - Wait for the host's completion notification when it provides one; otherwise check the tail of `<RUN_LOG>` and `instances list` no more than once a minute, and never loop on `sleep`.
   - Never probe with `debug break` or `debug continue`: both return `Success` with or without a session, and both block for the length of the current activity.
6. Never run this check with `debug start`. The debugger stops at every exception an activity throws, whether or not a Try Catch handles it, and holds the session, so a stopped session says nothing about whether the workflow fails. If a log ever shows `Suspended on exception`, cancel with rule 7 at once; that run is void and is repeated with `run`.
7. Stop the run only when the user asks or when the client was killed. Killing the client does not stop the execution; cancel it:

   ```bash
   env -u UIPATH_STUDIO_PID uip rpa execution cancel --project-dir "<OUTPUT_DIR>" --output json
   ```

   "Execution stop requested." means it was still running; "No Helm instance with a running execution found." means it had ended. Run this cancel once after every run whatever the outcome; it is harmless when nothing runs.
8. Repairs happen only through the fix and rerun loop below, one fix per run, each behind one yes/no. Outside the loop, do not edit the output, do not rework a selector, do not rerun.
9. Never run or validate the source project `<PROJECT_DIR>` through the headless Studio during the check or the loop. The migrator keeps the source's `projectId` on the output, and the host has been seen validating the migrated XAML when pointed at the source folder. The classic project's behavior is established by the user's own run of it, not by the skill.

## Verdict

Read `Data` by key presence; its shape varies with the CLI build. The outer `Result: "Success"` reports the CLI call, not the workflow. The duration is the `execution ended in: <hh:mm:ss>` log line.

| Outcome | Signal | Next |
|---|---|---|
| Passed | No errors (`HasErrors: false` or `errors: []`) and no exception (`ErrorMessage: null` or `output: "Session ended"`) | Report |
| Passed, not clean | The log reports that the healing agent recovered an activity: that activity's target did not resolve as migrated | The activity goes under Needs attention by name |
| Failed | `HasErrors: true` with an `ErrorMessage` whose lines `Source: <activity display name>`, `Message: <text>` and `Exception Type: <type>` name the failure; newer builds carry the same in `errors[]` with `output: "Execution aborted…"`. The log also names it, as `'<activity>' execution failed with exception <type>` | Attribution |
| Not a verdict: build failure | Compile errors at start: `Compile` log entries at `Error` level, or `errorName: "ERROR"` | Back to the fix loop of the build verification guide |
| Not a verdict: cancelled or killed | A run cancelled by the user or killed before any of the above | Yields only the last logged step |

## Attribution

For a failed run, take the failing activity and its file and look them up; the first matching row wins:

| Where it is | Verdict | What the report says |
|---|---|---|
| It carries, itself or through an ancestor, a `by uipath-activity-migrator` annotation (SKILL.md Rule 12), whatever the ledger says | migration-related, this skill's to diagnose | The Remediated or Verified healthy line with the exception; a requested treatment realised wrongly is redone as the loop's intro says |
| `uia.migratedItems` | migration-related | Selector carries the `.ToStringWithDelimiter()` marker: the post-migration fix guide is the fix. Otherwise quote the activity's `[PostMigration Action Required]` annotation, or the nearest ancestor's, with the exception |
| `uia.notMigrated` or `uia.partial` | not migration-related | Left classic by the tool; the exception is pre-existing or environmental |
| Neither, or no failing activity named | not migration-related | The exception as is |

- Several activities with that display name in the file: list them and say the run does not tell them apart.
- In fix-only mode there is no `<LEDGER>`: a failure at an activity that carries, itself or through an ancestor, a marker, a `[PostMigration Action Required]` annotation or a `by uipath-activity-migrator` annotation is migration-related; anything else is reported without attribution.
- When the loop ends without a pass, applications the last run opened may still be open; say so.

## Fix and rerun loop

The loop runs for a failure attributed to the migration and, before any failure, for a treatment the plan's go named (SKILL.md Rule 13, row (a) below); anything else is reported and the loop does not start. Applied before the first run, a requested treatment stops after step 3's validate and build: the first run is Step 6's check, behind its own yes or an earlier explicit request (Rule 11). A run that fails at a construct that edit produced refutes the realization, not the treatment: restore its backup and redo it as edit 1, once, behind one yes/no that names what changes, never a next fix on top of it; when the redone edit fails there again, restore the backup and report the requested treatment as a needs-attention item. `<N>` numbers the edits applied to the output, starting at 1; it counts confirmations, not constructs: everything one go or one yes approves is one edit.

1. Before proposing any fix:
   1. **Evidence.** Read the failing activity and its enclosing constructs in both projects: the classic form in `<PROJECT_DIR>` says what the workflow intended, its configuration and what the flow does next; the migrated form in `<OUTPUT_DIR>` and the tool's annotation say what the migration changed. The difference between the two is part of the evidence for every fix, alongside the exception and the annotation, and the fix restores the classic intent with modern constructs, never by reintroducing the classic activity.
   2. **Grounding.** Take the first source that applies:

      | Signal | Ground the fix on |
      |---|---|
      | (a) The plan's go named a treatment for the failing activity or one of its ancestors, or, before any run, for a construct of the output (SKILL.md Rule 13) | That treatment, with the name the run supplied when one was needed; source `requested`. The go is its yes, so step 2 is skipped; it is edit 1 and does not count toward step 5 |
      | (b) The failing activity's selector carries the marker | The post-migration fix guide's procedure, its scan, classification and confirmation included |
      | (c) A `[PostMigration Action Required]` annotation on the failing activity or on one of its ancestors names an action, such as moving the child outside the generated card or setting the target's Window selector | That action |
      | (d) Nothing grounded applies | One hypothesis formed from the evidence, which is the exception type and message, the tool's warning on the construct, and the difference between the classic activity in `<PROJECT_DIR>` and its migrated form in `<OUTPUT_DIR>`. A hypothesis is labelled as such in the question and in the report |

   3. **Limits.** Every fix, grounded or not, is a minimal targeted edit; it never invents or rewrites a selector value, never touches a marker selector, and never changes a package version. An edit that adds an activity, replaces one activity type with another, or changes the control flow, meaning which activities execute on a path or which construct's body or branch holds them, is authoring, not a fix, whatever grounds it; removing a wrapper and hoisting its children unchanged and in order, dropping an attribute, or retyping a Catch is a fix. When the user asks for one and the RPA authoring skill is available in this plugin, take the step 3 backup first, then spawn a subagent that runs that skill on the edit and returns the changed file, then continue with the same validate, build and rerun steps. When it is unavailable, apply the minimal fix instead and report the requested change as a needs-attention item. The subagent's brief:
      1. **What it gets.** The behavioural intent: what the classic construct did and what the edit must preserve, stated as behaviour, which failures are handled and that no element is resolved more often than the classic construct resolved it, never as which existing activities must stay untouched; the Limits and Sources sub-steps of this loop; the paths of both projects and of the file to edit; the instruction to invoke the RPA authoring skill through the Skill tool before editing, by the name its skill list shows (`uipath:uipath-rpa` in the plugin install, `uipath-rpa` otherwise), and to author with the package's documented idioms; step 3's validate and build commands as written there, together with the text of SKILL.md Rule 8, so the subagent writes the Studio-pin form for its own shell; and the instruction that every construct it edits or adds carries the SKILL.md Rule 12 mark.
      2. **What it never gets.** XAML mechanics: attribute values, identifiers, element names or property settings to copy. In particular, never tell it to reuse another target's identifiers; a new target gets a fresh `Guid`. Nor a design of its own: the brief carries the user's requested treatment and the constraints in this guide's words, never which activities to add or how the edit meets a constraint.
      3. **What comes back.** The edited file, marked as Rule 12 says, and the validate and build results. Anything of the stated intent the subagent could not preserve is a defect of the skill's own edit (Report section).
      4. **Check before validate.** Read the returned construct and count the UI targets on the path it executes, against the count the classic construct resolved, which the brief stated. A higher count is a defect of the skill's own edit, not a note: re-brief once, naming the two counts, and when the second return still exceeds the classic count, restore the backup and report the requested change as a needs-attention item. Only a construct that passes this check goes to validate.
   4. **Sources.**
      1. **Where.** SKILL.md Rule 14 names the only two sources: the packages the latest run resolved, here the set in `<OUTPUT_DIR>/.local/AllDependencies.json` read under `%USERPROFILE%\.nuget\packages\<package>\<version>\`, and the page the construct's own annotation links. Never another cached version, never a scan across versions.
      2. **How to read a package.** Within those packages, read documentation and file names only: `content/docs`, XML documentation files, and the DLL names under `lib`. A package's assemblies may sit in a companion package of the resolved set, so a file-name search covers every package `AllDependencies.json` lists, not only the ones `project.json` names. Never grep a binary for a name, and never write, compile or run a program to inspect assembly metadata: a text match inside a binary is a mention, not a definition.
      3. **Confirmation.** Every name an edit introduces into a XAML file, whether a type, an assembly, a property, an enum member or a name inside an expression, is confirmed by the validate and build of step 3, which reject an unknown one before any rerun. A candidate is therefore enough to propose, taken from the run log, from the migrated project's own declarations (the migrator's `xmlns` and `AssemblyReference` entries name the assemblies it wired in), or from a package file name.
      4. **Defaults.** When a fix introduces or reshapes an activity, its default property values come from `env -u UIPATH_STUDIO_PID uip rpa activities get-default-xaml --activity-class-name <CLASS_NAME> --project-dir "<OUTPUT_DIR>" --output json`, never from a neighbouring migrated activity: the migrator sets properties per activity, and a value copied from one changes the behaviour of another.
      5. **Fallback.** When those sources give no candidate, ask the user.
2. Ask one yes/no question: what will change, in which file and activity, and why it should remove this failure. When the edit introduces a name the grounding source did not supply, say that validate and build confirm it before the rerun. Yes means apply and run again. No ends the loop; report.
3. Before editing a file, copy it to `<PROJECT_DIR>/.upgrade/runtime-fixes/<N>/<relative path>` (fix-only mode: `<MIGRATED_DIR>/.upgrade/runtime-fixes/<N>/<relative path>`), `<relative path>` being the file's path and name relative to `<OUTPUT_DIR>` unchanged, no `.bak` or other suffix, and never overwriting a copy already in that folder: the first copy is the pristine one. Apply the edit together with its mark, as SKILL.md Rule 12 says: the `Remediated by uipath-activity-migrator on <date>: <what changed>` line replaces the matching `[PostMigration Action Required]` line or is added as a new annotation attribute, never an XML comment, and when the edit replaces the annotated construct, the construct that replaced it carries the line. Then validate the edited file and rebuild, `<REL_XAML>` being its path relative to `<OUTPUT_DIR>`:

   ```bash
   env -u UIPATH_STUDIO_PID uip rpa validate --project-dir "<OUTPUT_DIR>" --file-path "<REL_XAML>" --min-severity error --output json
   env -u UIPATH_STUDIO_PID uip rpa build "<OUTPUT_DIR>" --output json
   ```

   Both must run and pass; a command that errors on its own syntax is corrected and rerun, never skipped. Then restore the starting state and run again. If validate or the build rejects the edit, restore the backup and return to step 1 with its message as evidence; an edit that does not validate is never run. The rejected edit does not count toward the budget of step 5: the next proposal reuses `<N>` and its backup folder. Two rejected edits for the same `<N>` end the attempts at that failure: ask the step 4 question with the options that remain (stop, or the next grounded source or a different hypothesis, which becomes fix `<N>`), and when none remains report the failure as a needs-attention item.
4. Read the new verdict:
   - Passed: the loop ends. Every fix already carries its Remediated line from step 3; nothing is rewritten here. Report.
   - Failed in the same place, meaning same file, same activity display name and same exception type: the fix did not work. Ask one question with the options side by side: undo the fix and stop; undo the fix and apply the next one; keep the fix and apply the next one. The next fix is named in the option: the next grounded source, else a hypothesis different from the one that failed. Undo restores the backup, then validates and rebuilds. When no next fix exists, the only option is undo and stop, and the failure is reported as a needs-attention item.
   - Failed somewhere else: the fix stands; go back to step 1 for the new failure.
5. After 3 fixes, stop and ask whether to continue; each yes allows 3 more. The user's no ends the loop.

## Report

- The report block is the Runtime check block of the Step 6 template in SKILL.md.
- A pass is one line and nothing else: `Passed in <duration>` first time, `Passed on run <n> after <k> <fix or fixes>` after the loop.
- The workflow's own log output and observations about how the workflow behaves elsewhere, under a debugger for instance, are never report material.
- Fixes applied by the loop go under Fixes applied, each tagged with its fix number `<N>`, the backup folder's number, and its source: fix guide, annotation, hypothesis, or requested for a treatment the user chose; the Remediated annotation belongs to that fix's line, and the "annotations rewritten to Verified healthy" line counts only the fix guide's healthy findings.
- Undone fixes are a count on the Runtime check line, never lines.
- A defect introduced by the skill's own edit is a needs-attention item, counted in `<M>` as SKILL.md Step 6 defines it and listed by name, until it is fixed; it never appears under Next steps as a question.
- When the run passed, drop the "run the main workflow once in Debug" next step; the Studio version line stays.
- Package-specific runtime prerequisites still come from each package guide's Hook 3.

## Anti-patterns

- Running the check with `debug start`; the debugger stops at every throw, handled by a Try Catch or not, and holds the session, so it says nothing about whether the workflow fails
- Running or validating the source project through the headless Studio while the migrated one is open; both carry the same `projectId` and the host has mixed their files
- Inferring window state from `Get-Process` or any process listing before a rerun; it shows one window per process and hides the rest, the UIA package's window snapshot is the only source
- Polling the run log or the instance list more than once a minute while a run is in flight; a workflow can run for hours, every poll is a full turn that copies the log into the context, and the completion notification arrives either way
- Passing `--skip-build` to the runtime check, or probing it with `debug break` / `debug continue`; the first fails on a headless Studio that has not built the project itself, the second returns `Success` with or without a session
- Running or cancelling the migrated project from Studio's integrated terminal without clearing `UIPATH_STUDIO_PID`; the rpa tool opens the migrated project in the user's Studio, which closes their project and ends the terminal session
