mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-03 15:27:56 +01:00
* Attribute every paid trial's cost: bind label-named records by testName, price aborted SDK sessions from streamed usage, model-free cases cost $0
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: case cost adds streamed sessions to record sums and keeps record cost_known
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: the paid report headline counts ledger-only session cost once
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: a cost-only record never sets the trial model
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: recordE2E writes cost_case_id only for a registered label-named case
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: CHANGELOG for paid-report cost attribution (Unreleased)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: the headline adds only streamed session cost; cache writes without a 5m key
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: how the paid report prices a trial and what stays cost-unknown
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* Price PTY sessions from their transcripts: pin a session id, sum the session's and its subagents' usage into the ledger's streamed_cost_usd
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: transcript pricing never throws from a PTY ledger writer
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: pin transcript-cost.ts as non-behavioral at HARNESS_VERSION 6
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: recognise --session-id= and --resume= forms
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: CHANGELOG for PTY transcript pricing (Unreleased)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: PTY sessions priced from their transcripts
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: price PTY transcripts without adding a launch argument; native AUQ capture opts out
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: harness notes and CHANGELOG match the transcript claim
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(flaky): gstack-flaky run reruns a failed JUnit test once and ledgers the flake (GSTA-158)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(flaky): stream output, keep unreported runner failures red, fail-closed duplicates and nonzero reruns
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes
gstack-flaky never greens an incomplete run: a targeted rerun needs the
runner's summary proving the first run complete, otherwise (and always for
generic runners) the rerun repeats the whole command. A rerun clears a test
only when it exits 0 and the test passes once on its first attempt. Killed
runners exit 3 (FLAKY_COMMAND_KILLED) and signals are forwarded. The first
report is restored at --junit with reruns kept beside it; ids are redacted at
every output; the ledger gets its own GSTACK_FLAKE_LEDGER_JUNIT; fixtures are
registered in FREE_FIXTURES.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: latch cancellation and check whole-command rerun reports
A cancel forwarded to a runner that traps the signal now counts as killed for
every later attempt, so a cancelled job is never rerun or greened. A
whole-command rerun clears nothing when its report has a failed test, misses a
first-run test, or its runner counted failures outside the report.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: whole-command rerun when coverage or runner-flaky tests can fail the run
A coverage threshold or a fail-on-flaky policy fails a run for a reason a
narrowed rerun cannot reproduce, so either forces a whole-command rerun.
--junit refuses an existing file that is not a JUnit report instead of
deleting it.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(flaky): rerun the whole command by default; targeted rerun is opt-in
A rerun counts only on the runner's own full green verdict: exit 0, no failed
or missing test, nothing counted outside the report. That covers every way a
run can fail, which a narrowed rerun cannot (a coverage threshold with an lcov
reporter, a fail-on-flaky policy, a test never reached). --rerun-scope test
reruns the failed test alone, with its preconditions documented and the
complete-run checks kept as a safety net. An unreadable existing --junit file
is a usage error, not a crash.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: gstack-flaky CHANGELOG entry and standalone-binaries row (GSTA-158)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(flaky): quarantine registry for repeat flakes (GSTA-158 P2)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(flaky): bound renewal dates; match non-ASCII paths in check --base
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(flaky): reword the FLAKY_QUARANTINE_BASE hint so the egress scanner does not read it as a network op
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(agent-sdk): every SDK caller passes the claude_code preset or names why not
The SDK's default system prompt is a bare stub that drops the line telling the
model to run /skill through the Skill tool. runAgentSdkTest now refuses a
missing, empty or bare-string prompt; non-preset callers name a reason; a free
tripwire scans test/ and scripts/ for the same mistake.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: record the SDK prompt guard as a non-behavioral harness change and baseline its tripwire
harness-version: runAgentSdkTest validates systemPrompt before starting; every
live caller already passed the claude_code preset, so no verdict can change.
test-of-test ratchet: the tripwire's subject is the eval harness by design.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: name the preset literal callers pass and the unnamed-prompt refusal
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(eval-plan): frontier models under test (R54)
Haiku and Sonnet are not models under test. dry-run refuses a plan whose every
arm is Haiku or Sonnet unless --tier-question names what it asks about that
tier, warns on a mix, and re-costs the plan on Opus 5.5 and GPT-6.1 Sol.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(eval-plan): trim R54 skill prose and raise the eval-plan context ceiling
The R54 paragraph and CHECK: frontier bullet were cut to the minimum; the
exemptions and verdict rule stay in docs/TESTING_INTERNALS.md. The remaining
growth is the feature, so only the eval-plan eager ceiling moves (4887 -> 5458,
the capture helper's value); other skills' ceilings are left as they were.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(eval-plan): pilot start keeps the R54 refusal; --tier-question rejects a flag
Review pass 1 (full depth) found the frontier refusal could be skipped by
starting a pilot on Haiku or Sonnet arms behind a dry run made on other arms,
or behind a dry-run.json written before the check existed. startPilot now
refuses a pilot whose every arm is Haiku or Sonnet unless its dry run recorded
a tier question. dry-run --tier-question no longer takes the next flag as its
answer. The testing doc now says the frontier re-cost is printed for
comparison with the brief cap, not enforced.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(support-tiers): Windows CI in the present tense now that windows-smoke is required (#3806)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: empty commit for a clean check set at the same tree (cancelled orphan free-suite check at 97487df)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(skills): /eval-plan entry names the R54 frontier check
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
247 lines
16 KiB
Markdown
247 lines
16 KiB
Markdown
# Flaky tests: rerun once and record it (`gstack-flaky`)
|
|
|
|
`gstack-flaky run` runs your test command, reads the JUnit report it writes,
|
|
and when tests failed, runs the command once more. A test that passes on its
|
|
rerun is a **flaky pass**: the job stays green and the flake is recorded on a ledger, so
|
|
the daily flaky pass can fix it at the source. A test that fails twice is red.
|
|
This is CREW rule 16 ("run the failed test again and note that it is flaky")
|
|
for any runner that writes JUnit: Playwright, `bun test`, jest, vitest and
|
|
pytest. A test that keeps flaking while it is fixed can be
|
|
[quarantined](#quarantine): it still runs, with up to 3 attempts, and never counts
|
|
as a pass. gstack's own free suite keeps its file-level retry
|
|
(`GSTACK_FREE_RETRY_FLAKY`, [Flake ledger](TESTING_INTERNALS.md#flake-ledger)).
|
|
|
|
## Get started in GitHub Actions
|
|
|
|
```yaml
|
|
- uses: oven-sh/setup-bun@v2
|
|
with: { bun-version: 1.4.4 }
|
|
- name: Install gstack-flaky (pinned)
|
|
env: { GSTACK_REF: <a gstack commit sha you have tested> }
|
|
run: |
|
|
git clone --quiet --filter=blob:none https://github.com/garrytan/gstack.git "$RUNNER_TEMP/gstack"
|
|
git -C "$RUNNER_TEMP/gstack" checkout --quiet "$GSTACK_REF"
|
|
- name: E2E
|
|
env:
|
|
PLAYWRIGHT_JUNIT_OUTPUT_NAME: results/junit.xml
|
|
GSTACK_FLAKE_LEDGER_JUNIT: ${{ runner.temp }}/flaky-junit-ledger.jsonl
|
|
run: |
|
|
"$RUNNER_TEMP/gstack/bin/gstack-flaky" run --junit results/junit.xml -- npx playwright test --reporter=line,junit
|
|
- if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with: { name: flaky-junit-ledger-e2e, path: "${{ runner.temp }}/flaky-junit-ledger.jsonl", if-no-files-found: ignore, retention-days: 90 }
|
|
```
|
|
|
|
Replace `GSTACK_REF` with a gstack commit you have tested; the bin needs only
|
|
Bun and git. In Actions it also writes a step-summary table of the flaky
|
|
passes and one `::warning` annotation per flaky test, so they are visible on
|
|
the run before anyone reads the ledger.
|
|
|
|
## Runners
|
|
|
|
| Runner | Command after `--` | Notes |
|
|
|---|---|---|
|
|
| Playwright | `npx playwright test --reporter=line,junit` with `PLAYWRIGHT_JUNIT_OUTPUT_NAME=<file>` | `gstack-flaky` sets `PLAYWRIGHT_JUNIT_INCLUDE_RETRIES=1` so Playwright's own `retries` are reported; with retries configured, those attempts stand and nothing is rerun again. |
|
|
| bun | `bun test --reporter=junit --reporter-outfile=<file>` | |
|
|
| jest, vitest, pytest (`--runner generic`) | your command, writing JUnit | Always reruns the whole command, even with `--rerun-scope test`. |
|
|
|
|
The command after `--` runs without a shell. When it needs one, wrap it as
|
|
`bash -c '<script> "$@"' _` so a targeted rerun's selection arguments reach
|
|
the runner.
|
|
|
|
## Rerun scope
|
|
|
|
**Default: the whole command.** The rerun repeats your command exactly, and
|
|
counts only on the runner's own full green verdict: it exits 0, no test fails,
|
|
every test of the first run is in its report, and the runner counts no failure
|
|
outside the report. That verdict covers every reason a run can fail, including
|
|
the ones a narrowed rerun cannot see: a test the first run never reached
|
|
(`--bail`, `--max-failures`, `-x`), a coverage threshold (however coverage is
|
|
configured, `bunfig.toml` and lcov included), a fail-on-flaky policy, a
|
|
global setup error. A test that failed in the first run and passes once in this
|
|
rerun is a flaky pass. It costs one more run of the suite, which is still far
|
|
cheaper than rerunning the CI job by hand.
|
|
|
|
**Opt-in: `--rerun-scope test`.** Reruns the failed test alone (Playwright:
|
|
`<file> --grep <title> --project <project>`; bun: `<file> --test-name-pattern <title>`)
|
|
and clears it when that rerun exits 0. Use it only when the first run's exit
|
|
status can come from failed tests alone: no coverage threshold in any form, no
|
|
`--fail-on-flaky-tests`, no other step inside the command that can fail. As a
|
|
safety net, `gstack-flaky` still reruns the whole command
|
|
(`FLAKY_RERUN: scope=command (<why>)`) when the runner exited anything but
|
|
1, its summary is missing, it stopped early (bun `Bailed out`, Playwright
|
|
`did not run`, `interrupted`, `Testing stopped early`, a global timeout), it
|
|
printed a coverage table or got `--coverage`, or it retried flaky tests itself.
|
|
It cannot see a coverage threshold configured without console output (for
|
|
example `coverageReporter = ["lcov"]` in `bunfig.toml`), which is why this
|
|
scope is opt-in.
|
|
|
|
## Quarantine
|
|
|
|
A test that keeps flaking while someone fixes it can be **quarantined** in
|
|
`.gstack/quarantine.json` at the repository root. Quarantine is a larger
|
|
attempt budget, never a skip: the test still runs on every run, is listed as
|
|
quarantined in the output, and never counts as a pass.
|
|
|
|
**How a quarantined test is judged.** The verdict rule from
|
|
[Rerun scope](#rerun-scope) does not change: an attempt counts only when the
|
|
runner itself reports a full green run. When every test an attempt failed is a
|
|
live quarantined test, and nothing else is wrong with that attempt (no kill, no
|
|
failure outside the report, no first-run test missing), the whole command may
|
|
run again, up to 3 attempts in total. The run is green only when one of those
|
|
attempts is fully green. A quarantined test that fails all 3 is a **hard
|
|
break**, and the run is red. A test that is not quarantined keeps its one
|
|
rerun. A red attempt never turns green because its only reported failure is a
|
|
quarantined test, because the runner's exit status can come from things the
|
|
report does not show (a coverage threshold, a fail-on-flaky policy, a global
|
|
setup). With `--rerun-scope test` the quarantined test gets the same 3
|
|
attempts on the targeted path, with the same fallback to the whole command.
|
|
When the runner retries on its own (Playwright `retries`), its attempts are
|
|
the budget and nothing is rerun again.
|
|
|
|
**Missing results.** A quarantined id missing from a run that included its
|
|
file (and, for Playwright, its project) is red. A run that did not include the
|
|
file, such as a shard or a diff selection, is not.
|
|
|
|
**Read from the base branch.** `run --base <ref>` reads the registry from
|
|
that commit instead of the working tree. Pull-request CI passes its target
|
|
branch, so a change cannot quarantine the test it breaks. `check --base`
|
|
compares against the merge base, so check out full history for it:
|
|
|
|
```yaml
|
|
- uses: actions/checkout@v4
|
|
with: { fetch-depth: 0 }
|
|
- name: Quarantine registry
|
|
run: '"$RUNNER_TEMP/gstack/bin/gstack-flaky" quarantine check --base "origin/${{ github.base_ref }}"'
|
|
- name: E2E
|
|
run: |
|
|
"$RUNNER_TEMP/gstack/bin/gstack-flaky" run --base "origin/${{ github.base_ref }}" --junit results/junit.xml -- npx playwright test --reporter=line,junit
|
|
```
|
|
|
|
### Commands
|
|
|
|
| Command | What it does |
|
|
|---|---|
|
|
| `gstack-flaky quarantine add <id> --owner <who> --ledger <url> --class <class> --reason <text> --evidence <url>… --junit <file> [--days <n>]` | Adds an entry that expires in `--days` (default 7, at most 14). `--junit` counts the suite for the cap and confirms the id exists; `gstack-flaky ids` prints the ids. |
|
|
| `gstack-flaky quarantine renew <id> --owner <who> --evidence <url> [--days <n>]` | One renewal of up to 7 days from the later of now and the current expiry, with evidence not already on the entry and the owner named again. A second renewal is refused. |
|
|
| `gstack-flaky quarantine release <id> --reason <text> --pr <url>` | Moves the entry to `released` with the date, the reason and the PR. |
|
|
| `gstack-flaky quarantine check [--base <ref>] [--junit <file>]` | Validates every entry and the cap; with `--base`, also what this change did since the merge base. Exits 1 with one `QUARANTINE_REFUSED:` line per problem. |
|
|
| `gstack-flaky quarantine report [--ledger <file\|dir>…] [--base <ref>]` | Lists expired entries, then live entries soonest-expiring first with days left. With downloaded ledgers it adds recent outcomes and marks entries with 10 consecutive clean passes `READY_TO_RELEASE`; without `--ledger` it says the exit rule was not checked. |
|
|
|
|
### Rules
|
|
|
|
- **Every entry is owned and expires.** An entry holds `owner`, `ledger`
|
|
(the ledger line or issue tracking the fix), `failureClass`, `reason`,
|
|
`evidence`, `enteredAt`, `expiresAt`, `renewals` and `suiteTests` (the
|
|
suite size `add` counted). It lasts 7 days by default and at most 14 from
|
|
entry, plus one renewal of at most 7 days.
|
|
- **Expired means not quarantined.** An expired entry stops applying without
|
|
an edit: `run` treats the test as an ordinary test and prints
|
|
`FLAKY_QUARANTINE_EXPIRED` with the renew and release commands. An entry
|
|
that breaks a rule (for example one that lasts 30 days) is ignored the same
|
|
way, with `FLAKY_QUARANTINE_IGNORED`.
|
|
- **Cap.** Live entries are capped at 10% of the suite's tests, at least 1,
|
|
and 5 for a suite under 50 tests. `add` refuses past the cap; `check`
|
|
enforces it against `--junit` when given, else against the smallest
|
|
`suiteTests` on a live entry.
|
|
- **Classes.** `detector`, `harness`, `timing` and `model-latency`.
|
|
`product` is refused (a product defect is fixed, not quarantined), and so is
|
|
`infra` (an infrastructure red is rerun or fixed as infrastructure).
|
|
- **`check --base` refuses** an entry added in the same change that edits its
|
|
test's file, an entry that disappears without a release record, a release
|
|
record that was removed, and a changed `enteredAt` or rewritten renewal
|
|
history.
|
|
- **Exit rule.** 10 consecutive clean passes (`quarantined-pass` with no
|
|
failed attempt) on the ledgers since the entry was added. Release the entry
|
|
with the fix PR.
|
|
- **Separate from `CASE_QUARANTINE`.** gstack's own paid-eval quarantine
|
|
(`CASE_QUARANTINE` and `EVAL_POLICY`,
|
|
[TESTING_INTERNALS.md](TESTING_INTERNALS.md)) is a different registry with
|
|
its own rules for eval cases. The two share no schema, and `gstack-flaky`
|
|
neither reads nor writes it.
|
|
|
|
### The daily flaky pass
|
|
|
|
Download the ledger artifacts of the last week's runs and read them with
|
|
`report`; fix expired and `EXPIRING` entries first (fix the test, or renew
|
|
once with new evidence), release `READY_TO_RELEASE` entries, then fix the
|
|
worst repeat on the ledger:
|
|
|
|
```bash
|
|
for id in $(gh run list --workflow e2e.yml --limit 50 --json databaseId -q '.[].databaseId'); do
|
|
gh run download "$id" --pattern 'flaky-junit-ledger-*' --dir "ledgers/$id" || true
|
|
done
|
|
gstack-flaky quarantine report --ledger ledgers
|
|
```
|
|
|
|
## Rules
|
|
|
|
- **One rerun, small failures only.** A failed test gets one rerun when the
|
|
runner made no retries and at most `--max-reruns` (3) tests failed. More
|
|
failures than that is a real red, and nothing is rerun. When the run is
|
|
already red for a test that cannot be rerun, a whole-command rerun is
|
|
skipped.
|
|
- **A rerun clears a test only cleanly.** The rerun's command must exit 0 and
|
|
the test must run once and pass on its first attempt; a rerun the runner
|
|
retried again does not count.
|
|
- **Never green by accident.** The report is deleted before every attempt, and
|
|
a report that attempt did not write counts as missing. A missing, empty,
|
|
zero-test or malformed report fails, as does a non-zero exit with no failed
|
|
test (a crash or a non-test step) and a runner killed by a signal. Cancelling
|
|
`gstack-flaky` (SIGINT, SIGTERM) is passed to the runner and latched: nothing
|
|
is rerun after it, whatever exit the runner chooses. When the runner's
|
|
summary counts failures its JUnit omits (a bun file that fails to load, a
|
|
Playwright error outside any test), the run is red and nothing is rerun.
|
|
- **Reports.** After the run, `--junit` holds the first run's report, so a
|
|
later upload or test reporter sees what failed. Each rerun's report is kept
|
|
beside it as `<name>.rerun-<n>.xml`. Other reporters' outputs (Playwright's
|
|
`test-results/` and HTML report) are rewritten by a rerun; upload the JUnit
|
|
report as the record. An existing `--junit` file that is not a JUnit report,
|
|
or cannot be read, is refused (usage, exit 2), never deleted.
|
|
- **Ids.** A test is `<file>::<project>::<describe > title>`, with the project
|
|
empty outside Playwright, so a test in two browser projects is two tests.
|
|
`gstack-flaky ids --junit <file>` prints them.
|
|
- **Ledger.** One JSON line per flaky pass (`kind: flaky-pass`), per test
|
|
that failed its rerun (`rerun-fail`) and per quarantined test on every run
|
|
(`quarantined-pass`, `quarantined-fail`, `hard-break`), with the tree, commit, branch, run URL,
|
|
attempts, the rerun's scope (`test` or `command`) and the first lines of
|
|
the error. Ids, paths and failure text go through gstack's redaction engine
|
|
first; when the scan cannot run, they are withheld. The path is `--ledger`,
|
|
else `GSTACK_FLAKE_LEDGER_JUNIT`, else
|
|
`<state root>/flake-ledger-junit.jsonl`, and `FLAKY_RESULT` names it. It is
|
|
kept apart from the free suite's file-level ledger (`GSTACK_FLAKE_LEDGER`).
|
|
A ledger write error is a warning and never changes the verdict.
|
|
|
|
## Output and exit codes
|
|
|
|
One `FLAKY: <flaky-pass|fail|rerun-fail|quarantined-pass|quarantined-fail|hard-break> <id> attempts=<…> (<reason>)`
|
|
line per test that failed at least once and per quarantined test,
|
|
`FLAKY_RERUN: scope=command (<why>)` when the rerun repeated the whole command, then
|
|
`FLAKY_RESULT: tests=<n> failed=<n> flaky=<n> quarantined=<n> reruns=<n> command_exit=<n> verdict=pass|fail ledger=<file|none>`.
|
|
`failed` counts every outcome but `flaky-pass` and `quarantined-pass`; `quarantined`
|
|
counts the quarantined tests' outcomes, which are never counted as passes.
|
|
|
|
| Exit | Meaning |
|
|
|---|---|
|
|
| 0 | Every test passed, flaky passes included |
|
|
| 1 | A test failed (after its rerun, or with no rerun), including `FLAKY_UNREPORTED_FAILURES`, a quarantined test's hard break or missing result, and a refused `quarantine` command |
|
|
| 2 | Usage error, including a `--junit` path that is not a `.xml` file, or an existing file there that is not a readable JUnit report |
|
|
| 3 | No usable report, a crash, or a killed runner (a code below on stderr) |
|
|
|
|
| Code | Exit | Cause | Fix |
|
|
|---|---|---|---|
|
|
| `FLAKY_NO_RESULTS` | 3 | No report at `--junit`, an empty one, or one with no testcase | Make the command write JUnit to that path |
|
|
| `FLAKY_JUNIT_INVALID` | 3 | The report is not well-formed XML | Make sure one process writes it and nothing appends to it |
|
|
| `FLAKY_RETRIES_HIDDEN` | 3 | Playwright retried but its report omits the retries | Set `PLAYWRIGHT_JUNIT_INCLUDE_RETRIES=1` where the report is written |
|
|
| `FLAKY_COMMAND_FAILED` | 3 | Non-zero exit with no failed test | Read the command output: a real red |
|
|
| `FLAKY_COMMAND_KILLED` | 3 | The runner was killed by a signal (a cancelled job, an OOM kill) | Nothing was rerun; rerun the job |
|
|
| `FLAKY_COMMAND_NOT_STARTED` | 3 | The command could not be started | Check the argv after `--` |
|
|
| `FLAKY_UNREPORTED_FAILURES` | 1 | The runner counted failures or errors its JUnit omits | Fix the load error or the error outside any test: a real red |
|
|
| `FLAKY_LEDGER_WRITE_FAILED` | — | The ledger could not be appended (warning) | Check the path; the verdict stands |
|
|
| `FLAKY_QUARANTINE_INVALID` | 3 | `.gstack/quarantine.json` is not valid JSON or not a schema 1 registry | Fix the file; `quarantine check` names the problem |
|
|
| `FLAKY_QUARANTINE_BASE` | 3 | `--base` does not resolve to a commit (exit 2 for a value starting with `-`), or `check` finds no merge base | Fetch the base branch; `check --base` needs `fetch-depth: 0` |
|
|
| `FLAKY_QUARANTINE_REFUSED` | 1 | `add`, `renew` or `release` broke a rule | Read the reason; [Quarantine](#quarantine) lists the rules |
|
|
| `FLAKY_QUARANTINE_USAGE` | 2 | An unknown `quarantine` command or option, or a missing value | `gstack-flaky quarantine --help` |
|
|
| `FLAKY_QUARANTINE_EXPIRED` | — | Notice: an expired entry no longer applies | Fix the test, renew once, or release; the line prints both commands |
|
|
| `FLAKY_QUARANTINE_IGNORED` | — | Notice: an entry breaks a rule and does not apply | Fix the entry; `quarantine check` names the rule |
|