demo skill: look up routing and demo users in the project

Steps 2 and 4 carried copy-paste from another project (lib/hub_web/router.ex,
alias Hub.Accounts, /users/log-in with user[email]). A stale path there sends
the agent to a router that does not exist, and a guessed module alias fails at
run time.

Both are now generic instructions to read the project:

- route map: locate the router by searching for `use Phoenix.Router`, then read
  its scopes, pipelines and live_sessions to see what is public and what needs
  a session
- authentication: only when the route actually needs it; take credentials from
  documented demo accounts or the project's seeds, create a demo user through
  the project's own path (seeds, registration route, or the accounts function
  found by grep - never a guessed alias), and read the login route and form
  selectors off the router and rendered form

The port example keeps its concrete app/endpoint pair, now labelled as an
example with the grep that finds the right names, plus a note to use the
project's toolchain/build wrapper instead of bare `mix`.

make check green.
This commit is contained in:
Willem van den Ende
2026-10-26 21:26:19 +00:00
parent a0692056bc
commit 3eae3afcbb
+45 -30
View File
@@ -46,7 +46,7 @@ Build an understanding of what to demo from these sources (in priority order):
Explicit scenario (--scenario): If provided, use as primary guide. Explicit scenario (--scenario): If provided, use as primary guide.
Plan file: Read the plan's Goal, Acceptance Criteria, and completed Steps. Plan file: Read the plan's Goal, Acceptance Criteria, and completed Steps.
Recent commits: Run git log --oneline -15 and git diff main...HEAD --stat to identify changed files and commit messages. Recent commits: Run git log --oneline -15 and git diff main...HEAD --stat to identify changed files and commit messages.
Route map: Cross-reference changed files against known LiveView routes in the router (lib/hub_web/router.ex). Route map: Find the router yourself - do not assume a path. Search the project for its router (`grep -rn "use Phoenix.Router" lib/`; conventionally lib/<app>_web/router.ex), then read the scopes, pipelines and live_sessions to learn which routes the feature touches, which are public, and which require a logged-in user.
From these sources, produce a demo outline: From these sources, produce a demo outline:
@@ -58,60 +58,75 @@ From these sources, produce a demo outline:
If no plan exists and commits are ambiguous, ask the user for a brief description of what to demo. If no plan exists and commits are ambiguous, ask the user for a brief description of what to demo.
3. Resolve the dev port, then check the server 3. Resolve the dev port, then check the server
Never assume a port. The port lives in the project config: `app/config/dev.exs` Never assume a port. Read it from the project config, from the repo root:
sets `port: String.to_integer(System.get_env("PORT") || "8056")`, so `$PORT`
wins and the config default is the fallback. Ask the app, from the repo root:
DEMO_PORT=$(cd app && mise exec -- mix run --no-start -e \ DEMO_PORT=$(cd app && mix run --no-start -e \
'IO.puts(Application.get_env(:firehose, FirehoseWeb.Endpoint)[:http][:port])') 'IO.puts(Application.get_env(:firehose, FirehoseWeb.Endpoint)[:http][:port])')
DEMO_BASE_URL="http://localhost:${DEMO_PORT}" DEMO_BASE_URL="http://localhost:${DEMO_PORT}"
curl -s -o /dev/null -w "%{http_code}" "$DEMO_BASE_URL/" curl -s -o /dev/null -w "%{http_code}" "$DEMO_BASE_URL/"
Use `Application.get_env/2`, not `FirehoseWeb.Endpoint.config(:http)`: with Adapt that command to the project: find the app/endpoint pair in `config/*.exs`
`--no-start` the endpoint's ETS table does not exist and `config/1` raises. (`grep -rn "Endpoint," config/`) and use the same names. If the config reads the
port from the environment, the value above already reflects it. Do not resolve
the port with `<Endpoint>.config(:http)`: with `--no-start` the endpoint's ETS
table does not exist and it raises.
If the project pins a toolchain or wraps builds, use its wrapper for every
command below (`mise exec -- mix ...`, asdf shims, or its `make` targets - check
AGENTS.md/README first). Bare `mix` is not a safe assumption.
If the server is not reachable: If the server is not reachable:
The Phoenix dev server is not running. Start it now? The Phoenix dev server is not running. Start it now?
mkdir -p .tmp && (cd app && PORT=$DEMO_PORT mise exec -- mix phx.server \ mkdir -p .tmp && (cd app && PORT=$DEMO_PORT mix phx.server \
> ../.tmp/phx-demo.log 2>&1 &) > ../.tmp/phx-demo.log 2>&1 &)
Then poll `$DEMO_BASE_URL` for up to 10 seconds. If it still fails, read Then poll `$DEMO_BASE_URL` for up to 10 seconds. If it still fails, read
`.tmp/phx-demo.log`: a bundle error about `highlight.js` (or any module) means `.tmp/phx-demo.log`: an error about an unresolvable JS module means the
`app/assets/node_modules` is missing - run `make -C app assets` (root project's JS packages are not installed - run its assets install step (in this
`make deps` does it too). Only when the server really cannot come up, proceed repository `make -C app assets`, which root `make deps` also runs). Only when
with backend-only evidence (skip all browser screenshots) and note the the server really cannot come up, proceed with backend-only evidence (skip all
limitation in the demo document. browser screenshots) and note the limitation in the demo document.
Use `$DEMO_BASE_URL` for every URL below - there is no default port to fall Use `$DEMO_BASE_URL` for every URL below - there is no default port to fall
back on. back on.
4. Handle authentication 4. Handle authentication (only if the route needs it)
The app requires authentication for LiveView routes. Before capturing UI screenshots: Decide this from the project, not from this file. If every page you need is
public, skip this step. A route needs a session when the router found in step 2
puts it inside a `pipe_through` that requires a logged-in user, or inside a
`live_session` guarded that way.
Ensure a demo user exists: When you do need a session, read each part from the project instead of assuming
it:
mix run -e " - Credentials: check README, AGENTS.md, docs and the project's seeds
alias Hub.Accounts (`priv/repo/seeds.exs`, a `mix demo`-style task). Use documented demo
case Accounts.get_user_by_email(\"demo@example.com\") do credentials if they exist - never invent them.
nil -> Accounts.register_user(%{email: \"demo@example.com\", password: \"demodemo1234\"}) - Demo user: if nothing is documented, create one through the project's own
user -> {:ok, user} path, in this order: run its seeds; use its registration route; call the
end accounts/context function you find by searching for it (`grep -rn
" "get_user_by_email\|register_user\|create_user" lib/`). Copy the exact module,
function and field names from the source; do not guess an alias.
- Login route, form fields and submit button: read them off the router and out of
the rendered form (`rodney html form` or `rodney ax-tree`) rather than
assuming a path or an input name.
Log in via rodney: Then drive the form with the selectors you just read:
rodney start rodney start
rodney open "$DEMO_BASE_URL/users/log-in" rodney open "$DEMO_BASE_URL<login-route>"
rodney wait "input[name='user[email]']" rodney wait "<email-input-selector>"
rodney input "input[name='user[email]']" "demo@example.com" rodney input "<email-input-selector>" "<email>"
rodney input "input[name='user[password]']" "demodemo1234" rodney input "<password-input-selector>" "<password>"
rodney click "button[type='submit']" rodney click "<submit-selector>"
rodney waitidle rodney waitidle
If login fails, warn and proceed with backend-only evidence. Confirm the session took - `rodney url` should have left the login route, and
the page should show the user (name, avatar, menu). If login fails, warn, note it
in the demo document, and proceed with backend-only evidence.
5. Initialize the demo document 5. Initialize the demo document
Slugify the feature name (lowercase, hyphens, no special chars). Then: Slugify the feature name (lowercase, hyphens, no special chars). Then: