/ftl:lab-validator
๐ RHDP E2E Lab Validator
Write solve.yml and validate.yml Ansible playbooks for RHDP Showroom labs.
Reads your .adoc modules โ including screenshots โ and generates working playbooks for E2E testing.
Orchestrates 4 agents: content-reader โ solve-writer โ validate-writer โ env-connector.
Self-healing: When UI versions change, Playwright selectors are automatically recovered via vision โ no manual selector updates required.
Before You Start
The skill opens with a pre-flight checklist. Make sure both are ready before running it:
1 โ Showroom Repo
Sync from
Add solve/validate button placeholders to each .adoc module.
showroom_template_nookbag e2e-template branch:content/supplemental-ui/js/buttons.jscontent/supplemental-ui/css/site-extra.csscontent/lib/inject-buttons.jscontent/lib/dev-mode.jsruntime-automation/module-XX/solve.ymlruntime-automation/module-XX/validate.ymlsite.yml must have the Antora extensions and supplemental_files block configured (copy from e2e-template).Add solve/validate button placeholders to each .adoc module.
2 โ AgV Catalog
All lab types:
rhpds-ftl collection ยท showroom v1.6.6+ ยท zt-runner v2.4.2 ยท wetty v3.0
OCP tenant/dedicated:
RHEL VM:
See
rhpds-ftl collection ยท showroom v1.6.6+ ยท zt-runner v2.4.2 ยท wetty v3.0
OCP tenant/dedicated:
ocp4_workload_runtime_automation_k8s workloadRHEL VM:
vm_workload_runtime_automation workloadSee
examples/ in the e2e-template branch for exact common.yaml per lab type.
Workflow
โถ /ftl:lab-validator
โ
Pre-flight
Checklist Shown
Skill displays required showroom files, site.yml config, and AgV vars per lab type.
Sync your repo and AgV before continuing.
New: Asks if you already have solve.yml or validate.yml. If yes, uses them as baseline โ only generates what's missing.
Sync your repo and AgV before continuing.
New: Asks if you already have solve.yml or validate.yml. If yes, uses them as baseline โ only generates what's missing.
โ
Step 1
Collect Inputs + Environment Setup
Lab type: ocp-tenant ยท ocp-dedicated ยท vm-rhel
Showroom path: local path or GitHub URL
Access โ OCP: admin token or
Access โ VM: SSH host, user, key path
OCP tenant โ order guidance: If no live lab yet, skill tells you to order on
โ ๏ธ Skill checks
Showroom path: local path or GitHub URL
Access โ OCP: admin token or
oc login + restart ClaudeAccess โ VM: SSH host, user, key path
OCP tenant โ order guidance: If no live lab yet, skill tells you to order on
demo.redhat.com using your logged-in SSO user and note the GUID.โ ๏ธ Skill checks
dev.yaml for a silent content_git_repo_ref override that kills branch changes.
โ
Step 2
Discover Modules
Reads all
Checks AgV namespaces and runner image version.
Shows a summary โ you choose which modules to generate playbooks for.
.adoc files and identifies modules with exercises.Checks AgV namespaces and runner image version.
Shows a summary โ you choose which modules to generate playbooks for.
โ
Step 3 โ Per module
4-Agent Pipeline: Read โ Solve โ Validate โ Test
content-reader โ reads .adoc, vision-analyzes screenshots, classifies each step (k8s_exec โ api โ Playwright โ skip)
solve-writer โ generates solve.yml with intent-based Playwright scripts (self-healing on UI changes)
validate-writer โ generates validate.yml with
env-connector โ pushes, tests, collects screenshot evidence, runs self-healing if Playwright fails
Previews files before writing.
solve-writer โ generates solve.yml with intent-based Playwright scripts (self-healing on UI changes)
validate-writer โ generates validate.yml with
rhpds.ftl.validation_check, durable outcome checksenv-connector โ pushes, tests, collects screenshot evidence, runs self-healing if Playwright fails
Previews files before writing.
โ
Step 4 โ Guided
Push โ Restart โ Full Test Cycle
Skill runs the commands for you and shows output at each step:
Then the full test cycle using SSE streams:
git push โ oc rollout restart โ extract Showroom URLThen the full test cycle using SSE streams:
1. Fresh validate โ should โ fail
confirms checks test real student state
confirms checks test real student state
โ
2. Solve โ runs playbook
watch for fatal errors or tracebacks
watch for fatal errors or tracebacks
โ
3. Validate again โ should โ
pass
confirms solve completed the exercise
confirms solve completed the exercise
โ
4. Validate once more โ idempotency check
confirms solve left clean state
confirms solve left clean state
โ
Step 5 โ If needed
Fix Loop (with Self-Healing)
Ansible failure โ solve-writer or validate-writer re-invoked with error context
Playwright failure โ env-connector self-healing: screenshot โ vision โ new selector โ retry
Repeats until all modules pass clean. Screenshots stored as evidence.
Playwright failure โ env-connector self-healing: screenshot โ vision โ new selector โ retry
Repeats until all modules pass clean. Screenshots stored as evidence.
โ
โ
All Modules Pass Solve + Validate
Ordering Your Lab (OCP Tenant)
The skill guides you through this when no live environment exists yet.
โถ Order on demo.redhat.com
- Go to demo.redhat.com and find your catalog item
- Order using your Red Hat SSO user โ same user you are logged in as with
oc login - Note the GUID from the order confirmation
- Your showroom namespace will be
showroom-<guid>
Testing with curl (SSE Streams)
The skill generates and runs these for you. Each stream closes when the playbook finishes.
# Set your URL once (skill does this automatically)
SHOWROOM=https://showroom-<guid>.apps.<cluster>.<domain>
# 1. Fresh validate โ expect โ
curl -sk -N $SHOWROOM/stream/validate/module-01
# 2. Solve
curl -sk -N $SHOWROOM/stream/solve/module-01
# 3. Validate after solve โ expect โ
curl -sk -N $SHOWROOM/stream/validate/module-01
# 4. Validate again (idempotency) โ still โ
curl -sk -N $SHOWROOM/stream/validate/module-01
How to read the output:
- Lines starting with
TASKโ Ansible task names running live ok:/changed:โ task completedfatal:โ task failed โ paste to the skill for diagnosis- Last line contains the
validation_checkresult with โ /โ per exercise task
Lab Types
| Lab Type | AgV config | Runner | Key extravars |
|---|---|---|---|
| OCP Tenant | config: namespace | k8s sidecar pod, namespace-scoped SA | k8s_kubeconfig, student_ns, student_user, guid |
| OCP Dedicated | config: openshift-workloads | k8s sidecar pod, cluster-admin SA | k8s_kubeconfig, guid (student_ns empty) |
| RHEL VM | config: cloud-vms-base | Podman container on bastion | SSH via /app/.ssh/config, host aliases: node, bastion |
Key Patterns
| Pattern | Rule |
|---|---|
| Always pass kubeconfig | Plain oc uses showroom SA (no access). Use oc --kubeconfig= in shell tasks or kubeconfig: "" in kubernetes.core modules. |
| k8s_exec command | Must be a string, not a list. A list makes Kubernetes treat the first item as the executable name. |
| NetworkPolicy bypass | Use k8s_exec into the target pod and call localhost โ avoids cross-namespace HTTP blocks. |
| Idempotency | Solve runs every time a student retries. Guard every create operation. |
| Async operations | Trigger and exit. Validate uses any() not max() to detect completion without new queued tasks blocking results. |
| Durable outcomes | Validate persistent state (file exists, resource created) โ not transient state (branch name, pod restarts). |
| JSON in k8s_exec | Parse via python3 -c "import json,sys..." โ Ansible's from_json fails when stdout has deprecation warnings alongside JSON. |
| regex_search | first | Returns None on no match. None | first crashes. Use separate shell tasks instead. |
| dev.yaml override | Check for content_git_repo_ref in dev.yaml โ it silently overrides common.yaml and clones the wrong branch into the showroom pod. |