@qaping/cli 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/qaping +1 -1
- package/docs/QA-PLAN-FORMAT.md +6 -3
- package/package.json +1 -1
- package/skill/qaping/SKILL.md +107 -40
package/bin/qaping
CHANGED
|
@@ -43,7 +43,7 @@ function resolveKitDir() {
|
|
|
43
43
|
const RULE_BODY = `This machine has qaping: automatic QA for games — real human playtesters play the developer's builds on their own hardware and report back, and the coding agent runs the whole loop.
|
|
44
44
|
Whenever the user asks to set up QA for a game, run QA on a patch, check whether a change broke anything, or playtest a game or build, load the qaping skill and follow it — it owns authoring/maintaining QA-PLAN.md in the game repo and the per-patch run.
|
|
45
45
|
Builds ship with \`qaping publish-build <game.zip> --platform windows|macos\`; the printed /b/<slug> URL is what a round is filed against (store-delivered games file with their Steam/TestFlight/App Store URL instead).
|
|
46
|
-
The MCP tools are qaping_playtest (file a round with real human playtesters), qaping_results (fetch a finished round, free) and qaping_wait (continue a pending round —
|
|
46
|
+
The MCP tools are qaping_playtest (file a round with real human playtesters), qaping_results (fetch a finished round, free) and qaping_wait (continue a pending round — on pending, spawn a background task that loops qaping_wait and keep working; foreground polling is the fallback, and never report pending as the answer or end with an unbacked promise to check later).
|
|
47
47
|
Playtests are duration-billed at 2 credits per minute of play per playtester — state the estimated cost before filing. Windows rounds return a recording and no transcript; web rounds return answers only (no recording, no transcript) — never promise evidence a platform does not ship.
|
|
48
48
|
QA memory: whenever the developer mentions — in ANY conversation, not just QA runs — something that should always be tested, a fragile area, or a QA lesson learned, offer to record it as a check (or a note on an existing check) in QA-PLAN.md so it is tested from then on.
|
|
49
49
|
`;
|
package/docs/QA-PLAN-FORMAT.md
CHANGED
|
@@ -49,7 +49,10 @@ setup: "?save=campaign-mid" # optional: the link/flag that forces this check's
|
|
|
49
49
|
targeted round). Blocked/VOID outcomes change nothing here.
|
|
50
50
|
- **`setup` names the test affordance** that forces the check's precondition —
|
|
51
51
|
a URL param (`?fresh=1`, `?state=<checkpoint>`), a flag, a bundled-fixture
|
|
52
|
-
load control.
|
|
52
|
+
load control. At filing time the hook rides the ROUND's `url` — the review
|
|
53
|
+
interface loads it itself; testers cannot open links or type URLs — and
|
|
54
|
+
the filed step states only the player-visible expectation, never the
|
|
55
|
+
mechanism. A check
|
|
53
56
|
whose precondition can be neither forced nor verified is testimony-only —
|
|
54
57
|
say so in its prose.
|
|
55
58
|
- **Fixtures are provisioned by the dev's repo**: a previous-version save
|
|
@@ -78,8 +81,8 @@ last_verified: never
|
|
|
78
81
|
setup: "?save=campaign-mid"
|
|
79
82
|
```
|
|
80
83
|
|
|
81
|
-
1.
|
|
82
|
-
|
|
84
|
+
1. The game opens already loaded into the save "campaign-mid.sav" (made on
|
|
85
|
+
the previous release; the round's link forces it — no action needed).
|
|
83
86
|
2. Play for one minute in the desert outpost.
|
|
84
87
|
3. Describe what you saw: where you resumed, what the inventory held, and
|
|
85
88
|
anything missing, corrupted, or visually wrong.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qaping/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "qaping: automatic QA for your game. Your coding agent authors and maintains the QA plan, ships each patch's build to real human playtesters, and reports what broke.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"qaping",
|
package/skill/qaping/SKILL.md
CHANGED
|
@@ -17,11 +17,18 @@ cheaper. All service contact goes through three MCP tools —
|
|
|
17
17
|
|
|
18
18
|
## Ground rules (read before filing anything)
|
|
19
19
|
|
|
20
|
-
- **Playtesters are real people
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
- **Playtesters are real people, and waiting is background work.** A session
|
|
21
|
+
takes real minutes to be claimed and played, and the wait chain matters: each
|
|
22
|
+
`qaping_wait` renews the lease that keeps the round visible to new claimants.
|
|
23
|
+
The moment a filing returns pending, SPAWN A BACKGROUND TASK that loops
|
|
24
|
+
`qaping_wait` with the ping_id until results arrive, and keep working on
|
|
25
|
+
other things — that is the intended shape, the same as every pingfusi round.
|
|
26
|
+
Only if your harness has no background tasks: keep polling in the foreground.
|
|
27
|
+
Only in a one-shot print mode where neither is possible: say plainly that the
|
|
28
|
+
round is pending, give the ping_id, and ask to be re-invoked to continue —
|
|
29
|
+
never promise polling you cannot do (an ended session cannot poll; a round
|
|
30
|
+
went invisible and expired unclaimed exactly this way, live). Never report
|
|
31
|
+
pending as the final answer, never file a duplicate round.
|
|
25
32
|
- **Costs are duration-billed**: 2 credits per minute of play, per playtester
|
|
26
33
|
(`est_minutes × 2 × players`). State the estimate to the user BEFORE filing,
|
|
27
34
|
and set the wait expectation honestly in the same message: claim time is
|
|
@@ -44,17 +51,46 @@ cheaper. All service contact goes through three MCP tools —
|
|
|
44
51
|
- **QA-PLAN.md is the dev's file.** Commit it only with their approval; never
|
|
45
52
|
delete or demote a human check without them agreeing.
|
|
46
53
|
|
|
47
|
-
##
|
|
54
|
+
## The review interface (know your tester)
|
|
48
55
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
<!-- Distilled from QAPING_REVIEWER_INTERFACE.md (monorepo root, INTERNAL,
|
|
57
|
+
code-cited). Re-derive there when a reviewer surface changes. -->
|
|
58
|
+
|
|
59
|
+
Binding, derived from the review interfaces' code. The person who claims a
|
|
60
|
+
web round is on their phone, scrolling a feed. They read `instructions`
|
|
61
|
+
BEFORE claiming — front-load hardware and requirements there so the wrong
|
|
62
|
+
tester never claims. On claim the game auto-loads into an embedded browser
|
|
63
|
+
view with your steps beside it on the same small screen, with zero context;
|
|
64
|
+
attention is highest in the first minutes; setup friction is unpaid time.
|
|
65
|
+
|
|
66
|
+
The tester CAN: play the already-loaded game (touch, scroll, type); go
|
|
67
|
+
Back; Reload — which KEEPS storage, so a reload is never a fresh state; see
|
|
68
|
+
all steps at once and answer in any order; tap ONE option per option step;
|
|
69
|
+
type a note on any question step; pin a comment to a page element and draw
|
|
70
|
+
on it; pick one verdict; bail out with a reason.
|
|
71
|
+
|
|
72
|
+
The tester CANNOT:
|
|
73
|
+
- open tabs or windows — window.open and target=_blank links are dead
|
|
74
|
+
INSIDE the game too, so a game whose Play button opens a new window is
|
|
75
|
+
broken-for-review: flag it to the dev instead of filing;
|
|
76
|
+
- type or edit a URL: the round's `url` is the only page-load there is, and
|
|
77
|
+
links in step text are inert on the phone — never put links in steps;
|
|
78
|
+
- clear storage or go incognito: fresh state comes ONLY from a setup URL
|
|
79
|
+
param the round's `url` already carries;
|
|
80
|
+
- use devtools, attach files, or record — web rounds return answers only;
|
|
81
|
+
- use a second device;
|
|
82
|
+
- see `instructions` or `expected` once inside the review — EVERYTHING the
|
|
83
|
+
tester needs at answer time lives in the step text (≤300 chars each).
|
|
84
|
+
|
|
85
|
+
**Steps speak player language (MUST).** Things to tap and see in the game —
|
|
86
|
+
never flags, URL parameters, storage, or code concepts. A test hook is
|
|
87
|
+
exercised by the ROUND's `url` carrying it; the step describes only the
|
|
88
|
+
player-visible expectation ("the How to play option should be offered
|
|
89
|
+
first"), never the mechanism. Never ask to close/reopen anything or "start
|
|
90
|
+
fresh" — that state is a separate round whose `url` forces it. And as
|
|
91
|
+
always: one action per step, exact UI labels (the button says "Continue",
|
|
92
|
+
not "the resume option"), the most important check first, and never a step
|
|
93
|
+
that assumes they read your repo.
|
|
58
94
|
|
|
59
95
|
## SETUP — author QA-PLAN.md (first run in a repo)
|
|
60
96
|
|
|
@@ -121,8 +157,10 @@ verifiable state:
|
|
|
121
157
|
overlay on web) with a step asking the tester to read it back — a read-back
|
|
122
158
|
fact is verified; self-report is not.
|
|
123
159
|
|
|
124
|
-
Record each check's hook in its `setup` field;
|
|
125
|
-
|
|
160
|
+
Record each check's hook in its `setup` field; at filing time the hook
|
|
161
|
+
rides the ROUND's `url` — the game loads it itself, so the tester never
|
|
162
|
+
sees or types it — and the filed step states only the player-visible
|
|
163
|
+
expectation. The unreviewed-developer-build disclosure
|
|
126
164
|
already covers shipping these; the no-steering rule forbids steering SAFETY
|
|
127
165
|
decisions only. A store-delivered build that cannot surface state keeps its
|
|
128
166
|
checks testimony-only — mark that in the plan and report at that grade.
|
|
@@ -135,7 +173,10 @@ checks testimony-only — mark that in the plan and report at that grade.
|
|
|
135
173
|
checks run and why.
|
|
136
174
|
2. **Compose sessions.** Partition the selected checks by required state —
|
|
137
175
|
fresh-install / progression / settings-mutating — and put state-mutating
|
|
138
|
-
checks LAST within their session.
|
|
176
|
+
checks LAST within their session. A session has ONE state: its round
|
|
177
|
+
`url` (carrying the forcing setup param) is the only state control that
|
|
178
|
+
exists — testers cannot clear storage or start fresh themselves — so
|
|
179
|
+
checks needing different forced states never share a session. Budget play content: sum the checks'
|
|
139
180
|
directed play time; if it exceeds est_minutes, split into parallel
|
|
140
181
|
5-minute rounds (credit-neutral: two focused 5-minute rounds cost one
|
|
141
182
|
diluted 10-minute round) or raise est_minutes within the cap, and state
|
|
@@ -157,8 +198,11 @@ checks testimony-only — mark that in the plan and report at that grade.
|
|
|
157
198
|
5. **File** ONE `qaping_playtest` per composed session, always with
|
|
158
199
|
`questionnaire:'none'` — on a QA-PLAN round your checks are the questions;
|
|
159
200
|
the standard instrument is a separate experience round (below), never a
|
|
160
|
-
default.
|
|
161
|
-
|
|
201
|
+
default. A WEB session additionally files `require_evidence:'none'`
|
|
202
|
+
(MUST) — left at its default, the finish silently demands a pinned
|
|
203
|
+
screenshot-comment no step asked for. est_minutes is an
|
|
204
|
+
honest sum of the steps' directed play — the service
|
|
205
|
+
accepts 5–30 minutes (10 is the standard session; outside that
|
|
162
206
|
range the filing is refused, not clamped), and the clock is play time:
|
|
163
207
|
download/install happens before it starts. The authored steps MUST be:
|
|
164
208
|
- **one step per selected check**, its text opening with the id token —
|
|
@@ -167,11 +211,20 @@ checks testimony-only — mark that in the plan and report at that grade.
|
|
|
167
211
|
first", never "confirm the menu appears"), with options exactly
|
|
168
212
|
["Pass — as described", "Fail — describe exactly what you saw",
|
|
169
213
|
"Couldn't test — say why", "Didn't reach this part"] — the pick comes
|
|
170
|
-
back verified in steps_result
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
214
|
+
back verified in steps_result. EXCEPTION: when the check asks the
|
|
215
|
+
tester to DISCRIMINATE between named states ("which difficulty did the
|
|
216
|
+
bot play like?", "which screen did you land on?"), the options are the
|
|
217
|
+
NAMED candidates themselves ("rookie-level" / "harder than that") plus
|
|
218
|
+
"Couldn't tell — say why" — generic Pass/Fail on a discrimination
|
|
219
|
+
yields contradictions instead of a signal (measured live);
|
|
220
|
+
- option labels ≤40 chars, 2–4 options per step; never author a final
|
|
221
|
+
step whose options duplicate the verdict options — the phone hides it
|
|
222
|
+
as a duplicate of the verdict control;
|
|
223
|
+
- a check with a `setup` hook is forced by filing the session's `url`
|
|
224
|
+
WITH the hook — the game loads it itself; the step states only the
|
|
225
|
+
player-visible expectation. One whose precondition cannot be forced
|
|
226
|
+
opens with a verifying option step ("Before this session: had you ever
|
|
227
|
+
played this game before?" — yes / no / not sure);
|
|
175
228
|
- a recheck of a prior finding is a clearly-labeled step at its natural
|
|
176
229
|
play-order point (first when its required state demands it, last
|
|
177
230
|
otherwise) — "VERIFY FIX: last round saw X — does it still happen?" —
|
|
@@ -180,6 +233,9 @@ checks testimony-only — mark that in the plan and report at that grade.
|
|
|
180
233
|
- a closing **break-it slice** (~2–3 minutes) authored from the diff:
|
|
181
234
|
"this patch changed X — try to break it: <concrete abuse ideas from the
|
|
182
235
|
diff>. Report the weirdest thing you saw AND list what you tried."
|
|
236
|
+
Abuse ideas target PLAYER-VISIBLE behaviors the diff changed — things a
|
|
237
|
+
player can tap, see, or provoke — never internal mechanisms (a flag, a
|
|
238
|
+
cache, a storage key means nothing to a player).
|
|
183
239
|
Finding nothing is a fine answer when we know what was attempted; frame
|
|
184
240
|
it in `instructions` as "these checks are the territory — break anything
|
|
185
241
|
near them";
|
|
@@ -188,10 +244,16 @@ checks testimony-only — mark that in the plan and report at that grade.
|
|
|
188
244
|
was actually used, with options.
|
|
189
245
|
**Filing gate (MUST):** print `this round covers: <ids>` per session and
|
|
190
246
|
assert the ids — unioned across every session this run files — equal the
|
|
191
|
-
Select step's list BEFORE calling qaping_playtest.
|
|
192
|
-
20
|
|
193
|
-
|
|
194
|
-
|
|
247
|
+
Select step's list BEFORE calling qaping_playtest. The wire keeps only
|
|
248
|
+
the FIRST 20 steps_result rows and a play directive is prepended, so with
|
|
249
|
+
`questionnaire:'none'` budget at most 19 authored steps per session (8 if
|
|
250
|
+
the standard questionnaire rides) — rows past 20 are answered by the
|
|
251
|
+
tester and silently dropped at finish, which is why this gate exists. A
|
|
252
|
+
mismatch (the budget forcing cuts) fails loudly PRE-SPEND: batch another
|
|
253
|
+
session or state the deferral out loud — never silently truncate.
|
|
254
|
+
6. **Wait, in the background:** spawn a background task looping `qaping_wait`
|
|
255
|
+
and keep working (see ground rules) — foreground polling is the fallback,
|
|
256
|
+
and a promise to check later is never a wait.
|
|
195
257
|
7. **Report** from `qaping_results`:
|
|
196
258
|
- **Evidence line first (MUST).** Every report opens with its grade:
|
|
197
259
|
`Evidence: recording + transcript` (macOS/iOS) / `Evidence: recording
|
|
@@ -205,7 +267,11 @@ checks testimony-only — mark that in the plan and report at that grade.
|
|
|
205
267
|
findings mean fix and refile — unresolved never headlines as PASS.)
|
|
206
268
|
- **One row per SELECTED check (MUST)**, keyed by id, outcome from
|
|
207
269
|
{Pass, Fail, Blocked, NOT-ASKED}. "Couldn't test" and "Didn't reach this
|
|
208
|
-
part" are Blocked, with the why. A check
|
|
270
|
+
part" are Blocked, with the why. A check that reached the wire as more
|
|
271
|
+
than one row (a precondition step, a VERIFY FIX pair) takes its outcome
|
|
272
|
+
from the WORST row: any Fail → Fail; else any Blocked or unanswered row
|
|
273
|
+
leaves the check unverified and the headline counts it ("PASS — N
|
|
274
|
+
unverified") — never plain Pass over a Blocked sub-step. A check whose precondition came back
|
|
209
275
|
unverified or disproven is VOID — report it as Blocked ("VOID:
|
|
210
276
|
precondition unverified"), never as a pass or fail, and leave
|
|
211
277
|
`last_verified` untouched. A selected check that never made the wire or
|
|
@@ -255,18 +321,19 @@ the fluke); Fail → `failing`, and the issue upgrades to CONFIRMED. Never
|
|
|
255
321
|
resolve an ambiguity by re-buying the whole batch, and never label a
|
|
256
322
|
once-seen fail CONFIRMED without that round or hard evidence.
|
|
257
323
|
|
|
258
|
-
##
|
|
324
|
+
## Paired rounds (two-state comparisons)
|
|
259
325
|
|
|
260
326
|
A feel/physics/balance regression judged absolute buys little — a stranger
|
|
261
|
-
answers "did spin feel right" in a vacuum.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
327
|
+
answers "did spin feel right" in a vacuum. But a comparison never rides one
|
|
328
|
+
round: never two links in one round — links in step text are inert on the
|
|
329
|
+
phone and `instructions` go unread in-review, so a second URL simply never
|
|
330
|
+
gets opened. When a check needs TWO states compared (with/without a hook,
|
|
331
|
+
old build vs new), file TWO paired rounds with the SAME steps, one per
|
|
332
|
+
state, each state forced by its own round `url` (the ledger's `build` field
|
|
333
|
+
keeps the old build recoverable), and compare the answers yourself in the
|
|
334
|
+
report. Caveat it: different testers played each side, and a tester told to
|
|
335
|
+
hunt changes reports noise as change. Native builds pair the same way, one
|
|
336
|
+
build per round — re-publish the previous zip if its /b/<slug> expired.
|
|
270
337
|
|
|
271
338
|
## The experience round (opt-in, never a default)
|
|
272
339
|
|