Defects and Evidence
One ledger
Section titled “One ledger”Defects found by /test-run go into
syntaxis/context/findings.md — the same findings ledger
that /audit writes to.
A failed test therefore blocks /complete through
the gate that already exists. No second gate, and no way for code review and
testing to disagree about whether work can ship.
### F-07 [P1] open - Checkout accepts an expired card
**File:** src/checkout/validate.ts:42**Found:** 2026-09-19 by /test-run (cycle: regression; case: TC-014)**Why it matters:** ...**Suggested fix:** ...**Resolution:**Rules:
- IDs continue the ledger’s existing sequence, never reused, never renumbered.
- Severity is
P0–P3by the consequence of the defect, not by how visible it is. Only P0 and P1 block completion. - File names the suspected location when the cause is identified. When it is not, the record says the cause is unlocated rather than guessing a file.
- One finding per distinct defect. Several cases failing from one cause produce one finding listing those cases, not one finding each.
- A
blockedcase is not a defect. It goes in the cycle record only, unless the thing blocking it is itself a defect. /test-runnever changes an existing finding’s status. Re-verifying a repair is a later cycle’s job; closing a finding belongs to/audit.
The cycle record
Section titled “The cycle record”Every run writes syntaxis/qa/runs/<YYYY-MM-DD>-<cycle>.md:
# Test run - regression - 2026-09-19
**Branch:** feature/checkout-limits **Commit:** a1b2c3d**Environment:** local **Build:** 0.4.2**Platforms:** Chrome 141 (macOS 26), iPhone 17 simulator (iOS 26)
## Summary| Result | Count || pass | 18 || fail | 2 || blocked | 1 |
## Results| Case | Result | Platform | Finding || TC-014 | fail | web | F-07 || TC-021 | pass | iOS | || TC-022 | blocked | iOS | |
## Failures### TC-014 - Checkout rejects an expired card**Observed:** The order was accepted and a charge was created.**Expected:** The order is refused and no charge is created.**Steps to reproduce:** ...**Evidence:** test-results/tc-014-failure.png**Finding:** F-07
## Exit criteriaEach criterion from the test plan, and whether it was met.The commit, environment, and platform versions are mandatory. A result without them proves nothing a week later.
Rules that keep a cycle honest
Section titled “Rules that keep a cycle honest”| Rule | Why |
|---|---|
| Never edit application source during a cycle | Repairing mid-cycle invalidates the record |
| Never weaken or rewrite a case to produce a pass | A wrong case is a case defect, fixed separately |
| Observe, do not infer | A case passes because its result was seen, not because the code looks right |
| A partial pass is a fail | And the record names which half failed |
| A flaky case is a fail | Until proven otherwise; the attempts get recorded |
| Blocked is not a soft fail | Use it only when the case truly could not run, and name the blocker |
Evidence for every failure: exact reproduction steps, observed versus expected, screenshots or recordings the harness produced, and relevant logs — with credentials, tokens, and personal data redacted.
Entry criteria
Section titled “Entry criteria”A cycle refuses to start against an unknown build. /test-run records the
branch, exact HEAD, environment, and platform versions first, and checks the
test plan’s entry criteria. Running against an environment the plan excludes
produces a record that means nothing.
After a cycle
Section titled “After a cycle”| Situation | Next |
|---|---|
| A failure with an unclear cause | /debug |
| A failure with a known cause | /fix |
| Exit criteria genuinely met | /complete |
/complete archives the cycle records for the work item under
syntaxis/history/test-runs/. Records are immutable: a superseded cycle is never
edited or deleted, because it is evidence of what was true at that commit.
What a report always says
Section titled “What a report always says”The last line of every cycle is what it did not cover. A cycle that ran on one browser or one simulator proves only that, and the report says so rather than letting a summary count imply more.