Skip to content
Merged
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
36 changes: 36 additions & 0 deletions .cursor/commands/preflight-learning-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Command: /preflight-learning-path

Self-review a learning path package in `interactive-tutorials` **before** opening a PR. Mirrors [/review-learning-path-pr](review-learning-path-pr.md) (shared static checklists, shared claim-check, Playwright DOM) from the author side, with fewer stop-and-type moments: the agent runs what it can, then pauses only when it needs you (login, smoke choice, results / fixes).

When invoked, read and follow **[preflight-learning-path/SKILL.md](../skills/preflight-learning-path/SKILL.md)** in order.

LP packages are **single-repo** (`interactive-tutorials` only). Metadata lives in package `website.yaml`; the website repo is read-only for conversion ([PR #416](https://github.com/grafana/interactive-tutorials/pull/416)). Learning Hub criteria: [learning-hub-standards.md](../skills/review-learning-path/learning-hub-standards.md).

### Setup you need

- This repo checked out with your `{slug}-lj/` package
- **Playwright MCP** enabled in Cursor (for DOM checks)
- Access to `https://learn.grafana.net/` (Okta login in the Playwright browser when asked)
- Block Editor only if you choose a guided smoke walk later

---

## First message to the author

> I'll preflight your learning path with as few interruptions as possible. I'll run the static checks on my own, then pause when I need you logged into Playwright, again for an optional Block Editor smoke choice, then once for results and fix options.
>
> | When I pause | Why |
> |---|---|
> | Path unclear | Confirm which `{slug}-lj/` package |
> | Playwright not ready | Fix or add MCP |
> | Before live DOM | Okta login + which stack |
> | After DOM | Smoke: already-tested / walk-me / skip |
> | Results | What to fix (if anything) |
>
> **Setup:** Playwright MCP should be on. If it is missing or broken, I'll help fix it. You'll Okta-login in the Playwright browser for DOM checks.
>
> Preflight reports stay under `.cursor/lp-preflight-state/` (gitignored). Don't force-add them to your PR.
>
> **To start:** Share the path package (`{slug}-lj/` directory), or tell me to infer it from your current branch. If you already named the path, I'll begin the static checks now.

If the path is already clear from the user message, skip asking and start identify + static immediately.
1 change: 1 addition & 0 deletions .cursor/learning-path-workflows/workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,4 @@ The learning path slug is mysql-data-source.
| `/build-interactive-lj` | Existing milestone markdown in website repo (read-only source) | `content.json` + `manifest.json` + `website.yaml` files in interactive-tutorials |
| `/create-learning-path` | Feature description (no existing markdown) | `content.json` + `manifest.json` + `website.yaml` files |
| `/review-learning-path-pr` | Existing LP PR in `interactive-tutorials` (share PR URL/number) | Human-guided review: static workbook, Block Editor smoke test, chat-approved inline comments, submit |
| `/preflight-learning-path` | Local `{slug}-lj/` package before opening a PR | Author self-review with few pauses (login, smoke choice, results): mirrors review static + Playwright checks and shared claim-check, readiness report, optional fixes / frontend testid PR |
457 changes: 457 additions & 0 deletions .cursor/skills/preflight-learning-path/SKILL.md

Large diffs are not rendered by default.

144 changes: 144 additions & 0 deletions .cursor/skills/preflight-learning-path/author-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Author testing (preflight)

Live-test helpers for [preflight-learning-path/SKILL.md](SKILL.md).

Aligns with the five-phase [review-learning-path](../review-learning-path/SKILL.md) live path, lighter for authors: Playwright DOM is required; Block Editor is opt-in. Fits the hard author flow: pause for login, then smoke choice; do not quiz between DOM milestones.

---

## Prerequisites

Confirm during identify (quietly unless blocked). Remind in the slash-command first message.

| Need | Required when | Why | How to verify / fix |
|---|---|---|---|
| `interactive-tutorials` checkout with `{slug}-lj/` | Always | Package under test | Path on disk / current branch |
| **Playwright MCP** enabled (`user-playwright`) | Live path (default for new/conversion interactive) | Agent DOM checks | Identify: list or call Playwright MCP tools. If missing or broken: follow [If Playwright MCP is missing or broken](#if-playwright-mcp-is-missing-or-broken) |
| Okta login in the **Playwright** browser to `{learn_host}` (default `learn.grafana.net`) | Before Playwright DOM loop | MCP cannot complete SAML alone | Login pause: author logs in, replies `ready` |
| Pathfinder Block Editor on learn | Only if author chooses `walk-me` | Optional smoke coaching | `{learn_host}/plugins/grafana-pathfinder-app?dev=true` → **?** → Debug → Block Editor → import local JSON |
| Pathfinder CLI (`grafana-pathfinder-app` built locally) | Nice-to-have | `validate --packages` | Note if missing; do not abort preflight |
| `gh` auth + write access to the UI repo | Frontend walkthrough only | Frontend testid PR | Check when entering frontend steps |
| `website` repo in workspace | Optional (conversion) | Read-only legacy compare | Never write |

Same Playwright + Okta role as [learning-path-workflows/workflows.md](../../learning-path-workflows/workflows.md) and `/create-learning-path`.

### If Playwright MCP is missing or broken

Stop before live DOM checks. Do **not** silently skip DOM checks on new/conversion interactive paths. `static-only: <reason>` only when [static-only rules](reference-checks.md#static-only-preflight) allow it.

Diagnose which case applies, then offer help (manual steps always; agent action when possible):

| Case | How you can tell | Offer |
|---|---|---|
| **Config missing** from `~/.cursor/mcp.json` (no `playwright` / `@playwright/mcp` entry) | Read `mcp.json`; server absent | Ask: **Want me to add the Playwright MCP config for you?** If yes, merge the standard block below into `mcp.json`. Then ask them to reload MCP and reply when ready so you recheck. |
| **Needs auth** (`needsAuth` / only `mcp_auth` tool) | `GetMcpTools` / server status | Ask: **Want me to start the Playwright MCP connect flow?** If yes, call `mcp_auth` for `user-playwright` (empty args), wait, recheck. |
| **Configured but toggled off** in Cursor Settings | Entry exists in `mcp.json`; tools still unavailable | Manual only: Settings → MCP → enable **Playwright**. Agent cannot flip that toggle. |
| **Configured but broken** | Entry exists; server shows error / tools fail / navigate fails. Common: custom CDP like `http://localhost:9222` with nothing listening | Explain the failure plainly. Offer to replace with the standard `npx @playwright/mcp@latest` block (reply **add playwright mcp** or **fix playwright mcp**). Warn that this overwrites a custom playwright entry; keep other servers. Then reload and recheck. |
| **Errored / won't start** | Tools missing; logs or STATUS show install/runtime errors | Diagnose (`npx`, Node, network). Offer the standard config; author confirms reload. |

Standard config to add or restore (do not overwrite unrelated servers; for **configured but broken**, replace only the `playwright` server entry after the author agrees):

```json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}
```

**Blocked checkpoint shape (author-facing):**

> Playwright MCP isn't ready, so I can't run the live DOM checks on this path yet.
>
> **Manual setup:** Cursor Settings → MCP → enable **Playwright** (or fix / re-add it), then reload.
>
> If Playwright is listed but broken (for example a CDP URL like `localhost:9222` with no browser listening), reply **fix playwright mcp** and I'll switch it to the standard `npx @playwright/mcp@latest` config. You'll still need to reload MCP afterward.
>
> **Or:** reply **add playwright mcp** if it is missing entirely.
>
> Skipping live checks with `static-only` isn't a fit for new or conversion interactive paths.

Never edit `mcp.json` until the author agrees. Never claim MCP is ready until `GetMcpTools` for `user-playwright` shows usable browser tools (and a quick navigate smoke succeeds when diagnosing "broken").

---

## Two browsers (live path)

| Browser | Who | Purpose |
|---|---|---|
| **Playwright** (MCP) | Agent (+ author Okta login) | Required DOM existence checks |
| **Normal browser** | Author | Optional Block Editor (`walk-me` only) |

DOM exists ≠ Show me / Do it works. Reviewers still run full Block Editor smoke on the PR.

---

## Playwright DOM (required)

After author replies `ready` at the login pause:

For each interactive milestone in scope (path order):

1. Start URL: first `on-page:/path` in milestone blocks, else path manifest `startingLocation` (same as [review milestone start URL](../review-learning-path/reference-checks.md#milestone-start-url)).
2. Navigate on `{learn_host}`.
3. For each `reftarget`, record: `exists` / `missing` / `below-fold` / `state-dependent`.
4. Do **not** stop for author confirmation between milestones. One short progress line is enough; save the summary for the results menu.

Respect [live testing prerequisites](../review-learning-path/reference-checks.md#live-testing-prerequisites-phase-2) (stack state, credential-gated UI). Prefer documenting stack gaps over false "missing selector" on the wrong stack.

Apply [selector decision tree](../review-learning-path/reference-checks.md#selector-decision-tree) when promoting findings after live results.

---

## Block Editor (opt-in)

Authors are expected to dogfood while writing. Do **not** force a per-milestone interrogation by default.

### Prompt (once, after Playwright)

> Have you already smoke-tested this path in Block Editor (Show me / Do it)?
>
> Reply **`already-tested: <short notes>`** if yes (stack + anything flaky).
> Reply **`walk-me`** if you want a guided per-milestone check now.
> Reply **`skip-smoke`** to continue without recording Block Editor evidence.

### Local import (`walk-me` only)

No PR yet, so **do not** use the PR review tool.

1. Open `{learn_host}/plugins/grafana-pathfinder-app?dev=true` in the normal browser.
2. **?** → Debug → **Block Editor**.
3. Import `{path_dir}/{milestone}/content.json` from the local checkout.
4. Open the derived start URL; run every **Show me** and **Do it**.

### Guided loop prompts

For each scoped milestone:

> **Milestone {i} of {M}: `{milestone-id}`**
>
> 1. Import the local `content.json`
> 2. Open `{derived_start_url}`
> 3. Run every **Show me** and **Do it**
>
> **While you run it, watch for:** wrong highlights, Do it that no-ops or errors, steps that never unlock, and fake step numbers (intro prose or "You'll…" lines counted as steps).
>
> **Your turn:** Reply **pass**, **fail step N -** *what happened*, or **N/A -** *reason*.

Do **not** give the fake-step-number glance its own numbered setup step. Keep it inside the short **While you run it, watch for** line.

Record in state `pathfinder.{milestone-slug}`.

---

## Milestone scope

| `path_type` | Scope |
|---|---|
| **new** / **conversion** | Every interactive milestone in path `milestones` |
| **update** | Touched interactive milestones first; full path on request |

Skip terminal-only / external-CLI milestones for DOM and walk-me unless the author asks.
7 changes: 7 additions & 0 deletions .cursor/skills/preflight-learning-path/claim-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Claim check (preflight pointer)

**Canonical policy:** [../review-learning-path/claim-check.md](../review-learning-path/claim-check.md)

Shared by `/preflight-learning-path` and `/review-learning-path-pr`. Do not maintain a second verdict table here.

When preflight runs the static pass, follow that file. Write the report to `.cursor/lp-preflight-state/{slug}-claim-check.md` and use the **Preflight (results menu)** chat section.
137 changes: 137 additions & 0 deletions .cursor/skills/preflight-learning-path/frontend-selector-pr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Frontend selector PR (preflight)

Walk an author through adding a stable `data-testid` upstream when Pathfinder needs one and the DOM has no good selector.

**Canonical example:** [grafana/grafana-cmab-app#1795](https://github.com/grafana/grafana-cmab-app/pull/1795) (Add `data-testid` selectors to Usage page components).

Use that PR as the model for:

- Small, uniform component changes (testids only)
- Plain kebab-case names matching the product area
- PR title/body that explains Pathfinder authoring needs stable selectors
- Friendly, low-ceremony tone

Do not paste the whole #1795 diff. Link it and mirror the pattern. No em dashes in drafted PR bodies.

---

## When to enter

Trigger when live checks show a step needs a durable selector and:

- No `data-testid` / strong semantic attribute exists in the DOM, and
- Live Playwright or walk-me failed on that step (or the author wants a proactive testid anyway), and
- They reply **`frontend`** at the results menu or ask after package fixes

At the results menu, treat this as a **needs-frontend** finding: lead with **frontend**, not **fix N**. A package-only `reftarget` tweak is not the real fix. Only offer a temporary weak selector in the guide if the author explicitly asks, and label it as brittle.

If live passed with a justified `:contains()` and no stable selector exists, that stays Internal in review terms. Offer this walkthrough as an optional improvement, not a Fix-before-PR demand, unless Playwright/walk-me failed on that step.

---

## Walkthrough (checkpointed)

These pauses are intentional (author must approve name, repo, draft, push). Announce **Frontend selector (step X of 5)** at each stop. One ask per message. Do not call this "Phase 5" in author chat.

### 1. Confirm the element

From Playwright: URL, visible label, current weak selector, screenshot or DOM snippet if helpful.

Propose a `data-testid` (plain kebab-case, product-area prefix, matching existing testids in that app when present).

> **Frontend selector (step 1 of 5)**
>
> **Element that failed live**
> - Page: {url or page name}
> - Control: {visible label}
> - Guide selector today: `{reftarget}`
>
> **Proposed `data-testid`:** `{proposed-name}`
>
> **Your turn:** Reply **yes** if that name is fine, or suggest a different kebab-case name.

**Wait for:** author OK on the name (or edits).

### 2. Locate owning source

- Default core UI: `grafana/grafana`
- Plugin app pages (`/a/grafana-*-app/...`): that plugin repo (as #1795 did for CMAB)

Use workspace clones or GitHub search. Do **not** invent file paths.

> **Frontend selector (step 2 of 5)**
>
> Best guess for owning source: `{repo}` ({why}).
>
> Next I will confirm the exact file(s). I will not invent paths.
>
> **Your turn:** Reply **yes** if `{repo}` looks right, or name a different repo.

**Wait for:** confirm repo + file(s).

### 3. Draft the change

- Minimal diff: add `data-testid` (and wire through component props if needed)
- Match local naming conventions
- Draft PR title + body in the style of #1795 (Pathfinder needs stable selectors; keep scope tight)

Example body shape (adapt; do not copy blindly):

```markdown
Hey folks, I was building a Pathfinder guide and noticed some UI elements lacked stable selector IDs.

Adds `data-testid` attributes to {components} following the existing kebab-case naming on this page. These selectors are needed for interactive Pathfinder guides, which prefer `data-testid` over text or class-based targeting.

Example pattern: https://github.com/grafana/grafana-cmab-app/pull/1795
```

> **Frontend selector (step 3 of 5)**
>
> Draft change: add `{testid}` on {component summary}. Testids only; no behavior change.
>
> **Title:** {title}
>
> **Body:** (show draft)
>
> **Your turn:** Reply **yes** to approve, or say what to change.

**Wait for:** author approval of the draft.

### 4. Open the PR

1. Confirm `gh` auth and write access
2. Create branch, commit, push (**ask before push**)
3. `gh pr create` with the approved title/body
4. Follow existing grafana org repo norms; do not change repo visibility

> **Frontend selector (step 4 of 5)**
>
> Ready to open the PR in `{repo}` with the approved title/body.
>
> **Your turn:** Reply **yes** to push and create the PR, or **hold** to stop here.

Record `frontend_pr_url` in preflight state after create.

### 5. Update the guide selector

Update the milestone `reftarget` to the new testid **only after** the author confirms the frontend change is available on their test stack.

Until then: keep a temporary justified fallback if needed, and note the upstream PR URL in readiness / Open PR with notes.

> **Frontend selector (step 5 of 5)**
>
> Frontend PR: {url}
>
> When `{testid}` is on your test stack, we can update `{milestone}` to `[data-testid="{testid}"]`. We should not change the guide before that lands.
>
> **Your turn:** Reply **update guide** when the testid is available, or **done** to leave the guide as-is for now.

---

## Anti-patterns

- Giant refactors or drive-by UI changes in the testid PR
- Inventing component paths
- Updating guide JSON to a testid that is not on the test stack yet without saying so
- Treating a missing upstream testid as something to "fix" only inside `interactive-tutorials` when the DOM has no stable hook
- Offering bare **fix N** at the results menu as if a guide edit adds the testid
Loading
Loading