Testing safely¶
How non-developer builders test their work the same way developers do — without writing test code by hand, and without leaking real data into the test path.
The four layers¶
A change you make through the plugin should pass all four before promoting:
-
1 · Dry-run
/frappe-stack:build doctype Beneficiary --dry-runGenerates the JSON, runs validators, shows the diff against staging — does not POST. The same way a developer trial-runs a fixture before
bench migrate. -
2 · Seed test data
The
seeding-dataskill generates synthetic records via stock REST. Refuses real-shaped PII (real-looking Aadhaar / PAN / mobile patterns). Cleanup helper produces a ledger of created records for later removal. -
3 · Smoke-test
The
running-qaskill walks a manual checklist per blueprint type (DocType / Workflow / Dashboard / Report / Integration). Thetesteragent additionally runs any auto-generated FrappeTestCase tests viabench run-tests. -
4 · Pre-promote review
The
deployeragent runsreviewer(security + style) andtester(auto + coverage) in parallel before opening the PR. Reports are auto-commented on the PR before the rotation is tagged. Same standard a developer's PR has to meet.
Where each layer fires¶
%%{init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#F5E6DD',
'primaryTextColor': '#2E2E2E',
'primaryBorderColor': '#8B1E24',
'lineColor': '#9E2A2F',
'secondaryColor': '#E7C1AD',
'tertiaryColor': '#ffffff',
'fontFamily': 'Inter, system-ui, sans-serif',
'fontSize': '13px'
}
}}%%
flowchart LR
Idea[PM intent]
Dry["1 · Dry-run<br>--dry-run"]
Build["/frappe-stack:build"]
Seed["2 · Seed data<br>seeding-data skill"]
QA["3 · Smoke-test<br>running-qa skill<br>+ tester agent"]
Promote["/frappe-stack:promote"]
Review["4 · Pre-promote review<br>reviewer + tester<br>auto-commented on PR"]
PR{PR opens}
Idea --> Dry --> Build --> Seed --> QA --> Promote --> Review --> PR
classDef step fill:#F5E6DD,stroke:#8B1E24,stroke-width:1.5px,color:#2E2E2E,rx:10,ry:10
classDef cmd fill:#ffffff,stroke:#8B1E24,stroke-width:1.5px,color:#2E2E2E
classDef gate fill:#F28C38,stroke:#9E2A2F,stroke-width:1.5px,color:#ffffff
classDef plain fill:#ffffff,stroke:#D9B3A0,stroke-width:1px,color:#6B6B6B
class Dry,Seed,QA,Review step
class Build,Promote cmd
class PR gate
class Idea plain
Why this is dev-equivalent¶
A developer doing the same work would:
| Developer step | Plugin equivalent |
|---|---|
| Edit a fixture, eyeball the JSON | --dry-run shows the JSON + diff |
Run bench migrate on local |
/frappe-stack:build POSTs to staging |
Insert test rows via console / import-csv |
seeding-data skill |
Run bench run-tests --app <app> |
tester agent runs the same |
Run pre-commit (semgrep, lint) |
reviewer agent runs the same checks |
gh pr create, self-review, then request review |
/frappe-stack:promote does this and auto-comments the report |
git checkout <ref> && bench migrate to roll back |
/frappe-stack:rollback <ref> |
Same standards, same checks, different surface. The PM never writes Python; they get the same coverage gate.
The PII boundary¶
Test data must not look like real data. The plugin enforces this at three layers:
- Typing time. The
coach_user_prompt.pyUserPromptSubmit hook blocks real Aadhaar / PAN / Indian mobile patterns in PM prompts. - Seeding time. The
seeding-dataskill refuses to generate real-shaped PII even when asked. Synthetic Aadhaar starts with0000(real Aadhaar can't); synthetic phone never matches[6-9]\d{9}. - Pre-promote. The
revieweragent's semgrep rules catch any literal PII pattern that slipped through into a fixture or Server Script.
Failure modes¶
| Failure | What surfaces |
|---|---|
| Dry-run shows a destructive diff (e.g., a field would be removed and rows have data) | Refuses to proceed; PM has to acknowledge the data loss explicitly or change the design |
Seeding into a DocType with required Link to an empty linked DocType |
Refuses; surfaces "seed the linked DocType first" |
tester agent finds < 80% coverage on changed lines |
Build is not blocked, but the deployer's pre-promote checklist refuses without --emergency |
| Real PII pattern found in the seeded data ledger | Refuses; cleanup procedure runs to remove the contaminated rows |
Rollback target ref doesn't have a fixtures/app/ tree |
Refuses; surfaces "this commit predates the config-repo layout" |
Quick reference¶
# Try a design without committing to it
/frappe-stack:build doctype Beneficiary --dry-run
# Build for real
/frappe-stack:build doctype Beneficiary
# Fill it with synthetic data
(engineer agent loads seeding-data skill on demand)
# Run the QA checklist
(running-qa skill walks you through it; tester agent runs auto-tests)
# Pre-promote review (auto-runs inside /promote, but you can run it standalone)
/frappe-stack:review --since=origin/main
# Promote
/frappe-stack:promote
# If something goes wrong on staging, rewind
/frappe-stack:rollback HEAD~1