---
name: demonstrate-issues
description: >
  Run a live bug-demonstration capture session before filing GitHub issues.
  The user drives the browser and narrates bugs one after another ("see
  this — clicking X should do Y but does Z"); this skill captures each demo
  (snapshot + screenshot + description + environment context) without
  investigating, only after the user signals the session is over does it
  investigate root causes, then only after the user reviews the write-ups
  does it file issues. Use when asked to "demonstrate some bugs", "show you
  issues before filing them", or via `/demonstrate-issues`. Never fixes
  anything — it ends at filing GitHub issue(s); any actual fix is separate,
  later `dev-issue` work.
allowed-tools: Read, Glob, Grep, Bash, PowerShell, mcp__playwright__browser_navigate,
  mcp__playwright__browser_navigate_back, mcp__playwright__browser_click,
  mcp__playwright__browser_type, mcp__playwright__browser_fill_form,
  mcp__playwright__browser_select_option, mcp__playwright__browser_hover,
  mcp__playwright__browser_press_key, mcp__playwright__browser_wait_for,
  mcp__playwright__browser_snapshot, mcp__playwright__browser_take_screenshot,
  mcp__playwright__browser_console_messages, mcp__playwright__browser_network_requests,
  mcp__playwright__browser_evaluate, mcp__playwright__browser_resize,
  mcp__playwright__browser_tabs, mcp__playwright__browser_close,
  mcp__playwright__browser_handle_dialog, mcp__claude-in-chrome__tabs_context_mcp,
  mcp__claude-in-chrome__tabs_create_mcp, mcp__claude-in-chrome__tabs_close_mcp,
  mcp__claude-in-chrome__navigate, mcp__claude-in-chrome__computer,
  mcp__claude-in-chrome__read_page, mcp__claude-in-chrome__find,
  mcp__claude-in-chrome__form_input, mcp__claude-in-chrome__get_page_text,
  mcp__claude-in-chrome__read_console_messages,
  mcp__claude-in-chrome__read_network_requests, mcp__claude-in-chrome__resize_window
---

# Demonstrate Issues (HMIS)

**🚨 TOOLS: Playwright MCP is the default (`mcp__playwright__*`).** Every
step below is written for Playwright's plain tool names (`browser_navigate`,
`browser_snapshot`, `browser_take_screenshot`, ...) — don't reach for
claude-in-chrome out of general habit. The `mcp__claude-in-chrome__*` tools
in the `allowed-tools` frontmatter exist **only** for the discussed fallback
below, not for casual use. If Playwright genuinely isn't usable in the
environment (MCP server unavailable, the browser won't launch, etc. — a
headless box the user simply can't watch is *not* such a case; drive it
click-by-click per step 2), **discuss it with the user first** rather than
silently switching — they may prefer to solve the Playwright-side blocker
(e.g. relay screenshots) over falling back. Only switch tools after they
say so.

**If the claude-in-chrome fallback is approved:** use the
`mcp__claude-in-chrome__*` tools for navigation, page inspection, and form
input; don't call Playwright-only tools. Two steps have no fallback
equivalent — handle them explicitly rather than skipping silently:

- **Screenshot capture (step 3):** take the shot with
  `mcp__claude-in-chrome__computer`; if it can't be written into the
  session's `tmp/` subfolder, ask the user to save/relay the image, and if
  even that isn't possible record the demo's evidence as "screenshot
  unavailable (claude-in-chrome fallback)".
- **Native `confirm()`/`alert()` (step 3, "Native JS dialogs mid-demo"):**
  there is no `browser_handle_dialog` equivalent and the dialog blocks the
  extension — pause and ask the user to resolve it manually in their
  browser, then continue.

**🚨 LOGIN: ask, don't assume.** At step 2, once the login page is open, ask
the user directly whether they want to log in themselves or have Claude log
in and proceed — don't silently default to either one. Only look up
credentials or drive the login form after they've said they want Claude to
do it.

Structurally separates three phases with hard stops between them:
**demonstrate** → **investigate** → **file**. This exists to prevent acting
on a partial picture — jumping from "here's a bug" straight to code before
every bug the user wants to show is on the table, and before the full
picture of each one is understood.

## Non-goals

- **No development or fixing ever happens inside this skill.** It ends at
  filing GitHub issue(s). Any actual fix is separate, later work — hand the
  filed issue number(s) to `dev-issue`.
