test-qa — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited test-qa (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Perform full QA testing of any webapp through browser MCP tools, adopting the mindset of a senior QA engineer preparing an app for production release. This is NOT a simple page-navigation monkey test — it is controlled, intelligent, user-story-driven testing that covers CRUD operations, data pipeline integrity, UX quality, and edge cases.
Before ANY browser interaction, read the `protocol-browser-anti-stall` skill and apply its rules to every step — especially Rule 0 (manual & headed, never scripted). That skill lives at ~/.cursor/skills/protocol-browser-anti-stall/SKILL.md. Also read references/playwright-session-coordination.md in that folder — shared browser, tab claiming, persisted login.
Manual & headed, never scripted. Drive a visible browser one real action at a time with the individualbrowser_*tools.browser_evaluate/browser_run_code_unsafeare inspection-only — never use them to click, type, or navigate. Do not write*.spec.tsor runnpx playwright test; experience the app, don't automate past it.
Test as a real user, think as an engineer. Navigate like someone who just opened the app for the first time. Inspect like someone who knows what's under the hood.
Every mutation must be verified end-to-end. Creating, updating, or deleting something is not "tested" until you confirm the change persisted in the UI after a page refresh AND (if DB access available) in the database.
Evidence for every finding. Every bug report needs: screenshot, console output, network request, and reproduction steps. "It looked broken" is not a finding.
Clean up after yourself. If you created test data during CRUD testing, delete it at the end. Leave the app in the state you found it.
No hardcoded assumptions. Read the codebase to discover pages, entities, and features. Never assume a route exists without confirming it in the source code.
Before opening the browser, understand the app from its source code.
Read the dependency manifest:
package.json → Node/JS/TS (framework, UI lib, auth, ORM, state mgmt)
requirements.txt → Python
pyproject.toml → Python
Cargo.toml → Rust
go.mod → GoExtract and record:
scripts.dev in package.json (usually 3000, 3001, 5173, 5174)Scan the file system for page/route definitions:
| Framework | Scan Pattern |
|---|---|
| Next.js App Router | app/**/page.tsx or app/**/page.js |
| Next.js Pages | pages/**/*.tsx (excluding _app, _document) |
| Remix | app/routes/**/*.tsx |
| SvelteKit | src/routes/**/+page.svelte |
| Nuxt | pages/**/*.vue |
| React Router (SPA) | Grep for <Route or createBrowserRouter in source |
| Django | urls.py files |
| Rails | config/routes.rb |
For each route, note:
/words, /profile, /settings)/grammar/[slug], /culture/[id])Look for entity definitions:
| Source | Where |
|---|---|
| Supabase migrations | supabase/migrations/*.sql — table definitions, RLS policies |
| Prisma schema | prisma/schema.prisma — models, relations |
| Drizzle schema | drizzle/schema.ts or src/db/schema.ts |
| TypeScript types | types/*.ts, **/types.ts — interfaces for data entities |
| API routes | app/api/** — what CRUD endpoints exist |
| Feature files | features/*/ — feature-specific services, hooks, components |
For each entity, note: name, key fields, CRUD capabilities, relationships.
Search for:
createClient for Supabase, NextAuth, ClerkProvider, Auth0Provider)signIn, login, authenticate).env.local, .env.test, .env.example, README)If the project has README files in feature directories (@_*-README.md, docs/, etc.), read them to understand expected behavior and business rules.
Produce a structured summary before proceeding:
APP DISCOVERY:
- Framework: [name + version]
- Dev server: http://localhost:[port]
- Auth: [provider + method]
- Test account: [email / password, or "none found — ask user"]
- Routes discovered: [count]
- Public: [list]
- Auth-required: [list]
- Dynamic: [list with param patterns]
- Data entities: [list with CRUD capabilities]
- API endpoints: [count]Check the terminals folder for active dev server processes:
npm run dev, pnpm dev, next dev, etc.browser_tabs → list; read .playwright-mcp/session.json if present.select the auth tab from session.json, or new with the dev URL — do not hijackanother agent's tab.
browser_navigate → root URL (e.g., http://localhost:3000)
browser_wait_for → 2s
browser_snapshot → verify content rendered
browser_take_screenshot → baseline screenshot
browser_console_messages → capture any startup errors
browser_network_requests → capture initial API callsIf the page is blank after 3 incremental wait cycles (6s total), report a blocker.
Follow protocol-browser-anti-stall/references/playwright-session-coordination.md.
.playwright-mcp/auth/<host>.json via browser_run_code_unsafe if it exists..env.test / README (never paste secrets in chat).wait with incremental snapshots; then save storage state + session.json.
If auth is impossible, mark auth-required pages as BLOCKED and test only public pages.
After login (or on the public home page):
BASELINE:
- URL: [current URL]
- Console errors: [count — list if any]
- Network failures: [count — list if any]
- Visible content: [brief description]
- Screenshot: [reference]For EVERY route discovered in Phase 0b, do the following:
browser_navigate to the pagebrowser_take_screenshot for visual evidencebrowser_console_messages — record errors and warningsbrowser_network_requests — record API calls, failures, timing| Classification | Signals |
|---|---|
| CRUD page | Has forms, edit buttons, delete buttons, data tables |
| Display page | Shows data but no mutation controls (dashboards, profiles) |
| Settings page | Has toggles, selects, save buttons for preferences |
| Auth page | Login, register, forgot password forms |
| Static page | No dynamic data (about, terms, privacy) |
| Navigation hub | Links to child pages (home, index pages) |
For each page, immediately flag:
| Check | What to Look For |
|---|---|
| Dead page | Page returns 404, error boundary, or blank screen |
| Console errors | JavaScript errors, failed assertions, React errors |
| Network failures | 4xx/5xx responses, CORS errors, timeouts |
| Missing content | "undefined", "null", "NaN", "[object Object]" visible in text |
| Mock data | Placeholder text ("Lorem ipsum", "TODO", "test", "example@") that should be real |
| Dead buttons | Buttons that have no onClick or navigate nowhere (detect via snapshot inspection) |
| Missing metadata | No page title (document.title empty or generic), no description |
| Loading stuck | Spinner or skeleton that never resolves (after 6s) |
| Empty state | No data AND no helpful empty-state message |
| Broken images | Image elements with no src, broken src, or error fallback showing |
| Overflow | Text or elements overflowing their containers (visible in screenshot) |
After crawling all pages, produce:
FEATURE MAP:
- CRUD pages: [list — with which entity and which operations]
- Forms found: [list — page + form purpose]
- Data displays: [list — tables, lists, cards, charts]
- Interactive elements: [buttons, toggles, dropdowns per page]
- Search/filter: [which pages have search or filter controls]
- Settings: [which preferences are configurable]
- Dead buttons found: [list with page + element description]
- Pages with errors: [list]Based on the feature map, generate user stories. These are NOT predefined — they are derived from what the app actually contains.
#### Category A: First Impression
"As a first-time visitor, I open the app and try to understand what it does."
Steps:
#### Category B: Core User Journey
Identify the app's primary purpose from Phase 0 (e.g., language learning, project management, e-commerce, social network). Generate a story that walks through the main flow:
"As a [user type], I want to [primary action] so that [value]."
Steps: Follow the app's main flow from start to finish.
#### Category C: CRUD Lifecycle (per entity)
For each data entity discovered:
"As a user, I create a [entity], verify it appears, edit it, verify changes, delete it, verify removal."
Steps:
QA-TEST- for easy cleanup)#### Category D: Navigation Completeness
"As a user, I can reach every page from the navigation and never hit a dead end."
Steps:
#### Category E: Search and Filter (if applicable)
"As a user, I search for something and get relevant results."
Steps:
#### Category F: Error Handling
"As a user, I make mistakes and the app guides me."
Steps:
#### Category G: Settings and Preferences
"As a user, I change my preferences and they persist."
Steps:
For each CRUD-capable entity, execute the lifecycle test.
browser_snapshotQA-TEST-[field]-[timestamp]browser_take_screenshot before submitting (evidence of input)browser_network_requests — verify the API call succeeded (2xx response)browser_snapshot — verify success feedback (toast, redirect, confirmation)browser_take_screenshot — evidence of success stateRecord the created item's identifying info (ID, name, URL) for subsequent steps.
browser_snapshot — find the created item in the listbrowser_take_screenshot — evidencebrowser_take_screenshot — evidence of changes before savebrowser_network_requests — verify the update API call succeededbrowser_navigate to same URL) and verify changes persistedbrowser_take_screenshot — evidence before deletionbrowser_network_requests — verify the delete API call succeededFor each form, also test:
<script>alert('xss')</script>, '; DROP TABLE, emoji, UnicodeAfter each mutation (create/update/delete):
browser_network_requests — was the API call made? What status code?browser_navigate to the same page, is the mutation still visible?CallMcpTool(server: "plugin-supabase-supabase", toolName: "execute_sql", arguments: {
"project_id": "<PROJECT_ID>",
"query": "SELECT * FROM <table> WHERE <identifying_column> LIKE 'QA-TEST-%' ORDER BY created_at DESC LIMIT 5"
})Pipeline failures to detect:
Assess each page against design-award quality standards.
| Check | How to Verify |
|---|---|
| Consistent spacing | Screenshot — no irregular gaps or cramped areas |
| Typography | No mixed font sizes where they should match, no orphaned headings |
| Truncation | Text truncated with ellipsis where appropriate, not clipped |
| Image loading | All images render, no broken image icons |
| Icons | All icons render (no missing icon squares or fallback text) |
| Dark mode | If supported: toggle and verify all components adapt, no white flashes |
| Responsive | Test at 1280px, 768px, 375px — layout adapts without breaking |
| Check | How to Verify |
|---|---|
| Dead buttons | Click every button. Does it do something? |
| Form labels | Every input has a visible label or accessible name |
| Loading states | Trigger data fetches — is a loading indicator shown? |
| Success feedback | After mutations — toast, confirmation, or visual change? |
| Error feedback | After failures — is the error message helpful and visible? |
| Disabled states | Are disabled elements visually distinct? Is the reason clear? |
| Focus management | After modal close or form submit, is focus moved appropriately? |
| Check | How to Verify |
|---|---|
| Page titles | document.title — is it descriptive and unique per page? |
| Active nav state | Current page highlighted in navigation? |
| Dead ends | Any page with no way to navigate forward or back? |
| Empty states | Pages with no data — do they show a helpful message? |
| 404 page | Navigate to /nonexistent-page — is the 404 page helpful? |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.