Live Smoke Tests
Use this checklist to validate the MCP server against a real sandbox or disposable VCF Automation/vRO environment. Keep this separate from local validation: npm run validate checks the repository and must not contact VCFA.
Run live smoke tests only where it is acceptable to create, run, package, import, or delete disposable test assets. Use harmless workflows and test categories/packages. Review the exact target, expected impact, and rollback path before setting confirm: true on any live mutation. Use VCFA_IGNORE_TLS=true only in lab environments where you accept the TLS risk.
Environment Setup
Unless a section says otherwise, this checklist targets the default VCFA_TARGET_PLATFORM=vcfa platform (VCF Automation 9.x). The vRA/vRO 8 Compatibility Mode section below covers vra8.
Configure the required connection variables:
VCFA_HOST=...
VCFA_USERNAME=...
VCFA_ORGANIZATION=...
VCFA_PASSWORD=...Two dimensions change what a run actually covers, so record both alongside the results:
- Identity.
VCFA_ORGANIZATION=systemis a provider session. It reads vRO normally but cannot reach the tenant-scoped Automation services — project-service answers403and the catalog, deployment, blueprint, event-broker and subscription services answer500(VCFO-085). The catalog, deployment, template, subscription, event-topic and project tools therefore need a tenant organization. - vRO topology. With
VCFA_VRO_HOSTset, only/vco/apigoes to the external appliance while the login,GET /api/versionsand the Automation services stay onVCFA_HOST(VCFO-081). Unset, everything runs against the appliance-embedded orchestrator. A vRO result is only evidence for the topology it ran under.
# Optional: point the vRO half at an external appliance
VCFA_VRO_HOST=...Use clearly scoped artifact directories for the smoke run:
VCFA_ARTIFACT_DIR=./artifacts/live-smoke
VCFA_WORKFLOW_DIR=./artifacts/live-smoke/workflows
VCFA_ACTION_DIR=./artifacts/live-smoke/actions
VCFA_CONFIGURATION_DIR=./artifacts/live-smoke/configurations
VCFA_RESOURCE_DIR=./artifacts/live-smoke/resources
VCFA_PACKAGE_DIR=./artifacts/live-smoke/packages
VCFA_EXECUTION_LOG_DIR=./artifacts/live-smoke/execution-logsFor package-first validation, use a disposable package name:
VCFA_PROJECT_PACKAGE_NAME=com.example.vcfa.mcp.smokeRead-Only Discovery
Start with read-only calls and record the real IDs returned by the environment:
list-plugins()
list-categories(type: "WorkflowCategory")
list-categories(type: "ActionCategory")
list-categories(type: "ConfigurationElementCategory")
list-categories(type: "ResourceElementCategory")
list-workflows(filter: "<known harmless workflow name>")
get-workflow(id: "<workflow-id>")
list-actions(filter: "<known action name>")
list-configurations()
list-resource-elements()Stop if the required test category, workflow, action, configuration, resource, or package cannot be identified from discovery. Do not substitute guessed IDs.
Artifact Export And Local Validation
Export a harmless workflow and validate it locally:
export-workflow-file(id: "<workflow-id>", fileName: "smoke.workflow", overwrite: false)
preflight-workflow-file(fileName: "smoke.workflow")
diff-workflow-file(
base: { source: "file", fileName: "smoke.workflow" },
compare: { source: "file", fileName: "smoke.workflow" }
)When disposable action or configuration test objects exist, repeat the minimal export and preflight path:
export-action-file(id: "<action-id>", fileName: "smoke.action", overwrite: false)
preflight-action-file(fileName: "smoke.action")
export-configuration-file(id: "<configuration-id>", fileName: "smoke.vsoconf", overwrite: false)
preflight-configuration-file(fileName: "smoke.vsoconf")Harmless Workflow Execution
Use a known no-op or read-only workflow. Inspect its inputs first, then run it only after confirming the target and impact:
get-workflow(id: "<workflow-id>")
run-workflow-and-wait(
id: "<workflow-id>",
inputs: [
{ name: "<input-name>", value: "<safe test value>" }
],
timeoutSeconds: 60,
pollIntervalSeconds: 2,
confirm: true
)Verify the execution and logs:
list-workflow-executions(workflowId: "<workflow-id>", maxResults: 5)
get-workflow-execution(workflowId: "<workflow-id>", executionId: "<execution-id>")
get-workflow-execution-logs(workflowId: "<workflow-id>", executionId: "<execution-id>", level: "info", maxResult: 100)
get-workflow-execution-logs(
workflowId: "<workflow-id>",
executionId: "<execution-id>",
fileName: "smoke-execution-logs.json",
level: "info",
format: "json",
maxResult: 200,
overwrite: false
)Package-First Validation
Use only a disposable package and disposable content. Create the package only after confirming the package name is correct:
ensure-project-package(createIfMissing: true, confirm: true)
add-workflow-to-project-package(workflowId: "<workflow-id>", confirm: true)
rebuild-project-package(confirm: true)
export-project-package(fileName: "com.example.vcfa.mcp.smoke.package", overwrite: false)
get-project-package-import-details(fileName: "com.example.vcfa.mcp.smoke.package")Review the package identity and element list before any import. In a sandbox only, optionally perform one controlled import:
import-project-package(fileName: "com.example.vcfa.mcp.smoke.package", overwrite: false, confirm: true)Promotion Planning
Run promotion planning before imports so the operator can review preflight, backup, diff, and the exact recommended import call:
prepare-artifact-promotion(
kind: "workflow",
fileName: "smoke.workflow",
target: {
categoryId: "<workflow-category-id>",
workflowId: "<workflow-id>"
},
backup: {
enabled: true,
fileName: "smoke-backup.workflow",
overwrite: false
},
overwrite: true
)Confirm that the summary names the intended target, reports no blocking preflight issues, includes the expected diff, and recommends the correct import call.
VCF Automation 9.x Notes
Behaviour measured on 9.1 under VCFO-086; see the VCF Automation Verification Matrix for the per-tool record.
List semantics differ from vRA 8 and change what a filter result proves:
/workflowsappliesconditionsserver-side and case-insensitively, and honorsmaxResult, but ignoresstartIndexand rejectsqueryCount=truewith a400. An unfilteredlist-workflowstherefore trips the repeated-page guard and falls back to a category traversal of roughly 137 requests — that is the normal path on this platform, not a fault. A filtered listing is cheap./actions,/packages,/configurationsand/resourcesignoreconditionsandmaxResultentirely and return the full inventory, so the VCFO-073 client-side post-filter is what makesfilterwork there.
Two mutating tools perform one non-mutating read before the confirm gate, by design, so the prompt can name the target: update-configuration and ensure-project-package. Every other mutating tool refuses without reaching the network.
export-configuration-file answers 406 on 9.1 exactly as on vRA 8; route the element through add-configuration-to-project-package and export-project-package instead.
Check the API version the client settles on, which is logged once per authentication:
[vro-client] Negotiated VCF Cloud API version 9.1.0 via GET /api/versionsVCFA_TARGET_PLATFORM=vcfa9.1 and vcfa9.0 pin the version and skip that probe.
Split-host smoke check (external vRO)
When VCFA_VRO_HOST is set, confirm the split is real before reading anything into a vRO result. A set-but-unused variable proves nothing: both earlier tenant rounds had it set and made zero /vco/api requests. The startup banner and the per-request log lines are the evidence:
[vcfa-server] VCFA_VRO_HOST=<vro-host>: vRO API requests (/vco/api) are sent to this host; authentication and the Automation services use VCFA_HOST=<vcfa-host>.
[vro-client] GET /configurations?maxResult=100&startIndex=0&queryCount=true on <vro-host>
[vro-client] GET /blueprints?$search=…&page=0&size=100 on <vcfa-host>Every /vco/api path must name the vRO host and every Automation path the VCFA host. Then note which identity you are on, because the two are not interchangeable in this topology (VCFO-099):
- A provider session reads and writes vRO on the external appliance. This is the only identity that can author there.
- A tenant session is read-only on it and may see almost nothing —
create-configurationanswers403 … (Edit, false), and the inventory can read 0 workflows and 0 packages. A200on an empty list is not a pass; check the identity before concluding the appliance is empty.
No MCP tool creates a workflow category. For a disposable one, POST /vco/api/categories{name, type, description} answers 201 and DELETE /categories/{id}?deleteContents=false answers 204.
Searching the Automation services on 9.1
search is a silent no-op on the service for list-templates, list-deployments and list-catalog-items: the client sends $search=<needle>, 9.1 answers 200 and ignores it, and the full inventory comes back. Since VCFO-100 the client matches the needle itself, against name and description, so the tools return the filtered rows the caller asked for; $search is still sent for a service that honors it. A needle matching nothing now yields an empty result rather than the whole inventory — verified live under VCFO-100 on a 9.1 tenant session, together with a matching needle, a differing case, a padded needle, and a description-only match against a disposable blueprint. list-projects is unaffected; its search becomes an OData $filter that the project service does apply (VCFO-065/072, VCFO-099).
Deployment lifecycle (9.x, tenant session)
This is the only sequence in this document that provisions and destroys real infrastructure. It needs a tenant session — a provider session cannot reach the catalog or deployment service at all — disposable assets, and explicit user confirmation of the catalog item, project, inputs and expected cost before any confirm: true. delete-deployment is the only removal path and is itself a destructive day-2 operation rather than an undo.
Rendered tool output cannot settle a shape question: a missing key renders (unnamed), which says nothing about the real key, and both arms of the DeploymentActionList union render an identical Found N deployment action(s). So this sequence is driven through the MCP tools and mirrored by raw authenticated GETs that record the wire keys. Dump keys only, never bodies.
Discovery first, which is also the go/no-go gate:
list-projects()
get-project(id: "<project-id>")
list-catalog-items()
get-catalog-item(id: "<catalog-item-id>")
list-deployments()
list-deployments(projectId: "<project-id>")If the catalog holds nothing released to the project, stop before any write — that is a blocked run, not a settled one. Record the starting counts; the run must return to them. Deployment inputs come from the catalog item's schema or the blueprint, never guessed.
Refusals and target guards next, none of which mutates anything:
create-deployment(..., confirm: false)
delete-deployment(id: "<deployment-id>", confirm: false)
run-deployment-action(..., confirm: false)
create-deployment(..., expectedCatalogItemName: "zz-wrong", confirm: true)
create-deployment(..., expectedProjectName: "zz-wrong", confirm: true)The three confirm: false calls must refuse before any HTTP request. The two mismatches do reach the network, for the guard's own non-mutating read — a distinction worth recording, because the "refuses before any HTTP" claim in the verification matrix is about the first class only.
Then the provision, the reads, and teardown:
create-deployment(catalogItemId: "...", deploymentName: "zz-smoke-<date>", projectId: "...",
inputs: {...}, expectedCatalogItemName: "...", expectedProjectName: "...",
confirm: true)
get-deployment(id: "<deployment-id>") # poll to a terminal status
list-deployments(projectId: "<project-id>")
list-deployment-actions(deploymentId: "<deployment-id>")
delete-deployment(id: "<deployment-id>", expectedName: "zz-smoke-<date>", confirm: true)Points that decide whether the run proves anything:
- Capture the create response. The client types it as a single deployment object. If the route answers with a list of request objects instead, the tool prints no identifiers and the ID has to be recovered from
list-deployments— record which happened. - Record the full status vocabulary observed.
Deployment.statusis a loose string and the declared examples are informed guesses. - Mirror
get-deploymentandlist-deployment-actionswith rawGETs. These two are what settle the item shape and which arm of the action-list union the service serves. - The delete's success message is not evidence of removal. The client discards the response body, so it reports only a 2xx on an asynchronous route. Confirm by polling
get-deploymentto a 404 and by the project-scoped list no longer showing it. - Omit
expectedStatusfrom the teardown delete if any day-2 action was submitted: the deployment moves through transient states and a spurious refusal during teardown is the worst time to discover that. CREATE_FAILEDis not a reason to skip teardown — the record exists and may hold allocated resources.
Grep every capture for undefined, [object Object], NaN, (id: ) and for leaked secrets, and add (unnamed) for this run specifically: here a hit is not noise, it is the key-mismatch finding itself.
If teardown does not reach absence, say so explicitly with the deployment ID, name, project and last status, and record that live infrastructure is still allocated. Never write that an environment returned to its starting counts when it did not.
Cleanup trap
delete-package releases its members asynchronously, and for roughly two seconds afterwards vRO still reports them as in use and answers a delete with 409. Re-measured under VCFO-087, that refusal is transient rather than permanent: a plain retry cleared it in every timed sample, and nothing was ever permanently stuck — which is the opposite of what #192 reported.
So retry the delete first. delete-workflow, delete-action and delete-configuration also take force, which sends vRO's own ?force=true, but that skips a reference check that is doing real work — reach for it only for an element that is genuinely referenced, never to clear a refusal a retry would have cleared. Deleting disposable elements before the package that contains them, or deleting the package with deleteContents: true, still avoids the race entirely.
Provisioning A Deployment (VCFO-074)
This round provisions and destroys real infrastructure, and delete-deployment is itself a destructive day-2 operation rather than an undo. It needs disposable assets and explicit confirmation per safety. It also needs a tenant session: a provider (VCFA_ORGANIZATION=system) session cannot reach the catalog or deployment services at all, which answer 500 (VCFO-085). The identity, not the credentials, is the gate.
Build first. The rig spawns dist/index.js, and a stale build silently tests the previous signature — the likeliest way this round produces a wrong answer.
Go/no-go gate
Run the reads first and record the starting counts:
list-projects()
list-catalog-items()
get-catalog-item(id: "<catalog-item-id>")
list-deployments()
list-deployments(projectId: "<project-id>")- A
403/500here means the session is still provider-shaped. The round never started. - Zero released catalog items ⇒ stop before any write. Record it as a blocked round.
get-catalog-itemsupplies both the exact name the guards will be given and the request schema the deploymentinputsmust satisfy. Never guess inputs.- Pin
versionexplicitly. A catalog item's input schema changes between released versions, so taking the "latest" default can deploy a different contract than the one you recorded.
Ordered calls
Free calls first, so a late failure still leaves the cheap findings recorded.
create-deployment,delete-deployment,run-deployment-actionatconfirm: false— each must refuse before any HTTP.create-deploymentwith a wrongexpectedCatalogItemName, then a wrongexpectedProjectName. Unlike theconfirm: falsecases these do reach the network for the guard's non-mutating read.- The provision, with matching expected values and a name marking it disposable.
get-deploymentpolled to a terminal status; record the full status vocabulary.list-deploymentsbare and project-scoped with the deployment present.list-deployment-actions.run-deployment-actionguard paths (wrongexpectedActionName, wrongexpectedStatus). Submission is a separate decision: only a benign reversible action the user names explicitly, only after all reads are captured, and neverDeployment.Delete— teardown must go throughdelete-deployment, the tool under test.- When an action is submitted, capture its request ID and poll
get-deployment-requestto a terminal status. Record task progress, timestamps and response keys without printing untyped inputs or outputs.
A free request to read before any write. list-deployment-requests(deploymentId: "<id>") serves a deployment's request history — a Spring page on vRA 8.18 and on VCF Automation 9.1 alike (VCFO-095), read from GET /deployment/api/deployments/{id}/requests; the equivalent GET /deployment/api/requests?deploymentId=<id> exists on both and is not the route the tool sends. Listing a deployment that already exists yields a real, terminal request ID — including the create request's, which is returned nowhere at submission — so both that tool and get-deployment-request can be exercised at zero infrastructure cost before the round decides whether to provision anything. Run it against an absent deployment ID too: the 404 arm is free, and the refusal must still name get-deployment-request rather than implying the requests are gone with the deployment. The post-deletion 404 on a deployment that did exist needs a disposable deploy/delete cycle and belongs to a round that already has one.
Rendered output cannot settle a wire shape: a (unnamed) fallback says nothing about the real key, and both arms of the DeploymentActionList union render identically. A shape question needs a raw-HTTP key dump alongside the tool calls. Dump keys only, never the token or a response body.
Teardown
Rehearse the guard with a wrong expectedName (free), then delete with matching values.
The success text is not evidence of completion. delete-deployment reports the deletion as requested and prints the Deployment.Delete request the service queued (ID and status) when it returns one — a 2xx on this route means queued, not done. Poll that ID with get-deployment-request when it is present, then confirm resource removal independently by polling get-deployment to a 404 and by list-deployments(projectId) no longer listing it.
CREATE_FAILED is not an excuse to skip teardown — the record exists and may hold allocated resources. If teardown fails, say so immediately with the deployment id, name, project and last status, and file it. Never write "returned to its exact starting counts" when it did not.
Captures
Keep every result text, the server stderr, the key dumps, before/after counts and timings. Grep them for undefined, [object Object], NaN, (id: ) and for secrets (count only, never the value). Add (unnamed) to that grep: here a hit is not noise, it is a key-mismatch finding.
The 2026-09-16 results are recorded in the VCF Automation Verification Matrix.
vRA/vRO 8 Compatibility Mode
For vRA/vRO 8.12+ bearer-token validation, set the platform and use the vIDM domain shown on the Workspace ONE login page as the organization:
VCFA_TARGET_PLATFORM=vra8
VCFA_ORGANIZATION="System Domain"Read-only checks, safe on any vRA 8 environment:
list-workflows()
get-workflow(id: "<workflow-id>")
list-projects()
list-templates()
list-subscriptions()
list-event-topics()
list-catalog-items()
list-deployments()
run-workflow-and-wait(id: "<workflow-id>", inputs: [], timeoutSeconds: 60, confirm: true)
get-workflow-execution-logs(workflowId: "<workflow-id>", executionId: "<execution-id>", level: "info")The Automation-service list tools return the same shapes as on VCFA 9.x. list-catalog-items and list-deployments were both empty in the environment VCFO-068 and VCFO-070 verified; VCFO-088 later read a released catalog item and provisioned, inspected, powered off and on, and destroyed a deployment on vRA 8.18, so the catalog item, deployment and deployment-action shapes are confirmed there as well as on VCFA 9.1 (VCFO-074), and the DeploymentRequest shape is confirmed there for the first time on any platform. The deployment round described above under Provisioning A Deployment applies to this mode unchanged, except that the identity gate is a 9.x concern — here a vIDM user entitled to the catalog item suffices. Both renderers still fall back to (unnamed) for a row served without a name, so an unexpected shape degrades visibly instead of printing undefined.
The vRO write surface is verified on vRA 8 but still mutates a live environment, so run it only against a disposable category and disposable content, and clean up afterwards:
list-categories(type: "WorkflowCategory")
create-workflow(categoryId: "<disposable-category-id>", name: "zz-smoke", confirm: true)
create-configuration(categoryId: "<disposable-config-category-id>", name: "zz-smoke", attributes: [{ name: "setting", type: "string", value: "probe" }], confirm: true)
delete-workflow(id: "<workflow-id>", confirm: true)
delete-configuration(id: "<configuration-id>", confirm: true)Deleting an element immediately after the package that contained it can answer 409 Conflict reporting it as in use. On 9.1 this is transient — vRO releases package members asynchronously and the state clears in about two seconds — so retry the plain delete first. force: true sends vRO's own ?force=true and is for an element that is genuinely referenced; it skips the reference check, so do not reach for it to get past a refusal that a retry would clear (VCFO-087).
delete-workflow(id: "<workflow-id>", force: true, confirm: true)Configuration writes send the plural attributes key on every platform since VCFO-074, so this mode no longer has an attribute-key difference to check; PUT /configurations/{id} still has to carry the element name.
Template and subscription writes are supported in this mode (VCFO-070). They mutate a live environment, so use disposable objects and clean up. Create the subscription disabled and non-blocking, on a non-blockable topic, so it cannot stall provisioning:
list-projects()
list-event-topics()
create-subscription(
name: "zz-smoke",
eventTopicId: "<non-blockable topic id>",
runnableType: "extensibility.vro",
runnableId: "<harmless workflow id>",
blocking: false,
disabled: true,
confirm: true
)
update-subscription(id: "<subscription-id>", expectedName: "zz-smoke", description: "changed", confirm: true)
get-subscription(id: "<subscription-id>") # topic and runnable carried forward
create-template(name: "zz-smoke", projectId: "<project-id>", content: "formatVersion: 1\ninputs: {}\nresources: {}\n", confirm: true)
delete-template(id: "<template-id>", expectedName: "zz-smoke", confirm: true)
delete-subscription(id: "<subscription-id>", expectedName: "zz-smoke", confirm: true)A DRAFT template provisions nothing, but its create and delete do fire blueprint.configuration, which the platform's own content-sync subscribers listen on.
Expected unsupported-mode message in this mode:
export-configuration-file(...)It explains that vRA 8 serves a configuration element as JSON only and points at the project-package route. prepare-artifact-promotion(kind: "configuration", backup: { enabled: true }, ...) does not fail in this mode: it reports Backup skipped: with the same pointer and still returns the preflight report and the import recommendation.
With the disposable configuration element from the write checks, verify the update-configuration two-phase flow (both platforms):
update-configuration(id: "<configuration-id>", attributes: [{ name: "setting", type: "string", value: "probe-2" }], confirm: false) # confirmation prompt naming the element
update-configuration(id: "<configuration-id>", attributes: [{ name: "setting", type: "string", value: "probe-2" }], confirm: true)
get-configuration(id: "<configuration-id>") # description unchanged, value probe-2
update-configuration(id: "<configuration-id>", description: "changed", confirm: false) # refused: would delete the attribute
update-configuration(id: "<configuration-id>", attributes: [{ name: "token", type: "SecureString" }], confirm: false) # refused: empty secretThe vRO artifact chains below were all exercised against a vRA 8.18 lab under VCFO-075. Full per-tool results are in the vRA 8 Verification Matrix.
Discovery note for this mode: list-categories(type: "ActionCategory") returns nothing, so action modules come from the module column of list-actions. ResourceElementCategory does return categories.
Action chain. Export and diff take the action's element ID; get-action also accepts the fully qualified name:
list-actions(filter: "<name>")
get-action(id: "<module>/<actionName>", includeScript: true)
create-action(moduleName: "<module>", name: "<actionName>", script: "return 'ok';", returnType: "string", confirm: true)
update-action(id: "<action-id>", expectedName: "<actionName>", expectedModule: "<module>", script: "return 'v2';", confirm: true)
export-action-file(id: "<action-id>", fileName: "probe.action", overwrite: false)
preflight-action-file(fileName: "probe.action")
diff-action-file(
base: { source: "live", actionId: "<action-id>" },
compare: { source: "file", fileName: "probe.action" }
)
import-action-file(categoryName: "<module>", fileName: "probe.action", expectedCategoryName: "<module>", confirm: true)
delete-action(id: "<action-id>", expectedName: "<actionName>", expectedModule: "<module>", confirm: true)import-action-file requires the target module to already exist on vRA 8: an unknown module answers 404 Action category name not found. Use create-action to establish a new module first. Deleting a module's last action also removes the module, so a disposable module leaves no residue.
Resource chain. import-resource-element always creates a new element (it has no overwrite), so a round-trip adds one that must be cleaned up:
export-resource-element(id: "<resource-id>", fileName: "probe.gif", overwrite: false)
import-resource-element(categoryId: "<resource-category-id>", fileName: "probe.gif", expectedCategoryName: "<category>", confirm: true)
update-resource-element(id: "<new-resource-id>", fileName: "probe.gif", expectedName: "probe.gif", confirm: true)
delete-resource-element(id: "<new-resource-id>", expectedName: "probe.gif", confirm: true)Do not pass expectedCategoryName to update-resource-element or delete-resource-element on vRA 8: the platform's resource listing carries no category, so the tools refuse with a message saying the value cannot be verified. Confirm placement with list-resource-elements instead.
Direct package chain, on a disposable package:
create-package(name: "com.example.probe", description: "disposable", confirm: true)
export-package(name: "com.example.probe", fileName: "probe.package", overwrite: false)
preflight-package(fileName: "probe.package")
get-package-import-details(fileName: "probe.package")
import-package(fileName: "probe.package", expectedPackageName: "com.example.probe", overwrite: true, confirm: true)
delete-package(name: "com.example.probe", expectedName: "com.example.probe", deleteContents: false, confirm: true)preflight-package reports workflowArtifacts: 0 for a real vRO package and says so in a warning: vRO packages store elements as elements/<id>/data, not as nested .workflow / .action / .vsoconf entries, so only ZIP and import safety are validated. get-package-import-details reports the true element count — but it runs preflight internally, so it can fail on a package that does not pass.
The remaining project-package adders, beyond the workflow one shown earlier:
add-action-to-project-package(categoryName: "<module>", actionName: "<actionName>", confirm: true)
add-configuration-to-project-package(configurationId: "<configuration-id>", confirm: true)
add-resource-to-project-package(resourceId: "<resource-id>", confirm: true)
import-project-package(expectedPackageName: "<package>", overwrite: true, confirm: true)Discovery and planning tools worth including in a full pass:
list-workflows-by-category(categoryName: "<category>", maxCategories: 10)
collect-context-snapshot(fileBaseName: "probe-ctx", includeOptionalDomains: true, maxItemsPerDomain: 20)
diff-workflow-file(
base: { source: "live", workflowId: "<workflow-id>" },
compare: { source: "live", workflowId: "<workflow-id>" }
)
prepare-artifact-promotion(kind: "action", fileName: "probe.action", target: { categoryName: "<module>", actionId: "<action-id>" }, backup: { enabled: true })
prepare-artifact-promotion(kind: "package", fileName: "probe.package", target: { packageName: "<package>" })A scaffolded workflow imports and runs in this mode. Preflight warns that an input parameter "has a <description> child" on any workflow exported unmodified from vRO 8.x — that is a VCF 9.x editor constraint, not a defect in the exported file.
Negative And Safety Checks
Confirm the safety guardrails before trusting the environment for broader work:
run-workflow(id: "<workflow-id>", inputs: [], confirm: false)
delete-workflow(id: "<workflow-id>", confirm: false)
export-workflow-file(id: "<workflow-id>", fileName: "../escape.workflow")
export-workflow-file(id: "<workflow-id>", fileName: "smoke.workflow", overwrite: false)Expected results:
- Live mutation tools refuse to proceed unless
confirmistrue. - Unsafe artifact file names are rejected.
- Existing export targets require
overwrite: true. - Surfaced errors include safe diagnostics, such as status and correlation IDs, but not passwords, tokens, private keys, or raw sensitive response bodies.