The QA Loop
Syntaxis treats QA as a track of its own, not an afterthought bolted onto the build loop. Four commands cover the cycle:
/test-plan → /test-cases → /automate → /test-run(strategy) (the cases) (the code) (the cycle)How the diagram works
Section titled “How the diagram works”Like the build loop, this diagram splits into a setup step that runs once and a ring that repeats — but here the ring only closes back on itself once you decide to run another cycle, so nothing forces a fixed cadence the way feature-by-feature work does.
Setup — run once, or when scope changes
Section titled “Setup — run once, or when scope changes”01 · /test-plan. Writes syntaxis/qa/test-plan.md before any case gets
designed: what’s in scope and explicitly out of it, which test levels apply,
which environments and devices matter, the risk-based priority order, and the
entry and exit criteria that decide when a cycle counts as done. This is a
decision record, not a checklist to fill in — a solo project with one
environment says so plainly rather than inventing a staging tier it doesn’t
have. Its arrow feeds into 02 on the ring.
The ring — repeat once per test cycle
Section titled “The ring — repeat once per test cycle”02 · /test-cases. Designs cases into syntaxis/qa/cases/<area>.md, each
with a durable TC-NN identifier and a Covers field naming the exact
requirement it traces to — a case that covers nothing is either missing its
requirement or isn’t a case. Cases come from what the spec claims, never from
reading the implementation, because that would only prove the code agrees with
itself.
03 · /automate. Takes the cases that are stable, deterministic, and
repeatable, and turns them into real specs in whatever harness the project
already has — web or mobile — one test per case, titled with the case’s ID so
a failure points straight back at its specification. It then proves each new
test can actually fail, because a test that only ever passes is worse than
no test: it turns an unverified path into a false guarantee. A case that needs
visual judgement, a real payment, or a permission dialog the harness can’t
reach stays manual on purpose, and the report says so rather than pretending.
04 · /test-run. Drawn in rust, matching /check’s color in the build
loop, because this is the other diagram’s proof step: it executes the cases —
automated and manual alike — against the real running application and writes
syntaxis/qa/runs/<date>-<cycle>.md with the exact commit, environment,
platform versions, and every case’s result as pass, fail, blocked, or
skipped.
The shared ledger — where a failure actually goes
Section titled “The shared ledger — where a failure actually goes”The panel below the ring, connected to 04 by a dashed line, is not a fifth
step; it’s what happens inside /test-run every time a case fails. Every
fail opens a finding in syntaxis/context/findings.md — the exact same file
/audit writes to from the build loop. That one
design choice is why the QA track needs no gate of its own: a P0 or P1 finding
from a failed test blocks /complete through the
findings gate that already exists, so a code review and a test cycle can never
quietly disagree about whether work is ready to ship.
Where the ring closes
Section titled “Where the ring closes”There’s no arrow drawn from /test-run back to /test-cases on the diagram —
running another cycle is a decision you make, not a step that fires
automatically. In practice that decision is easy: run /test-cases again when
new behavior needs cases, /automate again once more of them stabilize, and
/test-run for every regression pass, smoke test, or release candidate.
/test-plan itself only needs revisiting when the scope changes, which is
why its setup box says “run once, or when scope changes.”
The commands
Section titled “The commands”/test-plan — decide what testing this project needs
Section titled “/test-plan — decide what testing this project needs”Writes syntaxis/qa/test-plan.md: scope and out-of-scope, test levels,
environments, target devices and browsers, risk-based priority, entry and exit
criteria, defect management, tooling, and roles.
It is a decision record, not a template. A solo project with one environment says so plainly rather than inventing a staging tier and a sign-off committee.
The out of scope section carries real weight: it is the record of an accepted risk, not an oversight.
/test-cases — design the cases
Section titled “/test-cases — design the cases”Writes cases to syntaxis/qa/cases/<area>.md with durable TC-NN identifiers.
### TC-014 [P1] manual - Checkout rejects an expired card
**Covers:** feature 7 / done-when 3**Preconditions:** A signed-in account with one saved expired card.**Steps:**1. Open the cart with one item and choose Checkout.2. Select the saved card ending 4242.3. Submit the order.**Expected:** The order is refused, the message names the expiry as thereason, the cart keeps its item, and no charge is created.**Platforms:** web, iOSTwo rules do most of the work:
- Cases derive from requirements, not from the implementation. Writing cases by reading the code only proves the code does what it does.
- Every case names what it covers. A case that covers nothing is either missing its requirement or is not a case.
See Test Design.
/automate — turn stable cases into code
Section titled “/automate — turn stable cases into code”Converts approved cases into specs in the harness the project already has, one test per case, titled with the case ID.
It automates a case only when the behaviour is stable, deterministic, repeated, and observable by the harness. Leaving a case manual is a legitimate outcome, not a failure — visual judgement, real payments, biometrics, and browser permission dialogs stay manual and get said so.
Then it proves each new test can fail. A test that passes against broken behaviour is worse than no test, because it turns an untested path into a false guarantee.
See Web Automation and Mobile Automation.
/test-run — execute a cycle and record it
Section titled “/test-run — execute a cycle and record it”Runs the cases against a real running application and writes
syntaxis/qa/runs/<date>-<cycle>.md with the branch, the exact commit, the
environment, the platform versions, and every case’s result.
| Result | Meaning |
|---|---|
pass |
The expected result was observed in full, including its negative half |
fail |
The expected result was not observed |
blocked |
The case could not be run, and the record names what blocked it |
skipped |
Deliberately not run this cycle, with a reason |
Every fail opens a finding. See Defects and Evidence.
Setting up the harnesses
Section titled “Setting up the harnesses”/automate writes tests but never installs a runner. Setup is separate and
opt-in:
| Command | Sets up |
|---|---|
/tests |
A stack-native unit test runner |
/tests browser |
A browser and end-to-end harness |
/tests mobile |
A device or simulator harness |
See Testing Setup.
How it relates to /check
Section titled “How it relates to /check”They answer different questions and neither replaces the other.
/check |
/test-run |
|
|---|---|---|
| Scope | One work item’s done-when criteria | A set of designed cases across areas |
| Output | Evidence for the current spec | A cycle record with per-case results |
| When | Inside the build loop, every feature | Regression, smoke, release candidate |
Standards
Section titled “Standards”syntaxis/context/qa-standards.md holds the conventions all four commands read:
the identifier scheme, severity and priority definitions, evidence rules, and
automation policy. Edit it once to match how your project tests.