- Does not change the behavior of `dev-issue`, `playwright-e2e`, or any
  other skill — they keep auto-logging in with Playwright and driving the
  browser themselves by default, no question asked. The ask-before-login
  and discuss-before-tool-fallback rules below are local to this skill
  only.

## Reference docs

- [Playwright E2E Testing Workflow](../../../developer_docs/testing/playwright-e2e-workflow.md) —
  PrimeFaces widget commit patterns, dialog handling, the §1 login/department
  gate, the §2 **never-navigate-by-URL** rule (the user drives here, so follow
  their menu path and record it — never "shortcut" to a page by URL when
  reproducing later; a URL-loaded page renders against uninitialised session
  state and yields a bug report that isn't real), and the §8/§8a
  screenshot-privacy-check convention this skill reuses for evidence capture.
- [Playwright MCP Guide](../../../developer_docs/tools/playwright-mcp-guide.md) —
  generic MCP tool mechanics (clicking, dropdowns, common errors).

## 1. Deploy check (environment-agnostic — never hardcode names/ports)

- Resolve the WAR path deterministically each run: prefer `<finalName>` from
  `pom.xml` over globbing. Only fall back to `target/*.war` if `pom.xml`
  doesn't resolve one, and if that glob matches more than one file, treat it
  as the "ambiguous working tree state" case below rather than guessing
  which one to use — never assume a fixed filename like `rh-3.0.0.war`, the
  version differs across checkouts/machines.
- Resolve the Payara **admin port** and the app's **HTTP port** from the
  local credentials file for this machine (`C:\Credentials\credentials.txt`
  or equivalent) — never assume the defaults (4848 / 8080). Multiple Payara
  installs can coexist on one box on non-default ports (see
  [playwright-e2e-workflow §27](../../../developer_docs/testing/playwright-e2e/environment-db.md#27-multi-payara-machines-asadmin-without---port-may-hit-another-users-domain)).
  **Don't `Read` the whole credentials file into context** — it may hold
  passwords/tokens alongside the ports. Extract just the port line(s) (e.g.
  `grep`/`findstr` for the admin-port/http-port keys) and use only those
  values.
- Resolve the deployed **context root / URL path** via
  `asadmin --port <admin-port> list-applications` rather than assuming
  `/rh` — different instances are deployed as `/rh`, `/hmis`, `/coop`, etc.
- Compare the resolved WAR's build time against `git log -1` (HEAD) — mtime
  alone doesn't prove the WAR was built from HEAD, so also check
  `git status --short` and record the current commit SHA alongside it. If
  the running app is behind HEAD, rebuild (`mvn clean package -DskipTests`,
  JDK 11) and redeploy automatically using the resolved admin port/app name
  — see [§0a](../../../developer_docs/testing/playwright-e2e-workflow.md#0a-rebuild-and-redeploy-local-code-changes-before-testing).
  Only pause and ask if the build fails or the working tree state is
  ambiguous (e.g. uncommitted changes on a file that affects the build, or
  more than one candidate WAR as above).

## 2. Open login page, then ask how to handle login

- `browser_navigate` to the resolved login URL.
- Ask the user whether they want to log in and select department themselves
  (e.g. in a visible Playwright-launched browser window, or by directing
  Claude click-by-click if the browser isn't visible to them), or whether
  they'd rather Claude look up credentials and log in/select department on
  its own, same as `playwright-e2e`'s normal login flow.
- Don't assume either way, and don't look up or enter credentials before
  they've said Claude should.
- **Wait until login *and* department selection are actually complete before
  starting the demonstration loop.** If the user handles it, pause until
  they confirm both steps are done (or the browser clearly shows the
  authenticated post-department landing page). If Claude handles it, proceed
  only once that landing page is reached. The shared workflow requires a
  selected department before any inner-page action — continuing early makes
  the demos run against unauthenticated / wrong-department state and produce
  false failures.

## 3. Demonstration loop

- The user narrates/points out each issue in chat while driving the browser
  themselves (e.g. "see this — clicking X should do Y but does Z").
- On the user's cue, capture:
  - an accessibility snapshot (`browser_snapshot`)
  - a screenshot (`browser_take_screenshot`) into the project `tmp/`
    folder, one subfolder per session
  - the user's description, verbatim
  - auto-detected environment context: department and user **role** read
    from the page header (not the raw account/login name), current git
    branch + commit SHA (`git rev-parse --abbrev-ref HEAD` / `git rev-parse
    HEAD`), timestamp
- **Pure capture only at this stage — no code investigation yet.** Confirm
  each capture ("Got it, recorded as demo #N") and wait for the next cue or
  the end signal.
- Multiple issues can be demonstrated in one session, back to back.

### Content-free capture cues

If the cue to capture carries no description at all (e.g. just "capture", or
"check playwrite"), don't capture speculatively and ask afterward what it
was for — ask for the one-line description. If the user provides it in the
same turn, capture the demo; otherwise wait and do not capture until the
description is available.

### Forward-looking narration vs a firm bug cue

Distinguish "I'm about to show you X" (scene-setting for a demo that hasn't
happened yet) from "see this, X is broken" (the actual cue). Narration that
describes what's coming next is not itself a capture cue — wait for the
concrete bug before recording anything.

The same non-capture handling applies to plain navigation/setup
instructions interspersed between demos — "go to inpatient dashboard",
"click room details", "now click admit" — where the user is just directing
the browser to the next thing worth showing, with no bug implied. Follow
the instruction, but don't treat it as a capture cue on its own; wait for
the user to actually point out a problem.

### Keep a running navigation breadcrumb, even when not capturing

The user is driving the browser, not you — when they say "I'm on page X"
or narrate a click, you often can't reconstruct that path from code (it may
depend on session state: a selected patient, department, in-progress form)
and the user may not be able to repeat the exact clicks on request. Losing
the trail forces them to redo manual navigation, which defeats the point of
letting them drive.

So on every non-capture navigation/narration turn, silently note (don't
announce it — this isn't a capture, just a running log) the menu
path/button clicked and, if visible from context already in front of you,
the resulting page's title and URL. Don't spend an extra `browser_snapshot`
call purely to fill in this log — use whatever page context you already
have (the last snapshot/screenshot taken, or the user's own words). If a
hop's destination truly isn't inferable that way, leave it unlabeled rather
than interrupting the flow to ask; a gap in the trail is better than
breaking the user's narration to ask a tracking question.

**Sanitize before storing, not just before filing.** URLs and page
titles/breadcrumbs routinely carry patient identifiers (BHT number, PHN,
patient name) even at this scratch stage — strip or generalize those as
you log each hop (e.g. `BHT/56757` → `[selected admission]`). Don't rely
on the step-7 filing-time redaction pass alone for this: by then the trail
has already been promoted into "Steps to reproduce" text, so anything left
unredacted here flows straight into the draft issue body.

Keep only the trail since the last completed capture (or session start,
whichever is more recent), most recent step last — this is scratch
context, not a demo record, and applies to whatever workflow is being
demonstrated, not just inpatient/admission ones. When a demo is actually
captured — not merely cued; a content-free cue (previous section) leaves
the trail open while it waits for the required description — that trail
becomes the "Steps to reproduce" backbone for that demo. Clear it once the
capture is consumed, so a later demo in the same session doesn't inherit
an earlier demo's steps. Any trail still open at session end is simply
discarded.

If a capture already happened and the user later clarifies that demo #N was not
meant as a bug report (e.g. "no error in this page yet, just gathering
facts"), treat that as an explicit instruction to drop the prior capture —
whether that clarification arrives in the very next message or a later one:
acknowledge it ("Dropping demo #N — noted as context only") and exclude it
from the investigation/filing phases. Don't carry the ambiguity forward and
make the user re-resolve it during investigation.

### Native JS dialogs mid-demo

If a demo step triggers a native `confirm()`/`alert()` (e.g. clicking an
"Accept" or "Delete" button that pops a browser-native confirmation), the
page blocks until the dialog is resolved. Don't guess whether to accept or
dismiss — pause and ask the user explicitly which one they want, especially
if their reply is short or ambiguous. Once they've said which, call
`browser_handle_dialog` with `accept: true` or `accept: false` accordingly.

### When an element-targeted screenshot won't crop cleanly

`browser_take_screenshot`'s `element`/`target` params can return the wrong
region for a specific gridcell/badge/small element — most often after the
page has scrolled or re-rendered and the accessibility-tree ref has gone
stale. If that happens, fall back to a full-page screenshot and crop it
manually (e.g. PowerShell `System.Drawing`) using coordinates read off the
page's own layout description.

When computing crop coordinates this way, remember the screenshot PNG is in
**device pixels**, not the CSS pixels the accessibility snapshot reports
element positions in — on a machine with a >1x device pixel ratio the two
disagree by that ratio (e.g. a 2000px-wide described layout can produce a
3455px-wide PNG, a ~1.73x factor). Derive the scale as
`image_width / described_css_width` and multiply your target CSS
coordinates by it before cropping, or the crop will land on the wrong
region.

**HARD STOP** — do not read application code, form a root-cause hypothesis,
or otherwise start investigating any demo until the end signal in step 4.

## 4. End signal

The user says "that's all" (or equivalent) to end the demonstration loop.

## 5. Investigation phase

For each recorded demo: full codebase access is available (grep, read
controllers/JSF pages, `git blame`/`git log` on the relevant file, DB
queries if needed) to work out expected-vs-actual behavior and a root-cause
code pointer (file/line). Database queries are **read-only** and select only
the fields needed to confirm the root cause (same rule as
[playwright-e2e-workflow §6](../../../developer_docs/testing/playwright-e2e-workflow.md#6-verify-against-the-database));
keep raw query results — and especially patient data — out of the
transcript and out of draft/filed issue text.

Rhythm is flexible and assistant-judged: default to investigating all
recorded issues quietly and bringing finished write-ups back for batch
review (step 6), but switch to narrating findings live, issue-by-issue,
when that reads better for a given case — ask the user when genuinely
unsure which mode fits.

## 6. Discuss before filing

Present the **complete sanitized issue body** for each draft — not just
title/summary/root cause/grouping, but the full content from step 7
(environment, steps to reproduce, expected vs actual, root cause, and the
evidence/attachments after redaction) — together for the user's review.

Default is **one GitHub issue per demonstrated bug**, but if two demos seem
to share a root cause (or one demo should split into two issues), ask the
user before filing rather than deciding unilaterally. If the user asks for
every demo in the batch to be filed as a single combined issue, structure it
as one issue with a `## Part N` section per demo — each section keeping its
own full template (summary, environment, repro, expected/actual, root
cause, evidence) so the parts stay independently actionable/closeable via
checkboxes despite sharing one issue number. Ask the user if it's unclear
whether they want this per-section structure or a single merged narrative
instead.

**HARD STOP** — do not file anything until the user confirms the exact
final body and attachments for this batch.

## 7. File

One GitHub issue per confirmed bug (per the discussion in step 6), each
following a standard template:

- **Summary**
- **Environment** (branch/commit, department, user role, instance if
  relevant)
- **Steps to reproduce** — minimal and deterministic (strip anything not
  required to trigger the bug)
- **Expected** vs **Actual**
- **Root cause** — code file/line pointer, with a short explanation
- **Evidence** — inspect **every** captured artifact for identifiable data
  (patient names, NICs, phone numbers, financial details, etc.) before it
  goes anywhere near the issue: screenshots, accessibility snapshots, the
  user's verbatim description, environment context, and the assembled issue
  body text itself — not just screenshots. If clean, keep it; if it
  contains identifiable info, redact it, or ask the user how to handle it if
  clean redaction isn't straightforward.

  `gh issue create --body` is text-only — it cannot upload local
  screenshots. Publish screenshots through the existing wiki flow instead,
  same as every other HMIS skill: copy the sanitized images into
  `../hmis.wiki/images/`, commit and push the wiki, then embed the raw wiki
  URLs (`https://raw.githubusercontent.com/wiki/hmislk/hmis/images/<name>.png`)
  in the issue body — see
  [playwright-e2e-workflow §8](../../../developer_docs/testing/playwright-e2e-workflow.md#8-publishing-screenshot-evidence).

Before filing, re-read the assembled body against
[What May Go Into a GitHub Issue, PR, or Comment](../../../developer_docs/git/github-public-content-policy.md)
— the repo is public, so the body must carry no patient/doctor/staff names,
production record identifiers (bill/BHT/PHN numbers, entity IDs),
affected-record counts, production schema names, cutover dates or per-staff
statistics. A demo session collects exactly those things, so this pass is not
a formality.

File with `gh issue create --repo hmislk/hmis --title "<title>" --body-file
<file>` (use `--body-file` for the multiline body assembled above). Verify
the created issue — including that its embedded images render — before
removing the session's temporary screenshots from the project `tmp/`
folder.
