Claude opencode Skill

regression-testing

Execute regression test suites via CI/CD, analyze results, classify failures, and produce GO/NO-GO release decisions. Use when running regression, smoke, or sanity suites through GitHub Actions, monitoring workflow runs, downloading Allure or Playwright artifacts, classifying fai

LLM Mart · 0 points · 20 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download upex-galaxy-agentic-qa-boilerplate-.agents_skills_regression-testing-d287bb2.zip · 44 KB
Part of upex-galaxy/agentic-qa-boilerplate — 13 skills

Install

skills CLI npx skills add https://github.com/upex-galaxy/agentic-qa-boilerplate/tree/main/.agents/skills/regression-testing
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install upex-galaxy-agentic-qa-boilerplate@llmmart
Git git clone https://github.com/upex-galaxy/agentic-qa-boilerplate.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole upex-galaxy/agentic-qa-boilerplate collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Forbidden invocations

NEVER invoke /sdd-* skills from this workflow. SDD is an optional user-installed ceremony; this skill ships self-contained and does not chain SDD under any condition. If you need to refactor KATA, fixtures, cli/, scripts/, or api/schemas/ pipeline, exit this skill first and invoke /framework-development — which itself runs Plan → Code → Verify → Archive natively (no SDD required).

This boundary is mechanical, not advisory: scripts/lint-skills.ts rejects any /sdd- mention outside this section. See: .agents/skills/agentic-qa-core/references/skill-composition-strategy.md §4 (governs users who manually install SDD).

Regression Testing — Execute, Analyze, Decide

Orchestrates the full release-readiness pipeline: trigger a CI suite, monitor it to completion, classify failures, score against release criteria, and emit a GO / CAUTION / NO-GO verdict plus a stakeholder report.

Three phases, always in this order: Execute → Analyze → Report. Do not skip analysis and jump to a report. Do not guess classification without reading failure logs.


Compact Rules

  • DO: run Execute → Analyze → Report in that order. Never skip analysis and jump to a report, and never classify a failure without reading its logs.
  • DO: clear the readiness preflight before triggering anything — gh authenticated, the suite's workflow file present, GitHub Actions secrets set, Allure resolvable, active env confirmed. A 20-60 minute run that 401s mid-way is the expensive failure.
  • DO: persist RUN_ID the moment the trigger returns, before anything else. Resume re-attaches to a live run instead of re-triggering CI; a trigger that landed without the id saved costs the whole run again.
  • DO NOT: mark a failure REGRESSION without checking its history first — the single most common misclassification. A first-ever failure with no history is NEW TEST, unverified, not a regression.
  • DO: classify every failure into exactly one of KNOWN-BLOCKED / KNOWN ISSUE / ENVIRONMENT / NEW TEST / FLAKY / REGRESSION, and assess severity on a separate axis — a FLAKY test on checkout is still CRITICAL.
  • DO: exclude @blocked:{BUG-KEY} tests from the gating pass-rate and report their count with each blocking key. They are parked behind an already-filed bug: never REGRESSION, and never a new bug.
  • DO NOT: use ENVIRONMENT as a scapegoat. Many unrelated tests failing on one host is environment; one test failing on an endpoint other tests reach fine is more likely a REGRESSION.
  • DO NOT: call a test flaky on fewer than 5 runs of history — mark "insufficient history" and re-evaluate rather than guessing.
  • DO NOT: emit GO while any REGRESSION-class failure stands. Hard vetoes regardless of score: any @critical test failing, any HIGH/CRITICAL-severity regression, or a pass rate below 90%.
  • DO: file only CONFIRMED product failures — the REGRESSION class, plus a NEW TEST failure once manually confirmed to be a real defect. FLAKY, ENVIRONMENT and KNOWN ISSUE get no issue at all. Triage decides WHETHER to file; the defect-management doctrine decides the type and the fields.
  • DO NOT: open a GitHub issue for a quality failure. It is filed in the issue tracker, parented to the QA Defect Management process epic and linked to the source Story — never to a product or dev epic.
  • DO: create every Test Execution with its Test Environment (from active_env) and assignee = self at create time, close the STR only AFTER the verdict is written, and leave the RTP at its ready status — a suite run never completes the plan it ran from.
  • DO NOT: invent a sprint number. Take N from the user or from the STP's own scope-id; a guessed N forks a duplicate STP/STR pair. Nothing found and nothing given → ask before creating at sprint altitude.
  • DO NOT: skip the artifact download on a red build (evidence vanishes after the retention window), and never merge smoke and regression results into one pass-rate — their SLOs differ.

Read full SKILL.md when: driving the CI commands, applying the GO/CAUTION/NO-GO scoring table, resolving a borderline classification, wiring the TMS artifacts, or writing the report.


Inputs

  • .github/workflows/*.yml — workflow files for regression / smoke / sanity suites; defines triggers, inputs, and artifact uploads. LOAD /github-actions-docs before editing or diagnosing one: Actions syntax (matrix, needs, reusable workflows, artifact retention, permissions) is the part of this skill's surface that changes upstream without telling anyone, and a guessed key fails at runner start with a message that points nowhere. Reading one does not need it; changing one does.
  • .context/master-test-plan.md — regression Epic key + expected pass-rate SLOs per suite.
  • playwright.config.ts — reporter config, retry policy, project matrix; needed to interpret retry counts and shard splits.
  • Previous run's Allure report (artifact URL or local download under ./analysis/previous/) — baseline for trend computation.
  • kata-manifest.json — registry of tests and ATCs available; used to cross-reference failed test IDs.
  • .agents/jira-required.yaml — Jira refs (project key, work types, transitions) for filing regression issues.
  • agentic-qa-core/references/defect-management-doctrine.md — canonical authority for classifying (Bug/Defect/Improvement), the mandatory field matrix, QA-Assignee ownership, and the QA process epic when a confirmed regression is filed in Jira (Phase 3). Read BEFORE filing any defect.
  • agentic-qa-core/references/artifact-lifecycle.md — canonical authority for artifact statuses: the STR closes at {{jira.status.test_execution.close}} after the verdict, the RTP stays at {{jira.status.test_plan.ready}}, every created artifact carries assignee = self, and an unmapped transition slug goes through the §4 fallback instead of a silent skip. Read BEFORE firing any transition.

Subagent Dispatch Strategy

Orchestration & Session contracts: this skill follows agentic-qa-core/references/orchestration-doctrine.md (mandatory subagent dispatch — main thread is command center) AND agentic-qa-core/references/session-management.md (Phase 0 resume check, plan-first persistence at .session/<skill-slug>/<scope>/, archive on completion). Phase 0 (resume check) and Phase 1 (plan write) are NOT optional. The orchestrator also applies the per-stage Definition-of-Done gates in agentic-qa-core/references/stage-gates.md: verify a stage's DoD BEFORE recording its progress checkpoint and advancing.

This skill is per-run scope: <scope> = <env>-<YYYY-MM-DD> (e.g. staging-2026-05-20). Session state lives at .session/regression-testing/<scope>/{plan.md, progress.md} per agentic-qa-core/references/session-management.md §3 + §9. The single highest-value resume case: if the Monitor subagent dies while watching a long CI run but RUN_ID was captured in plan.md, Phase 0 re-attaches via gh run view <RUN_ID> instead of re-triggering CI (saves 20–60 min of wall-clock).

This skill is compliant with the doctrine in AGENTS.md §"Orchestration Mode (Subagent Strategy)" and the session contract in .agents/skills/agentic-qa-core/references/session-management.md. Every dispatch follows the 7-component briefing format defined in .agents/skills/agentic-qa-core/references/briefing-template.md, and the pattern selected per stage matches the decision guide in .agents/skills/agentic-qa-core/references/dispatch-patterns.md. The two CI-bound stages (long-running watch, multi-artifact download) and the high-volume failure classification step are the hotspots — everything else stays inline because the dispatch overhead is not justified.

Stage Pattern Subagent role
Trigger workflow (gh workflow run) Single inline — no dispatch needed (one shell call)
Wait/monitor gh run watch Background one Monitor subagent runs the watch; main thread continues with prep work; subagent notifies on exit
Download 3 artifacts (allure / evidence / playwright) Parallel 3 simultaneous subagents, one per artifact; cap = 3 (no rate-limit risk)
Classify failures (chunks of ~10 tests each) Parallel N subagents based on failure volume; cap = 10 to avoid context dilution
Compute metrics (pass-rate, trends) Single inline — needs aggregated state, low cost
Generate executive report Single inline — final synthesis, decisions live here
GO / CAUTION / NO-GO verdict Single inline — main thread owns release decisions
  • Error protocol: On any subagent failure: STOP, report full context to user, present retry / skip / abort options. Do NOT auto-fix. See .agents/skills/agentic-qa-core/references/orchestration-doctrine.md.

Fleet seam (optional)

Triage itself is never parallelized across sessions: one conductor reads the run, classifies, and owns the verdict. The seam is for what comes AFTER Phase 2, when the classification leaves several independent failure clusters that each need code — and only when the user asks for them to be worked at once.

  • Topology: one worktree per failure cluster. A cluster's fix is code (a spec, a locator, a fixture), so each worker gets its own checkout and its own branch; two sessions in one checkout contend on the git index even on disjoint files. One cluster = one worker = one branch. Never two workers on one cluster.
  • The conductor writes launch.txt in .session/regression-testing/<scope>/ — one self-contained line per cluster — always, whether or not any orchestration transport exists on the machine. Launching, supervising and closing those sessions is orca-orchestration/SKILL.md ([ORCHESTRATION_TOOL]): supervised launch is the native path, and launch.txt is the payload for the human-paste fallback when nothing can launch it.
  • The verdict never moves. GO / CAUTION / NO-GO, the metrics, the STR and every Jira write stay with the conductor (Phase 3). A worker fixes its cluster and reports; it does not re-score the run, does not file the defect, and does not transition the STR.
  • Each worker's fix is authored under /test-automation (Plan → Code → Review) on its own branch, and lands per git_strategy — a regression fix is not exempt from the automation gate.
  • Silence rule: the absence of an orchestration transport is never named to the user, never appears in the preflight gate, and never appears in the Environment block or the report.

Readiness Preflight Gate (MANDATORY — runs before Phase 0)

Full doctrine: agentic-qa-core/references/preflight-gate.md. Runs FIRST, before the resume check and any gh workflow run. Two laws: (1) args-as-answers — the suite (regression/smoke/sanity), env, and any grep/test_file are provided args; ask only the gaps. (2) probe, don't assume. Surface gaps + REDs as ONE AskUserQuestion checklist; self-fix with approval + explanation; STOP on any blocking RED. This generalizes the Phase 1 §Preflight (gh auth) to a full readiness check pulled to t=0. Generic baseline (env resolution, secret/restart handling, the two laws, output contract) is inherited from the reference §3.1 — not repeated here. Below is only this skill's specific capability delta (note: test-user creds, MCPs and browsers live inside the CI runner, not the orchestrator).

Capability Need Why here
GitHub CLI authenticated REQUIRED Every stage drives CI via gh (gh auth status, gh workflow run, gh run watch, gh run download). Not authed → user runs gh auth login (suggest the ! prefix); do not proceed.
Workflow files present REQUIRED .github/workflows/ must hold the regression/smoke/sanity workflow for the chosen suite, with the inputs this skill passes.
GitHub Actions Secrets/Variables REQUIRED The runner authenticates with env-prefixed creds (secrets.<ENV>_USER_EMAIL / _PASSWORD) + XRAY_* / ATLASSIAN_* as Repository/Environment Secrets — the suite 401s mid-run without them. gh secret list (add --env <env> for environment scope) shows them; missing → gh secret set <NAME> from .env. /adapt-framework only emits a manual list today, so this is the most common silent gap.
Allure 3 local REQUIRED bunx allure resolves (devDep, no global install); allurerc.mjs present for bun allure:agent markdown triage.
Active env REQUIRED The suite runs against <<ACTIVE_ENV>> (default {{DEFAULT_ENV}}). Confirm it is the intended target before a 20–60 min run.
[TMS_TOOL] (result sync) OPTIONAL Only when .agents/project.yaml testing.tms_cli is set — Stage 3 pushes run status. jira-xray → /xray-cli + XRAY_*.
[ISSUE_TRACKER_TOOL] (file regression issues) OPTIONAL Only on NO-GO / CAUTION-with-regressions, to file issues. Load /acli then.

Test-user creds, OpenAPI/API_TOKEN, DBHub and Playwright browsers live inside the CI runner, not the orchestrator — this skill does not exercise them locally, so they are out of scope for this gate. After the gate clears (all REQUIRED GREEN), continue to Phase 0 below.


Phase 0 — Session resume check (MANDATORY, inline)

Before suite selection or any gh workflow run, run the resume contract from agentic-qa-core/references/session-management.md §4:

  1. Compute prospective <scope> = <env>-<YYYY-MM-DD> from invocation context (env defaults to {{DEFAULT_ENV}}).
  2. Check .session/regression-testing/<scope>/progress.md.
  3. If it does NOT exist → proceed to suite selection + Phase 1 preflight + plan.md write.
  4. If it DOES exist:
    • Read plan.md (captured suite, env, workflow_file, RUN_ID if Phase 1 already triggered).
    • Read tail of progress.md.
    • If RUN_ID is present AND progress.md last entry is Phase 1 — Trigger — status: completed but Monitor entry is missing/failed: surface the option to re-attach to the existing RUN_ID via gh run view <RUN_ID> --json status,conclusion instead of re-triggering. This is the high-value resume case.
    • Otherwise surface the standard offer resume / restart / abort. On restart, archive to .session/.archive/<YYYY-MM-DD>-regression-testing-<scope>-aborted/ first.

When to run each suite

Suite Workflow file Duration Use when
regression regression.yml 20-60 min Pre-release validation, nightly full run
smoke smoke.yml 2-5 min Post-deploy health check, @critical only
sanity sanity.yml 1-10 min Validate one feature / one file / one grep pattern

If the user says "run regression" with no qualifier, default to regression on {{DEFAULT_ENV}}. If they say "smoke" or "critical only", use smoke. If they specify a file, grep, or single feature, use sanity.


Local reporting (Allure 3, no global install)

Allure 3 is a devDep — bunx allure resolves to the local node_modules/.bin/allure, no brew install allure / scoop install allure required. Configuration lives at allurerc.mjs, single-plugin BY DESIGN: with only the Awesome plugin the generated index.html IS the report (no card-chooser landing), and its top-left mode dropdown covers everything — Report (drill-down, tag filters), Graphs (complete executive chart set: status, dynamics, severities, stability, testing pyramid, durations…), Timeline. Never add plugin-dashboard instances — they duplicate Graphs with fewer charts and bring back the landing screen (rationale in allurerc.mjs comments). Trend charts are fed by historyPath: ./.allure/history.jsonl and populate from the 2nd run onward.

Use case Script Underlying command
Run tests + auto-generate report (human review) bun allure:run bunx allure run -- bun test
Run tests + emit markdown for AI review bun allure:agent bunx allure agent -- bun test
Generate report from existing ./allure-results bun allure:generate bunx allure generate ./allure-results
Serve last generated report locally bun allure:open bunx allure open
Live-refresh report during iterative dev bun allure:watch bunx allure watch ./allure-results

bun allure:agent is the AI-friendly entry point: it produces a markdown summary the orchestrator (or a Verifier subagent) can read directly without parsing HTML. Use it whenever you need a structured pass/fail breakdown after a local re-run while triaging a CI failure (Phase 2 step 1, before downloading the merged-allure-results artifact from CI).

CI artifacts (merged-allure-results-{env}) are still produced by the workflow and downloaded via gh run download as documented in Phase 2. The published GitHub Pages reports are generated by scripts/ci/publish-allure-pages.ts with the SAME allurerc.mjs and allure devDep as local runs — the /{env}/{suite}/ URL redirects straight into the latest run's Awesome report (Report | Graphs | Timeline), with per-suite trend history and last-10-runs retention.

Allure version-currency check (MANDATORY during any Allure/Pages setup)

The boilerplate pins allure / allure-playwright / allure-js-commons at scaffold time, so by the time someone installs the repo and runs this setup they are usually behind upstream. Whenever this skill performs Allure setup (first local report, preflight RED on the "Allure 3 local" row) or GitHub Pages setup (references/github-pages-setup.md), run this check FIRST:

  1. npm view allure version && npm view allure-playwright version → compare against package.json.
  2. Same major behind → summarize the news for the user (release notes: gh api repos/allure-framework/allure3/releases), then offer bun update allure allure-playwright allure-js-commons (or bump the ^ ranges + bun install). Keep allure-js-commons in lockstep with allure-playwright (it is imported directly by tests/components/TestFixture.ts for the layer auto-label).
  3. New major available → NEVER upgrade silently. Present breaking changes and wait for explicit user approval.
  4. Config-currency (older scaffolds) — bun run update syncs skills and appends new devDeps, but it NEVER overwrites allurerc.mjs or tests/components/TestFixture.ts (project-adapted files). If the local allurerc.mjs predates the current template (no historyPath, no categories, or stale plugin-dashboard instances), OFFER to migrate it: fetch the boilerplate's current allurerc.mjs as reference (https://raw.githubusercontent.com/upex-galaxy/agentic-qa-boilerplate/main/allurerc.mjs), preserve the project's name, and port the config. Same for the _allureLayer auto-fixture in TestFixture.ts (feeds the testingPyramid + durations-by-layer charts in Awesome's Graphs tab) — without it those charts render empty. Never overwrite silently; show the diff and wait for approval.
  5. After any bump: bun allure:generate from existing results (or a sandbox run) and confirm the report renders — the root index.html must open the Awesome report directly, with the Report | Graphs | Timeline mode dropdown working.

Known gotchas to preserve on upgrade (context in allurerc.mjs comments):

  • Dashboard chart type values must match ChartType in @allurereport/charts-api — the plugin README's trend/pie examples are stale and yield an empty dashboard (404 on widgets/charts.json).
  • historyPath must stay OUTSIDE allure-report/ (./.allure/history.jsonl) or test:clean erases trend history.
  • Multiple instances of one plugin need an explicit import: field — a custom key alone does not resolve (relevant only if a project deliberately adds extra report views).

Phase 1 — Execute

Preflight (always)

gh auth status
gh repo view --json name,owner
gh workflow list

If gh is not authenticated, stop and ask the user to run gh auth login. Do not proceed.

Write .session/regression-testing/<scope>/plan.md per agentic-qa-core/references/session-management.md §6 BEFORE the Trigger step below. Capture: Goal (suite + env + reason for run), Inputs (workflow file path, env vars, optional grep/test_file for sanity), Approach (subagent pattern per stage from the dispatch table above), Phase breakdown (Trigger → Monitor → Download → Classify → Compute → Report → Verdict), Risks, Verification checklist (all 3 artifacts download + verdict emitted), Cross-references (.context/reports/regression-<env>-<date>.md will hold the final verdict). RUN_ID lands in plan.md §Inputs AFTER the Trigger step captures it — append, do not rewrite the body.

Trigger

# Full regression
gh workflow run regression.yml \
  -f environment=staging \
  -f video_record=false \
  -f generate_allure=true

# Smoke
gh workflow run smoke.yml -f environment=staging -f generate_allure=true

# Sanity (grep OR test_file, never both)
gh workflow run sanity.yml -f environment=staging -f test_type=e2e -f grep="@auth"
gh workflow run sanity.yml -f environment=staging -f test_file="tests/e2e/auth/login.test.ts"

Capture run ID

# Wait 3-5 seconds for the run to register, then:
gh run list --workflow=regression.yml --limit=1 --json databaseId,status,createdAt -q '.[0].databaseId'

Store as RUN_ID. Every subsequent step uses it.

Progress checkpoint after Trigger: append RUN_ID to .session/regression-testing/<scope>/plan.md §Inputs (so resume can re-attach) AND append a phase entry ## Phase 1.Trigger — <ts> with status: completed, next: Phase 1.Monitor, notes: RUN_ID=<value> to progress.md. This is the critical persistence point — Trigger landing without RUN_ID persisted means resume cannot re-attach.

Monitor to completion

Use the dispatch defined in §Subagent Dispatch Strategy: Background. Delegate gh run watch <RUN_ID> to a Monitor subagent so the main thread is freed to prepare the report scaffold and load the classification rubric. See references/ci-cd-integration.md §"Monitoring the workflow run (Background dispatch)" for the full briefing.

Reference command (executed inside the subagent, not inline on the main thread):

gh run watch <RUN_ID> --exit-status
# Fallback polling (only if gh run watch is unavailable):
gh run view <RUN_ID> --json status,conclusion
# status: queued | in_progress | completed
# conclusion (only when completed): success | failure | cancelled | timed_out

Do not start Phase 2 until the Monitor returns status: completed.

Output of Phase 1

A short execution summary with: workflow name, run ID, environment, duration, conclusion, per-job status, artifact list, and the Allure URL pattern https://{owner}.github.io/{repo}/{environment}/{suite}/.

Read references/ci-cd-integration.md when configuring new workflows, debugging CI-only failures, tuning sharding / retries / timeouts, or wiring up secrets and variables.


Phase 2 — Analyze

Step 1: Collect data

Use the dispatch defined in §Subagent Dispatch Strategy: Parallel for the three artifact downloads (allure / evidence / playwright). Fan out three subagents in a single tool-call block — each owns one artifact, writes to its own directory, and reports back when its download is verified. The metadata reads (gh run view) stay inline because they are short.

Reference commands (the metadata reads run inline; the three gh run download calls live inside the parallel subagents):

# Inline (main thread): full run context
gh run view <RUN_ID> --json status,conclusion,jobs,createdAt,updatedAt,url,headBranch,event,actor

# Inline (main thread): failed logs only (much smaller than --log)
gh run view <RUN_ID> --log-failed

# Inline (main thread): list artifacts so the parallel dispatchers know what to fetch
gh run view <RUN_ID> --json artifacts --jq '.artifacts[].name'

# Parallel subagent A — allure results
gh run download <RUN_ID> -n merged-allure-results-staging -D ./analysis/

# Parallel subagent B — failure evidence (screenshots, traces, videos)
gh run download <RUN_ID> -n e2e-failure-evidence       -D ./analysis/evidence/

# Parallel subagent C — playwright HTML report
gh run download <RUN_ID> -n e2e-playwright-report      -D ./analysis/playwright/

Each subagent uses the briefing shape in agentic-qa-core/references/briefing-template.md §"Parallel — Download 3 CI artifacts in regression-testing". Cap the fan-out at 3 — there are only ever three artifact streams and GitHub's per-run rate limits are not a concern at that size.

Step 2: Parse results

Source of truth priority: Allure results JSON > Playwright report.json > raw logs. Each Allure result has status, statusDetails.message, statusDetails.trace, and labels[] (look for testId = ATC ID, suite, and severity).

The suite label is tag-derived — single source of truth. Allure suite/grouping labels are NOT a separate taxonomy: they derive from the Playwright tag (@smoke / @regression / @e2e / @integration / @critical) that also drives CI scope selection. A test tagged @integration reports suite: integration automatically. So the suite you read here is exactly the scope CI ran — never reconcile it against a parallel Allure label set. Convention owner: test-automation/references/ci-integration.md §3.2.1.

Step 3: Compute metrics

Metric Formula
Total count of results
Passed / Failed / Skipped / Broken count by status
Pass Rate Passed / Total * 100
Duration max(stop) - min(start)
Trend current pass rate − previous run pass rate

Exclude KNOWN-BLOCKED from the gating pass-rate. Tests classified KNOWN-BLOCKED (tagged @blocked:{BUG-KEY}, see Step 4) are parked behind an already-filed bug — they are NOT regression failures and must not depress the pass-rate that drives the GO/NO-GO score. Compute the gating Pass Rate over Total − KNOWN-BLOCKED, and report the blocked count separately (with each {BUG-KEY}) so the release decision is not gamed in either direction.

Previous-run comparison requires downloading artifacts of the previous run:

PREV=$(gh run list --workflow=regression.yml --limit=2 --json databaseId -q '.[1].databaseId')
gh run download $PREV -n merged-allure-results-staging -D ./analysis/previous/

Step 4: Classify every failure

Use the dispatch defined in §Subagent Dispatch Strategy: Parallel when the failure list has more than 10 entries. Shard the failures into chunks of ~10 (cap at 10 subagents) and fan out one classification subagent per chunk; merge their JSON reports in the main thread. For ≤10 failures, classify inline (the dispatch overhead is not justified). See references/failure-classification.md §"Parallel classification (default for >10 failures)" for the full briefing and merge protocol.

Apply this decision tree to each failed test (whether classified inline or inside a parallel subagent). Never mark a test REGRESSION without checking history first — that is the single most common misclassification.

Failed test
  │
  ├── Tagged @blocked:{BUG-KEY}? ────────────► KNOWN-BLOCKED
  │   (test asserts test.fail('Blocked by {BUG-KEY}') — a deliberately
  │    parked test, not a fresh regression; excluded from gating pass-rate)
  │
  ├── Linked to a known-issue ticket? ───────► KNOWN ISSUE
  │
  ├── Error matches environment pattern? ────► ENVIRONMENT ISSUE
  │   (ECONNREFUSED, ETIMEDOUT, net::ERR_, Navigation timeout,
  │    browserType.launch, 502/503, context deadline exceeded)
  │
  ├── No history (first-ever run)? ──────────► NEW TEST FAILURE
  │
  ├── Failure rate > 20% over last 10 runs? ─► FLAKY
  │
  └── Passed in last ≤ 5 runs, now fails? ───► REGRESSION   (release blocker)
Category Impact Action
KNOWN-BLOCKED LOW Already tracked by {BUG-KEY} — exclude from gating pass-rate, list in report with the blocking bug key. No new Jira bug (the marker already names the open bug)
REGRESSION HIGH Block release, file Jira Bug/Defect (Phase 3 §File defects in Jira, doctrine Part 1), assign
FLAKY MEDIUM Schedule stabilization, do not block — no Jira bug
KNOWN ISSUE LOW Document against existing ticket, do not block — no new Jira bug
ENVIRONMENT MEDIUM Re-run after infra check — no Jira bug
NEW TEST LOW Manual verification → if a genuine product defect, file Jira Bug/Defect; else accept or fix

KNOWN-BLOCKED — consuming the blocked-test marker. The @blocked:{BUG-KEY} tag + test.fail('Blocked by {BUG-KEY}') marker is defined in test-automation (references/automation-standards.md §7 Stability; the PROGRESS.md blocked-tests note lives in references/planning-playbook.md) — this skill only consumes it. The GO/NO-GO gate MUST recognize @blocked:{BUG-KEY} tests and classify them as KNOWN-BLOCKED, never REGRESSION: they are deliberately parked behind an already-filed bug, not a fresh failure. Exclude them from the pass-rate that gates the release (see §Compute metrics), and list each in the report under its own heading with the blocking {BUG-KEY}. Do NOT file a new Jira bug — the marker already names the open one.

sdet CI-fallback clause (integration-trunk suites only): an ENVIRONMENT-class red on a Sanity-CI run for a ticket branch may authorize merging into the integration trunk — never the final trunk → main PR — when proven by BOTH (a) the change passing locally on local AND staging, and (b) the same red being present independent of the change (nightly already red, or the failing line is shared pre-existing code). File a separate infra/flake ticket and reference it in the PR. This is NOT a relaxation of the GO bar: a REGRESSION-class failure is never eligible, and the final PR to main still requires a genuinely green test step. See .agents/skills/git-flow-master/references/sdet-integration-trunk.md §CI-fallback clause.

Read references/failure-classification.md when: the decision tree is ambiguous, you need the full error-pattern catalogue, you are classifying a borderline case, or you are computing flakiness over historical runs.

Step 5: Assess severity per failure

Severity is independent of classification. A FLAKY test on the checkout flow is still CRITICAL severity.

Severity Criteria
CRITICAL Core user journey (login, checkout, payment). Any @critical tagged test.
HIGH Major feature (search, profile, dashboard)
MEDIUM Secondary feature (filters, preferences)
LOW Edge case or admin-only path

Output of Phase 2

An analysis block with: metrics table, trend delta, one section per failure category (Regressions first, then Flaky, Known, Environment, New), per-failed-test detail (name, ATC ID, suite, error, last-pass date, screenshot link), job summary, and a preliminary verdict.


Phase 3 — Report & Decide

GO / CAUTION / NO-GO scoring

Compute a weighted score from the analysis. Maximum is 9.

Factor +3 +1 0 -1 -2 -3
Pass Rate ≥ 95% 90–95% < 90%
Regressions 0 1-2 Low 1+ Medium Any High/Critical
Critical tests All pass Any fail
Flaky tests ≤ 3 4-5 > 5

Verdict thresholds:

  • Score ≥ 7 → GO — release approved
  • Score 4-6 → CAUTION — manual review required, document accepted risks
  • Score < 4 → NO-GO — block release, fix regressions, re-run

Never auto-GO if: any @critical test fails, any REGRESSION with HIGH/CRITICAL severity exists, or pass rate < 90%. These are hard vetoes regardless of score.

File defects in Jira (when decision = NO-GO or CAUTION with regressions)

Quality issues go to Jira, not GitHub. A regression-discovered product failure is a defect-management artifact and follows agentic-qa-core/references/defect-management-doctrine.md — the same authority /sprint-testing uses. This skill files the issue IN JIRA with the full mandatory field matrix; it does NOT open a GitHub issue.

Only CONFIRMED real product failures become Jira issues. Use the Phase 2 Step 4 triage as the gate: file in Jira only for the REGRESSION class and for a NEW TEST failure once it is manually confirmed to be a genuine product defect (not a bad assertion). FLAKY, ENVIRONMENT, and KNOWN ISSUE do NOT get a Jira bug — they route to stabilization / infra / the existing ticket as the classification table already prescribes. The failure-triage classification and the defect issue-type are separate axes: triage decides whether to file; the doctrine decides what type and what fields.

For each issue that clears the gate:

  1. Classify Bug vs Defect by the affected feature's lifecycle stage, NOT by where the failure ran (doctrine Part 1): the regressed feature is already live above Staging (production / superior env) → Bug; the feature is still pre-release (Staging or below) → Defect. A genuinely new, desirable behavior surfaced beyond the AC → Improvement (Part 1).
  2. File it in Jira with the full mandatory field matrix (doctrine Part 5): severity (impact-based) → priority auto-derived (Part 5.1), native components = affected product module (Part 3, mandatory & pre-existing), root_cause + error_type + test_environment, qa_assignee = the authenticated session user (self; never-overwrite, Part 2), and evidence (Allure link + failure screenshots/traces/logs from ./analysis/evidence/).
  3. Parent to the QA Defect Management epic — the QA process epic (qa.qa_epics.defect_epic.name), found-or-created; NEVER a product/dev epic (Part 4).
  4. Link to the source Story/feature for traceability via the causal link (Part 4) — the regressed ATC's covering Story.
  5. Write via acli/REST (doctrine Part 6): create with acli workitem create --from-json (create-time customfields under additionalAttributes.customfield_*, native components:[{name}]); set customfields/components on an existing issue via REST PUT /rest/api/3/issue/{KEY}; qa_assignee is read-before-write. Because this stage may run from CI, load /acli first (it owns auth, syntax, and the REST-PUT pattern in references/acli-integration.md).

Run the doctrine's filing gate (Part 9) before submitting each issue. Save the returned Jira key to reference in the report.

TMS sync (optional, when [TMS_TOOL] is configured via .agents/project.yaml testing.tms_cli)

Prerequisite: Load /xray-cli skill (Modality jira-xray) before executing the [TMS_TOOL] commands below. In Modality jira-native, load /acli instead and map test-execution operations to native Jira issues (see test-documentation/references/jira-setup.md).

The sprint regression maps to two Jira items (items-first by excellence — the Story custom field is never used at this altitude).

This skill has no sprint concept of its own. N is NOT derivable from a suite run: take it from the user, or from the Sprint#{N} scope-id of the STP this skill finds. Never invent it — a guessed N forks a duplicate STP/STR pair for the sprint. No STP found and no N given → ASK before creating anything at sprint altitude.

  • STP (Sprint Test Plan) — a Test Plan item titled STP: Sprint#{N}: {sprint objective} (e.g. STP: Sprint#30: Checkout hardening). Parents to the QA Master Test Plan epic (qa.qa_epics.master_test_plan_epic.name); relates to the Sprint. Producer: /sprint-testing — its Session Start find-or-creates the STP on the FIRST ticket of the sprint, and every tested ticket updates it (a live planner: scope, progress). This skill CONSUMES the STP as context; it find-or-creates it only as a fallback when a suite runs and the STP is missing. Never write results into it: an Xray Test Plan aggregates the LATEST status of each of its Tests across all Executions, so the STP rolls up on its own as the ATRs and the STR accumulate — it carries the plan (description) and the human observations (comments), nothing else (test-documentation/references/xray-platform.md §4).
  • STR (Sprint Test Results) — a Test Execution item titled STR: Sprint#{N}: Regression Testing (e.g. STR: Sprint#30: Regression Testing). Parents to the QA Test Artifacts epic (qa.qa_epics.test_artifacts_epic.name); relates to the Sprint; testPlan → STP. Created at sprint CLOSE as the recap of all sprint results — by THIS skill when it runs the closing regression, or completed by /sprint-testing's batch close if that already created it: whoever arrives first creates it, the other completes it. The run's term is Regression Testing — "Sprint" already comes from the Sprint#{N} scope-id, so the title carries no redundant "Sprint Regression".

Environment gate: every Test Execution this skill creates — the STR included — carries the Test Environment taken from active_env in .agents/project.yaml, set at create time. An Execution without its environment fails the checklist: do not write results into it until the environment is set.

Ownership gate: every artifact this skill CREATES (the STR, and the STP in the fallback case) carries assignee = the authenticated session user, set at create time — agentic-qa-core/references/artifact-lifecycle.md §2. Xray refuses membership edits on a Test Plan the caller does not own, so an unassigned Plan turns into a blocker the moment tests must be added to it. If the find returns an artifact someone ELSE owns, do not reassign it silently: ask first.

Lifecycle gate (agentic-qa-core/references/artifact-lifecycle.md §1):

  • The STR is born {{jira.status.test_execution.active}} and MUST be transitioned to {{jira.status.test_execution.close}} via {{jira.transition.test_execution.complete}} after the GO / CAUTION / NO-GO verdict is written — never before the verdict, never left open.
  • The RTP (and any Test Plan this skill only consumed) stays at {{jira.status.test_plan.ready}} and is never completed by a regression run: the RTP is long-lived, and a suite execution does not finish the plan it ran from. Do NOT fire {{jira.transition.test_plan.complete}} here.
  • The STP is closed by whoever owns sprint close, not by this skill — unless this skill IS the sprint close (see the sprint-close DoD in stage-gates.md), in which case {{jira.transition.test_plan.complete}} moves it to {{jira.status.test_plan.completed}} after the STR is closed.
  • Unmapped slug → artifact-lifecycle.md §4 fallback: list the LIVE transitions, propose the closest synonym in ONE AskUserQuestion, fire the live id on yes, recommend bun run jira:sync-workflows. Never skip silently, never guess an id.

Find-or-create the STR before updating it — never assume another producer already created it; if /sprint-testing's batch close got there first, the find returns its item and this skill only completes it:

[TMS_TOOL] Find-or-create Test Execution:
  summary: STR: Sprint#{N}: Regression Testing
  parent: {QA Test Artifacts epic — qa.qa_epics.test_artifacts_epic.name}
  links: {relates to → Sprint; testPlan → STP key}
  environment: {active_env from .agents/project.yaml}

[TMS_TOOL] Update Test Execution:
  executionKey: {STR execution-key}
  results: {per-ATC status + failure comments from Phase 2}

# After the Phase 3 verdict is written — close the run, never leave it ACTIVE:
[ISSUE_TRACKER_TOOL] Transition: {{jira.transition.test_execution.complete}}   # active -> close
  issue: {STR execution-key}

Write the report

Save to .context/reports/regression-{env}-{date}.md. Use references/failure-classification.md only if you need the pattern catalogue; the report template itself is inline below.


Report template

# Regression Quality Report — {env} — {date}

## Executive Summary
**Verdict: {GO / CAUTION / NO-GO}**
Score: {score}/9. {one-line rationale}

| Metric | Value | Threshold | Status |
|--------|-------|-----------|--------|
| Pass Rate | {x}% | >= 95% | {ok/warn/fail} |
| Regressions | {n} | 0 | {ok/warn/fail} |
| Critical failures | {n} | 0 | {ok/warn/fail} |
| Flaky | {n} | <= 3 | {ok/warn/fail} |
| Duration | {d} | - | - |

## Release Blockers
{if NO-GO, enumerate regressions with severity, owner, ETA. Otherwise: "None."}

## Failure Details
### Regressions ({n})
  - {test} | {atc_id} | last passed {date} | [issue]({url}) | probable cause: {...}

### Flaky ({n}) — schedule stabilization
### Known Issues ({n}) — accepted
### Known-Blocked ({n}) — excluded from gating pass-rate
  - {test} | {atc_id} | blocked by [{BUG-KEY}]({url})
### Environment ({n}) — re-run after infra check

## Trend (last 5 runs)
{ASCII sparkline or pass-rate table}

## Links
- Workflow run: {url}
- Allure: {url}
- Created issues: {list}
- TMS execution: {key / url}

## Recommendations
1. Immediate (pre-release): {...}
2. Short-term (this sprint): {...}
3. Long-term (tech debt): {...}

Post-decision actions

Decision Actions
GO Mark release candidate approved; schedule post-deploy smoke
CAUTION Review with team lead; document accepted risks; proceed deliberately
NO-GO Block release; assign regression issues; schedule fix verification; plan re-run

Whatever the verdict, close the run: transition the STR to {{jira.status.test_execution.close}} via {{jira.transition.test_execution.complete}}, leave the RTP at {{jira.status.test_plan.ready}}, then run the light stage verifier (agentic-qa-core/references/artifact-lifecycle.md §5). Stage-specific lines:

[ ] STR exists by KEY, carries its Test Environment, assignee = self
[ ] STR at {{jira.status.test_execution.close}} — via complete, AFTER the verdict
[ ] STR -> STP linked via the `testPlan` edge
[ ] RTP untouched at {{jira.status.test_plan.ready}} (a regression run never completes it)
[ ] Verdict comment posted in the TMS (the durable record — not the local report file)
[ ] Any unmapped slug went through the §4 fallback (asked), never a silent skip

Per-phase progress + Archive

After Phase 1 Monitor returns, after each Phase 2 step (Collect / Parse / Compute / Classify / Severity), and after Phase 3 Verdict, the orchestrator appends a phase entry to .session/regression-testing/<scope>/progress.md per agentic-qa-core/references/session-management.md §7. artifacts_touched records the downloaded CI artifacts (allure / evidence / playwright dirs) + the final .context/reports/regression-<env>-<date>.md.

After the Verdict emits, the orchestrator runs Archive per agentic-qa-core/references/session-management.md §8: moves .session/regression-testing/<scope>/ to .session/.archive/<YYYY-MM-DD>-regression-testing-<scope>/ (two-file dir preserved) and calls mem_session_summary with the archive path. .context/reports/regression-<env>-<date>.md stays in the reports dir as a local generated report — that directory is gitignored [LOCAL] output (.context/reports/README.md), so the file exists only on the machine that ran the suite and nothing downstream may depend on it. The durable record is the STR in the TMS plus the GO / CAUTION / NO-GO comment posted with it.

On Verdict = NO-GO with regressions still being filed as issues, archive WAITS until the issue-creation step completes (so the session state still references the open issue list at archive time).


Gotchas

  • Allure URL is predictable but only live after the "Build & Deploy Allure Report" job succeeds. If that job failed, the URL 404s — analyze from downloaded artifacts instead.
  • gh run watch can time out on long suites. Fall back to polling gh run view <RUN_ID> --json status every 60-90 seconds.
  • gh run view --log dumps every step's output and is often >50MB on large suites. Always prefer --log-failed during analysis; use --job=<JOB_ID> --log for targeted drilldown.
  • This repo ships retries: 0 everywhere (playwright.config.ts) — tests must be deterministic, and a retry would only mask the flake. A flaky test therefore surfaces as a plain intermittent failure and is caught by the >20% history rule, never by a retry-pass signal. If a downstream project has consciously enabled retries, a test that passes on retry is still flaky — see the "Conscious divergence: enabling retries" box in references/ci-cd-integration.md for how to read retry counts in Allure.
  • ENVIRONMENT is not a scapegoat. ECONNREFUSED to your app's own API probably means the app crashed, not "infra glitch". Check if the same run has many unrelated tests failing on the same host — that is environment. One test failing with a network error on an endpoint that other tests hit successfully is more likely a REGRESSION.
  • Never mark NEW TEST as REGRESSION. A first-ever failure with no history is not a regression — it is unverified. Manually confirm once before classifying.
  • Flakiness needs 5 runs of history minimum before you can call it at all (below that, mark "insufficient history" and re-evaluate next sprint — do not guess). The failure-rate itself is computed over a wider window: the last N = min(10, available) runs (see references/failure-classification.md). 5 is the floor to have any signal; 10 is the window the percentage is actually computed over.
  • Sanity + grep and test_file are mutually exclusive. Passing both makes the workflow ignore one silently. Pick one.
  • Video recording inflates artifact size by 5-10x. Only enable video_record=true when debugging flakiness or capturing bug evidence. Never enable it for nightly regression.
  • CI credentials come from GitHub secrets, not .env. Do not copy values from local .env into workflow YAML — reference ${{ secrets.NAME }} only.
  • Session-footer contract (mandatory at close). The final phase is not done until the two chat-facing blocks from ../agentic-qa-core/references/session-footer-contract.md are printed: (1) consolidated screenshot list — repo-relative paths, verified on disk, bug annotations first — plus in-flow surfacing of every capture's path the instant it lands; (2) Session Footer listing skills/MCPs/CLIs actually used + testing levels touched, with explicit "none" entries for expected-but-untouched levels. Framing for this skill: execution. Multi-subagent sessions: each stage report carries the five footer fields (skills_loaded, mcps_used, clis_used, testing_levels_touched, screenshots_captured); the orchestrator compiles the footer ONCE at close. Chat only — never in a Jira comment or ATR body.

Specific tasks

  • Configuring or debugging GitHub Actions workflows — read references/ci-cd-integration.md
  • Enabling GitHub Pages so the published Allure reports are browsable ("set up GitHub Pages", "report URL is 404", "publish the reports site") — read references/github-pages-setup.md (enable via gh api, first-build stuck/errored gotcha + manual rebuild, gh-pages history squash job). Run the §Allure version-currency check first.
  • Making CI reports PRIVATE ("reports must be login-protected", "no publiques evidencia pública", "protege los reportes") — read references/private-hosting-setup.md (Test Report Portal: Vercel + Supabase + private R2, work-email login, portal-side retention, history round-trip replacing gh-pages). The publish step in all three suite workflows is already dual-mode — you only wire secrets. GitHub Enterprise orgs have a zero-infra shortcut (Pages visibility → Private); offer it first.
  • Setting up Allure locally for the first time, or the user asks "is Allure up to date?" — run the §Allure version-currency check under §Local reporting.
  • Classifying a borderline failure (REGRESSION vs FLAKY vs ENVIRONMENT) — read references/failure-classification.md
  • TMS / Xray result import — load /xray-cli skill
  • Downloading traces or screenshots for a failure — use [AUTOMATION_TOOL] per AGENTS.md Tool Resolution; for Playwright trace inspection load /playwright-cli
  • Session contract (Phase 0 resume, plan.md/progress.md schemas, archive policy, Engram per-phase checkpoint, RUN_ID re-attach mechanism) — read ../agentic-qa-core/references/session-management.md. This skill is a producer of session/regression-testing/<scope>/... topic keys.

Anti-patterns — NEVER do these

  • R1. NEVER classify a failure as FLAKY without re-running the test in isolation — masks real regressions.
  • R2. NEVER emit GO when known REGRESSION class > 0 — quality gate is binary: regressions block.
  • R3. NEVER auto-retry failing tests in CI without surfacing the retry count in the report.
  • R4. NEVER skip Allure artifact download on red builds — evidence vanishes after the retention window.
  • R5. NEVER trigger a regression workflow without --ref <commit-sha> pinned — different commit = different baseline.
  • R6. NEVER mix smoke + regression suite results into one pass-rate number — different SLOs.
  • R7. NEVER mark a test KNOWN-failure without a Jira ticket linking the suppression to a tracking issue.

Quick reference

# Trigger + get run ID in one shot
gh workflow run regression.yml -f environment=staging && sleep 5 && \
  RUN_ID=$(gh run list --workflow=regression.yml --limit=1 --json databaseId -q '.[0].databaseId') && \
  echo "RUN_ID=$RUN_ID"

# Wait for completion
gh run watch $RUN_ID

# Failed logs only
gh run view $RUN_ID --log-failed

# All failure evidence
gh run download $RUN_ID -n e2e-failure-evidence -D ./analysis/evidence/

# Previous run for trend
PREV=$(gh run list --workflow=regression.yml --limit=2 --json databaseId -q '.[1].databaseId')
gh run download $PREV -n merged-allure-results-staging -D ./analysis/previous/
Files (agentic-qa-boilerplate)
  • evals
    • evals.json 5.4 KB
      {
        "skill_name": "regression-testing",
        "evals": [
          {
            "id": 1,
            "prompt": "Trigger the regression suite on staging and tell me if we can deploy to production.",
            "expected_output": "The assistant invokes the regression-testing skill, triggers gh workflow run regression.yml with environment=staging, captures the run ID, monitors until completion, downloads artifacts, classifies any failures, computes a GO / CAUTION / NO-GO verdict using the scoring matrix, and produces a stakeholder report.",
            "files": [],
            "expectations": [
              "The response references running `gh workflow run regression.yml` with an environment flag",
              "The response captures or references a run ID via `gh run list` or `gh run view`",
              "The response mentions monitoring the run with `gh run watch` or polling `gh run view --json status,conclusion`",
              "The response includes a GO, CAUTION, or NO-GO verdict",
              "The verdict is backed by the scoring matrix or the hard-veto rules (e.g. any @critical failure, any HIGH/CRITICAL regression, pass rate < 90%)"
            ]
          },
          {
            "id": 2,
            "prompt": "The nightly smoke test failed. Analyze the results and classify the failures.",
            "expected_output": "The assistant retrieves the failing smoke run, downloads failed logs and artifacts, and classifies each failed test into KNOWN-BLOCKED, KNOWN ISSUE, ENVIRONMENT, NEW TEST FAILURE, REGRESSION, or FLAKY following the decision tree.",
            "files": [],
            "expectations": [
              "The response uses `gh run view --log-failed` or `gh run download` to gather evidence",
              "Every failed test is placed into exactly one of the six classification buckets",
              "At least one classification includes the error pattern that drove the decision (e.g. ECONNREFUSED -> ENVIRONMENT, or 'element not found after deploy' -> REGRESSION)",
              "The response notes severity (CRITICAL / HIGH / MEDIUM / LOW) alongside classification for any failure in a core flow",
              "The response does not classify a test as REGRESSION without history evidence (or explicitly flags 'insufficient history')"
            ]
          },
          {
            "id": 3,
            "prompt": "Generate a quality report for tomorrow's stakeholder meeting. Include pass rate and trend.",
            "expected_output": "The assistant produces an executive-summary quality report with verdict, metrics table (pass rate, regressions, critical failures, flaky count), trend against the previous run(s), failure details section, release blockers, and recommendations.",
            "files": [],
            "expectations": [
              "The report contains an Executive Summary with a GO / CAUTION / NO-GO verdict",
              "The report contains a metrics table with Pass Rate, Regressions, Critical failures, Flaky count, and each metric is compared to its threshold",
              "The report includes a trend section comparing the current run's pass rate to at least one previous run",
              "The report includes separate sections for each non-empty failure category (Regressions, Flaky, Known, Environment)",
              "The report ends with Immediate / Short-term / Long-term recommendations and is saved under .context/reports/"
            ]
          },
          {
            "id": 4,
            "prompt": "Write a regression test for the bug they just fixed in the login flow.",
            "expected_output": "This request is authoring new test code, not executing regression. The regression-testing skill should NOT be the primary one invoked — the assistant should instead defer to the test-automation skill (or at minimum make clear that regression-testing is not the right fit).",
            "files": [],
            "expectations": [
              "The response does NOT trigger `gh workflow run` or otherwise invoke the regression-testing pipeline",
              "The response either invokes or recommends the test-automation skill",
              "The response does not produce a GO/NO-GO verdict"
            ]
          },
          {
            "id": 5,
            "prompt": "Manually test whether the bug fix for UPEX-123 actually works.",
            "expected_output": "This is manual retest work owned by the sprint-testing skill (single-issue QA flow), not regression-testing. The assistant should not trigger the regression pipeline.",
            "files": [],
            "expectations": [
              "The response does NOT trigger `gh workflow run` for regression, smoke, or sanity",
              "The response does not produce a GO/NO-GO release verdict",
              "The response either invokes or recommends the sprint-testing skill (or a manual QA workflow)"
            ]
          },
          {
            "id": 6,
            "prompt": "Set up GitHub Actions to run our tests on every pull request.",
            "expected_output": "This is a general CI/CD setup question, not a regression-execution request. The regression-testing skill's `references/ci-cd-integration.md` may be useful, but the skill's primary workflow (execute -> analyze -> report) should not trigger. The assistant may reference the skill's ci-cd-integration material but should not invoke a regression run.",
            "files": [],
            "expectations": [
              "The response does NOT trigger `gh workflow run regression.yml` or similar",
              "The response does not attempt to classify failures or produce a GO/NO-GO verdict",
              "Any CI/CD advice given is consistent with the patterns in references/ci-cd-integration.md (PR = build checks only via build.yml, daily scheduled regression.yml + smoke.yml, manual sanity.yml)"
            ]
          }
        ]
      }
      
  • references
    • ci-cd-integration.md 21.9 KB
      # CI/CD Integration — GitHub Actions for Regression Testing
      
      Read this when configuring new workflows, modifying existing ones, debugging CI-only failures, tuning sharding or retries, wiring secrets, or optimizing execution time.
      
      ---
      
      ## 1. Strategy matrix
      
      | Trigger | Tests | Duration | Purpose |
      |---------|-------|----------|---------|
      | Pull request (`build.yml`) | Static checks + compile only — no test execution | 2-5 min | Block PRs that break the framework build |
      | Daily 00:00 UTC (`regression.yml`) | Full suite: integration + E2E, Allure report | 20-60 min | Regression + trend data |
      | Daily 02:00 UTC (`smoke.yml`) | `@critical` smoke projects (`smoke-ui` + `smoke-api`) | 2-5 min | Environment heartbeat |
      | Manual (`sanity.yml`) | Targeted subset (`grep` \| `test_file`) | varies | Verify a fix or a suspect area |
      
      Do NOT run the full E2E suite on every PR — it is too slow and costly. Do NOT ignore flaky tests — fix them.
      
      ---
      
      ## 2. Workflow file layout
      
      The shipped workflows — read the real files, never quote them from memory (Critical Rule #11 applies to workflows just as much as scripts):
      
      ```
      .github/workflows/
      ├── build.yml            On: pull_request → main            → TestBuild checks: env check, types, lint, playwright --list (no test execution)
      ├── regression.yml       On: schedule (daily 00:00 UTC) + workflow_dispatch → full regression (integration + e2e jobs, merged Allure report)
      ├── smoke.yml            On: schedule (daily 02:00 UTC) + workflow_dispatch → @critical smoke suite
      ├── sanity.yml           On: workflow_dispatch              → targeted run (grep | test_file inputs)
      ├── pages.yml            On: push to main + workflow_dispatch → GitHub Pages docs hub deploy
      └── pages-squash.yml     On: schedule (monthly) + workflow_dispatch → squash Pages branch history
      ```
      
      The three test workflows with `workflow_dispatch` (`regression`, `smoke`, `sanity`) are what the regression-testing skill triggers via `gh workflow run`. The two `pages-*` workflows are report/docs plumbing, not test suites.
      
      ---
      
      ## 3. PR workflow — the shipped `build.yml` (framework validation, no test execution)
      
      The shipped PR gate deliberately runs NO tests. It validates that the framework compiles and passes static checks — a smoke test for the test framework itself:
      
      ```yaml
      name: TestBuild Checks
      on:
        pull_request:
          branches:
            - main
      
      env:
        CI: true
        TEST_ENV: 'staging'
        STAGING_USER_EMAIL: ${{ secrets.STAGING_USER_EMAIL }}
        STAGING_USER_PASSWORD: ${{ secrets.STAGING_USER_PASSWORD }}
      
      jobs:
        TestBuild:
          name: Framework Validation
          runs-on: ubuntu-latest
          timeout-minutes: 15
          steps:
            - uses: actions/checkout@v4
              with:
                fetch-depth: 1
            - uses: oven-sh/setup-bun@v2
            - run: bun install
            - run: bun run test:env:check     # validates env configuration
            - run: bun run types:check
            - run: bun run lint:check
            - run: bunx playwright test --list   # compile check — lists tests without running them
      ```
      
      Key points:
      - No test execution on PRs — actual suite runs live in the scheduled `regression.yml` / `smoke.yml` and the manual `sanity.yml`.
      - Credentials are the env-prefixed pair for the selected `TEST_ENV` (`STAGING_USER_EMAIL` / `STAGING_USER_PASSWORD`), needed only so `test:env:check` and config resolution pass. URLs are NOT secrets — they resolve from `.agents/project.yaml` via `config/variables.ts`.
      - `bunx playwright test --list` catches broken imports and type errors in specs without spending CI minutes on browsers.
      
      ---
      
      ## 4. Daily regression — the shipped `regression.yml`
      
      Runs daily at 00:00 UTC and on `workflow_dispatch` (with `environment` and `generate_allure` inputs). Read the real file — this is the shape, not a copy:
      
      ```
      regression.yml
      ├── env: TEST_ENV = inputs.environment || 'staging'
      │        LOCAL_USER_EMAIL / LOCAL_USER_PASSWORD       (secrets)
      │        STAGING_USER_EMAIL / STAGING_USER_PASSWORD   (secrets)
      │        TMS_PROVIDER = vars.TMS_PROVIDER || 'xray'   (repo VARIABLE, not a secret)
      │        AUTO_SYNC + XRAY_CLIENT_ID / XRAY_CLIENT_SECRET (TMS sync, optional)
      │        STP_EXECUTION_KEY                            (secret — the STR's key)
      ├── job: integration   → bun run test:integration  → Sync Results to TMS → uploads integration-allure-results + integration-test-results
      ├── job: e2e           → bun run test:e2e          → Sync Results to TMS → uploads e2e-allure-results + e2e-test-results
      │       (the sync step is `bun run test:sync`, gated on AUTO_SYNC == 'true' AND
      │        TMS_PROVIDER != 'xray' — the xray leg is the XrayImport job below, and
      │        running both would import the same runs twice)
      ├── job: allure-report (if: always, unless generate_allure=false)
      │       merges both allure-results dirs → merged-allure-results-<TEST_ENV>
      │       generates + publishes the Allure report (same allurerc.mjs as local runs)
      └── job: XrayImport   (if: always() && vars.TMS_PROVIDER == 'xray', continue-on-error)
              downloads the *-test-results artifacts → [TMS_TOOL] JUnit import into $STP_EXECUTION_KEY
              skips with an annotation when AUTO_SYNC != 'true', Xray creds are missing,
              or STP_EXECUTION_KEY is unset; a jira-native repo skips the job silently
      ```
      
      Key points:
      - Credentials are the env-prefixed pairs (`LOCAL_*` / `STAGING_*`) matching `config/variables.ts` — there are no `TEST_USER_*` secrets, and no URL secrets: `config.baseUrl` resolves from `.agents/project.yaml` by `TEST_ENV`.
      - TMS sync (Xray) runs off `AUTO_SYNC` + `XRAY_CLIENT_ID` / `XRAY_CLIENT_SECRET`; the Jira-Direct alternative uses `ATLASSIAN_EMAIL` / `ATLASSIAN_API_TOKEN` (present in the file, commented until enabled).
      - **There are two write-back legs, one per modality, and they never both fire.** On a jira-native project the `Sync Results to TMS` step inside each test job runs `bun run test:sync` after the Playwright process has exited (`reports/atc_results.json` is written by `KataReporter.onEnd()`, too late for anything inside the run — issue #27). On an Xray project that step is skipped and the `XrayImport` job below does the import instead.
      - **The Xray write-back leg is the `XrayImport` job**, gated on `TMS_PROVIDER` (a repo VARIABLE — a job-level `if:` can read `vars` but never `secrets`). It runs `if: always()` so a failing suite still reports its results, and `continue-on-error` so a TMS outage never turns a green suite red. `STP_EXECUTION_KEY` names the **STR** Test Execution the JUnit reports import into — never the STP itself; unset means the job skips with a warning annotation rather than minting an orphan Execution.
      - The `allure-report` job runs `if: always()` so failures still produce a report; the Slack failure notification block exists but ships commented out.
      - The artifact name the analysis phase downloads is `merged-allure-results-<TEST_ENV>`.
      
      ---
      
      ## 5. Smoke + sanity — the shipped `smoke.yml` and `sanity.yml`
      
      **`smoke.yml`** — daily at 02:00 UTC and on `workflow_dispatch` (`environment` input):
      
      - Same env block as regression (`TEST_ENV` selector + `LOCAL_*` / `STAGING_*` credential secrets).
      - Single job: `bun run pw:install` → `bun run test:smoke` (the `smoke-ui` + `smoke-api` Playwright projects — `@critical` tagged tests, ONE project per surface so a UI `storageState` never reaches an API test).
      - Publishes its Allure report per environment; the run summary prints the published URL (`.../<TEST_ENV>/smoke/`).
      
      **`sanity.yml`** — `workflow_dispatch` only, with inputs for `environment`, test type, `grep`, and `test_file`:
      
      - Routes to `bun run test`, `bun run test:e2e`, or `bun run test:integration` with the optional `--grep` filter, or runs a single `test_file`.
      - `grep` and `test_file` are mutually exclusive — passing both silently ignores one (see the skill's Gotchas).
      - Uploads `sanity-playwright-report` + test-results artifacts; report publishing supports both the private Portal and GitHub Pages paths.
      
      Neither shipped suite uses sharding or a multi-browser matrix today — the suite runs single-worker (see §6). The sharding recipes in §9 are the scaling path for a downstream project whose suite outgrows one runner.
      
      ---
      
      ## 6. Playwright config for CI
      
      The shipped `playwright.config.ts` is the source of truth — read it, don't quote it from memory. The load-bearing choices:
      
      ```typescript
      import { defineConfig, devices } from '@playwright/test';
      import { config, env } from './config/variables';
      
      export default defineConfig({
        testDir: './tests',
        testMatch: /.*\.test\.ts/,
        fullyParallel: false,
        forbidOnly: !!process.env.CI,   // Fail the build if someone committed test.only()
      
        // KATA Recommendation: Avoid retries - tests should be deterministic
        // If a test fails, investigate immediately rather than masking with retries
        retries: 0,
      
        // Single worker for now - increase when tests are stable and parallelizable
        workers: 1,
      
        reporter: [
          ['./tests/KataReporter.ts'],   // rich terminal output, local + CI
          ['html', { outputFolder: 'playwright-report', open: 'never' }],
          ['json', { outputFile: 'test-results/results.json' }],
          ['junit', { outputFile: 'test-results/junit.xml' }],
          ['allure-playwright', { resultsDir: config.reporting.allureResultsDir, /* ... */ }],
        ],
        use: {
          baseURL: config.baseUrl,   // resolved from .agents/project.yaml by TEST_ENV — never a BASE_URL env secret
          trace: 'retain-on-failure', // flat: with `retries: 0`, `on-first-retry` never fires and a local failure yields no trace
          screenshot: config.reporting.screenshotOnFailure ? 'only-on-failure' : 'off',
          video: env.isCI && config.reporting.videoOnFailure ? 'retain-on-failure' : 'off',
        },
        projects: [
          // global-setup → ui-setup  → e2e | smoke-ui  → global-teardown
          //              → api-setup → integration | smoke-api
          // (dependency-chained projects; see the real file for the full list, incl. sandbox)
        ],
      });
      ```
      
      Rules:
      - `forbidOnly` in CI — non-negotiable. Prevents test.only() slipping into main.
      - `retries: 0` **everywhere, local and CI** — tests must be deterministic. A retry does not fix a flake, it hides it; the failure surfaces immediately and gets investigated, and the classification phase never has to unmask retry-passes.
      - `workers: 1` + `fullyParallel: false` — the shipped suite runs serially. Raise parallelism only when tests are proven independent; scale via workflow-level sharding (§9) before per-runner workers.
      - No `process.env` reads in the config: everything routes through `config/variables.ts` (single source of truth; URLs from `.agents/project.yaml`, credentials from env-prefixed `LOCAL_*` / `STAGING_*` vars).
      
      > **Conscious divergence: enabling retries.** Some downstream projects deliberately set
      > `retries: 1-2` in CI to stabilize a large legacy suite while it is being cleaned up. If
      > you make that call, own its consequences: (1) a green run no longer means a stable
      > suite — a test that passes on retry is still flaky; (2) the Analyze phase MUST read
      > Allure's retry data (`retriesCount > 0` on a `passed` result = a flake observation)
      > and count retry-passes in the flakiness numerator —
      > `effective_failure_rate = (failed + retried_passes) / total`
      > (see `failure-classification.md` §5 "Retry-aware flakiness"); (3) `trace:
      > 'on-first-retry'` starts earning its keep in CI too. Record the decision as an ADR
      > (`.context/ADR/`) — it is a flake-policy decision. With the shipped `retries: 0`, none
      > of this machinery applies: a retry-pass signal cannot occur.
      
      ---
      
      ## 7. package.json scripts
      
      **Read `package.json` directly before quoting any command** (Critical Rule #11) — script names drift, and this doc will not be updated in lockstep. The names CI leans on today:
      
      | Script | Role in CI |
      |--------|-----------|
      | `test` / `test:e2e` / `test:integration` | Full run / `e2e` project / `integration` project |
      | `test:smoke` | `smoke-ui` + `smoke-api` projects (`@critical` grep, one per surface) |
      | `test:env:check` | Validates env configuration before any suite runs |
      | `test:sync` | TMS results sync (`tests/utils/jiraSync.ts`) |
      | `lint:check` / `types:check` | Static gates in `build.yml` |
      | `pw:install` | `playwright install --with-deps chromium` |
      
      Exact commands, flags, and the rest of the script catalogue: open `package.json`.
      
      ---
      
      ## 8. Secrets and variables
      
      Repository Settings → Secrets → Actions (the names match `config/variables.ts` — env-prefixed credentials, one pair per environment):
      
      | Secret | Value |
      |--------|-------|
      | `LOCAL_USER_EMAIL` / `LOCAL_USER_PASSWORD` | Test account for `TEST_ENV=local` |
      | `STAGING_USER_EMAIL` / `STAGING_USER_PASSWORD` | Test account for `TEST_ENV=staging` |
      | `AUTO_SYNC` | Master switch for the TMS write-back — `'true'` to enable. Gates both the `Sync Results to TMS` step and the `XrayImport` job. Absent/anything else = every suite runs with sync off (the workflows default it to `'false'`) |
      | `STP_EXECUTION_KEY` | Key of the **STR** — the Test Execution linked to the sprint's STP, filed under the `QA Test Artifacts` epic. **NOT the STP's own key**: a Test Plan derives its status from Executions and is never written into, so CI refuses to import without a real Execution key and skips with a warning |
      | `XRAY_CLIENT_ID` / `XRAY_CLIENT_SECRET` | Xray Cloud API credentials (TMS sync, Modality jira-xray) |
      | `ATLASSIAN_EMAIL` / `ATLASSIAN_API_TOKEN` | Jira-Direct TMS sync alternative (commented in the workflows until enabled) |
      | `PORTAL_URL` / `PORTAL_PROJECT` / `PORTAL_API_KEY`, `R2_*` | Private report portal publishing (optional; see `references/private-hosting-setup.md`) |
      
      ### Variables (not secrets)
      
      Repository Settings → Secrets and variables → Actions → **Variables** tab:
      
      | Variable | Value |
      |----------|-------|
      | `TMS_PROVIDER` | `xray` (default when unset) / `jira` / `none`. It must be a VARIABLE because the `XrayImport` job gates on it in a job-level `if:`, and that context can read `vars` but never `secrets` |
      
      `bun run setup --variables` **cannot** push this one: that path only writes secrets (`cli/lib/variables-flow.ts` has no `gh variable set`). Set `TMS_PROVIDER` by hand in Settings → Secrets and variables → Actions → Variables.
      
      There is **no `BASE_URL` / `API_BASE_URL` secret and no `TEST_USER_*` pair**: URLs are not secrets — they resolve from the versioned `.agents/project.yaml` through `config/variables.ts`, selected by `TEST_ENV`.
      
      `TEST_ENV` itself is not a stored variable either: the workflows derive it from the `environment` dispatch input, defaulting to `staging`.
      
      Never copy local `.env` values into workflow YAML. Always reference `${{ secrets.NAME }}`.
      
      ---
      
      ## 9. Optimization playbook
      
      ### Sharding (parallel execution)
      
      ```yaml
      strategy:
        matrix:
          shard: [1/4, 2/4, 3/4, 4/4]
      steps:
        - run: bunx playwright test --shard=${{ matrix.shard }}
      ```
      
      4 shards = ~4x faster. Merge reports at the end with `playwright merge-reports`.
      
      ### Dependency caching
      
      ```yaml
      - uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-${{ runner.os }}-${{ hashFiles('bun.lock') }}
      ```
      
      Saves 2-3 minutes per run.
      
      ### Fail-fast (when appropriate)
      
      ```yaml
      strategy:
        fail-fast: true
        matrix:
          browser: [chromium, firefox, webkit]
      ```
      
      Use fail-fast when browsers should behave identically and one failure implies the others will fail. Do NOT use it in nightly — you want full coverage even if one browser is broken.
      
      ### Path filters
      
      ```yaml
      on:
        pull_request:
          paths:
            - 'tests/**'
            - 'config/**'
            - '!docs/**'
      ```
      
      Skips the entire workflow on doc-only PRs.
      
      ---
      
      ## 10. Quality gates
      
      In Settings → Branches → Branch protection:
      
      - Require status checks to pass before merging.
      - Select: `TestBuild Checks / Framework Validation` (the `build.yml` job).
      - Require branches to be up to date before merging.
      
      Result: no PR merges to `main` with red integration tests.
      
      ---
      
      ## 11. Troubleshooting CI-only failures
      
      ### "Playwright browser installation failed"
      Use `bunx playwright install --with-deps chromium`. The `--with-deps` flag installs system libraries.
      
      ### "Out of memory in CI"
      The shipped config already runs `workers: 1`. If a downstream project raised it, drop it back down — and shard at the workflow level (§9) instead of stacking workers on one runner.
      
      ### "Tests flaky in CI, pass locally"
      Two knobs, in order:
      1. Bump timeouts: the shipped config uses `timeout: 60000` with a 10s `expect` timeout — widen per-test with `test.slow()` before touching globals.
      2. Add explicit waits on navigations: `await page.waitForLoadState('networkidle')` (or, better, a deterministic `waitForResponse` on the request the page depends on).
      
      Do NOT reach for retries — the doctrine is `retries: 0` (a retry hides the flake; see §6). If the test still fails intermittently after real waits, it is genuinely flaky — surface it in the Analyze phase and schedule stabilization.
      
      ### "Artifacts not uploaded"
      Add `if: always()`:
      ```yaml
      - uses: actions/upload-artifact@v4
        if: always()
      ```
      Without it, a failed test step aborts the job and skips artifact upload.
      
      ### "Secrets empty in forked PRs"
      GitHub intentionally does not pass secrets to workflows from forked PRs. Mitigations:
      - Mock API in integration tests (no secrets needed).
      - Use `pull_request_target` for trusted operations only (security-sensitive — review carefully).
      
      ### "gh workflow run succeeds but no run appears"
      Race condition — `gh run list` queries before the run registers. Always `sleep 3-5` before listing the run ID.
      
      ---
      
      ## 12. Do / don't
      
      ### Do
      - Run the build checks (`build.yml`) on every PR — fast feedback without spending CI minutes on suites.
      - Let the scheduled `regression.yml` + `smoke.yml` carry suite execution; use `sanity.yml` for targeted verification.
      - Use sharding for any E2E suite > 10 minutes.
      - Cache `~/.cache/ms-playwright` and `node_modules`.
      - Always upload artifacts with `if: always()`.
      - Notify Slack on nightly failures only (PR noise is counterproductive).
      - Keep secrets out of logs — `::add-mask::` if you must echo them.
      
      ### Don't
      - Run full E2E on every PR.
      - Ignore flaky tests — either fix or quarantine with a tracking ticket.
      - Skip cleanup between runs (test data pollution accumulates).
      - Enable retries to "stabilize" the pipeline — the shipped doctrine is `retries: 0` (deterministic tests; a retry hides the flake). Diverge only consciously, per the divergence box in §6.
      - Upload sensitive data in artifacts (screenshots can contain PII).
      - Hard-code credentials in workflow YAML.
      
      ---
      
      ## 13. Monitoring the workflow run (Background dispatch)
      
      The CI run is long (20-60 min). Blocking the main thread on `gh run watch` is wasteful — we delegate to a Monitor subagent and continue with preparation work in the main thread. This section is the canonical reference for the dispatch declared in `regression-testing/SKILL.md` §"Subagent Dispatch Strategy" → "Wait/monitor `gh run watch`" row.
      
      **When to use**: every time we trigger a regression workflow that takes >5 min. (For `smoke` (2-5 min) the dispatch overhead is borderline; classify by actual wall time, not workflow name.)
      
      **Dispatch (Background pattern)**:
      
      Briefing (follows the 7-component format from `agentic-qa-core/references/briefing-template.md`):
      
      ```
      Goal: Watch GitHub Actions run <RUN_ID> until it terminates and report final status.
      Context docs:
        - .github/workflows/regression.yml (workflow definition)
        - <PBI_FOLDER>/test-report-skeleton.md (where main thread is preparing the scaffold)
      Skills to load: (none — uses gh CLI directly)
      Exact instructions:
        1. Run: gh run watch <RUN_ID> --exit-status
        2. Capture exit code and final status (success / failure / cancelled).
        3. Capture run duration (gh run view <RUN_ID> --json conclusion,createdAt,updatedAt).
        4. Capture count of failed tests if failure (gh run view <RUN_ID> --log-failed | grep -c "FAIL ").
      Report format:
        JSON: { "runId": "<RUN_ID>", "status": "success|failure|cancelled", "exitCode": <int>, "durationSeconds": <int>, "failedTestCount": <int|null>, "logsAvailable": <bool> }
      Rules:
        - Do NOT download artifacts — that is a separate Parallel dispatch.
        - Do NOT classify failures — that is a separate Parallel dispatch after artifacts arrive.
        - On gh CLI auth failure: stop and report; do not retry.
      ```
      
      **While the Monitor runs, the main thread**:
      - Reads prior report skeleton from `.context/regression-history/`.
      - Prepares the report header with run metadata already known (commit SHA, branch, workflow name).
      - Loads classification rubric from `failure-classification.md` so it's ready when the run terminates.
      
      **On Monitor return**:
      - If `status === "success"`: skip to artifact download (still Parallel — see SKILL.md §Subagent Dispatch Strategy) only for Allure/Playwright reports; classification step is skipped.
      - If `status === "failure"`: dispatch the Parallel artifact download, then the Parallel classification.
      - If `status === "cancelled"`: report to user, stop, await instruction.
      
      ### Fallback: polling when `gh run watch` is unavailable
      
      If the runner doesn't support `gh run watch` (very old `gh` CLI, restricted network) or the watch errors out repeatedly, the Monitor subagent can fall back to polling — but this still runs inside the subagent, not on the main thread:
      
      ```bash
      gh run view <RUN_ID> --json status,conclusion
      # status: queued | in_progress | completed
      # conclusion (only when completed): success | failure | cancelled | timed_out
      ```
      
      Poll every 60-90 seconds. The Monitor still owns this loop; the orchestrator stays free.
      
      ### Manual cancellation
      
      If the user cancels the run mid-watch (`gh run cancel <RUN_ID>` from another terminal), the Monitor returns `status: "cancelled"`. The orchestrator surfaces this to the user and waits for direction — do not silently re-trigger.
      
      ### Race condition reminder
      
      `gh workflow run` returns before the run is queryable. The orchestrator must `sleep 3-5` before listing the run ID (see §11 "gh workflow run succeeds but no run appears"). The Monitor dispatch happens AFTER the run ID is captured — it does not need its own sleep.
      
    • failure-classification.md 15.3 KB
      # Failure Classification — Complete Reference
      
      Read this when classifying a borderline failure, when the SKILL.md decision tree is ambiguous, when you need the full error-pattern catalogue, or when computing flakiness over historical runs.
      
      Classification dictates release-blocking behavior. A wrong classification either blocks a safe release (false REGRESSION) or ships a bug (false FLAKY). Follow the rules below — do not improvise.
      
      ---
      
      ## 1. The six categories
      
      | Category | Definition | Release impact | Typical action |
      |----------|------------|----------------|----------------|
      | **KNOWN-BLOCKED** | Test tagged `@blocked:{BUG-KEY}` with `test.fail('Blocked by {BUG-KEY}')` — deliberately parked behind an already-filed bug | LOW — excluded from the gating pass-rate | List in the report with the blocking `{BUG-KEY}`; **no new Jira bug** (the marker already names the open one) |
      | **REGRESSION** | Test passed recently, now fails consistently due to a code or data change | HIGH — blocks release | Open issue, assign, fix, verify, re-run |
      | **FLAKY** | Test fails intermittently (> 20% failure rate over last 10 runs) on an unchanged build | MEDIUM — does not block | Quarantine or stabilize next sprint |
      | **KNOWN ISSUE** | Failure is tracked by an existing backlog ticket | LOW — documented, does not block | Reference the ticket in the report |
      | **ENVIRONMENT** | Failure is caused by infrastructure, network, or external dependency — not the app under test | MEDIUM — does not block | Re-run after infra fix |
      | **NEW TEST FAILURE** | First-ever execution, no history to compare against | LOW — needs manual verification | Reproduce manually, then classify |
      
      A failure can only belong to ONE category. When multiple rules match, apply this precedence:
      
      ```
      KNOWN-BLOCKED > KNOWN ISSUE > ENVIRONMENT > NEW TEST > REGRESSION > FLAKY
      ```
      
      Rationale: a `@blocked:{BUG-KEY}` marker is definitive — the test was parked on purpose, so no other rule applies (and it never enters the gating pass-rate; see SKILL.md §Compute metrics). If a ticket already tracks the failure, stop looking. If the error is clearly infrastructure, do not blame the code. A test with no history cannot be a regression yet.
      
      ---
      
      ## 2. Decision algorithm (canonical)
      
      ```
      Input: one failed test result
      
      1. Is the test tagged `@blocked:{BUG-KEY}` (with the `test.fail('Blocked by {BUG-KEY}')` marker)?
         → YES: classify as KNOWN-BLOCKED with the blocking bug key. Exclude from the gating pass-rate. STOP.
         → NO: continue.
      
      2. Is the test's ATC ID or title referenced in any known-issue ticket?
         → YES: classify as KNOWN ISSUE with the ticket URL. STOP.
         → NO: continue.
      
      3. Does the error message match any environment pattern (see §3)?
         → YES and other tests on the same run also failed on the same host: classify as ENVIRONMENT. STOP.
         → YES but this is the only failure in a suite of passing tests on the same host: treat as suspicious — likely REGRESSION disguised as infra. Continue.
         → NO: continue.
      
      4. Is this the test's first recorded execution (no prior Allure history or TMS run records)?
         → YES: classify as NEW TEST FAILURE. STOP.
         → NO: continue.
      
      5. Compute failure rate over the last N runs (N = min(10, available history)).
         → If failure rate > 20% and current build == previous builds (no deploy between them):
           classify as FLAKY. STOP.
         → If failure rate ≤ 20% AND the test passed in at least one of the last 5 runs:
           classify as REGRESSION. STOP.
         → If insufficient history (N < 5 or no previous passes): mark as REGRESSION (candidate),
           re-verify on next run. STOP.
      ```
      
      ### Parallel classification (default for >10 failures)
      
      When the failure list has more than 10 entries, classifying serially burns the orchestrator's context with raw test logs. Instead we shard. This is the canonical reference for the **Parallel** dispatch declared in `regression-testing/SKILL.md` §"Subagent Dispatch Strategy" → "Classify failures (chunks of ~10 tests each)" row.
      
      **Sharding rule**: split the failure list into chunks of ~10 failures (round up). Cap total subagents at 10 — if there are >100 failures, batches must be larger than 10 each.
      
      **Dispatch (Parallel pattern)** — one briefing per chunk, all dispatched in a single message, following the 7-component format from `agentic-qa-core/references/briefing-template.md`:
      
      ```
      Goal: Classify <N> test failures in chunk <CHUNK_INDEX>/<TOTAL_CHUNKS> against the rubric.
      Context docs:
        - .agents/skills/regression-testing/references/failure-classification.md (rubric)
        - <ARTIFACT_PATH>/allure-results/ (raw failure data)
        - .context/regression-history/known-failures.json (if exists — list of KNOWN failures with their classification)
      Skills to load: (none)
      Exact instructions:
        1. For each failure in the chunk:
           a. Read its allure result + screenshot + trace summary.
           b. Apply the decision tree: KNOWN-BLOCKED / KNOWN / ENVIRONMENT / NEW TEST / REGRESSION / FLAKY.
           c. Capture: { test, classification, evidence_paths, confidence: high|low, justification: <50 words }
        2. Cross-check against known-failures.json (if present) — KNOWN classifications must match a prior entry.
      Report format:
        JSON array: [ { "test": "...", "classification": "...", "evidence_paths": ["..."], "confidence": "...", "justification": "..." }, ... ]
        At the end of the array, a summary: { "chunk": <CHUNK_INDEX>, "counts": { "REGRESSION": N, "FLAKY": N, ... } }
      Rules:
        - Do NOT decide GO/NO-GO — that lives in the orchestrator.
        - Do NOT modify known-failures.json — read-only.
        - If a failure can't be classified with high confidence, mark confidence: low and let the orchestrator escalate.
      ```
      
      **Aggregation in the main thread**: after all parallel subagents return, the orchestrator merges the JSON arrays, sums the counts, and feeds the totals into the GO/NO-GO decision. Low-confidence classifications get re-reviewed inline by the orchestrator before the verdict is computed — never auto-promoted.
      
      **Fallback to serial**: if the failure count is ≤10, classify inline — the dispatch overhead is not justified. The same decision tree above is applied per failure, just without the fan-out.
      
      ---
      
      ## 3. Environment error patterns (verbatim matches)
      
      If the error message contains any of the strings below, it is an environment indicator.
      
      ### Network / infrastructure
      - `ECONNREFUSED`
      - `ETIMEDOUT`
      - `ECONNRESET`
      - `EAI_AGAIN`
      - `ENOTFOUND`
      - `net::ERR_CONNECTION_REFUSED`
      - `net::ERR_NAME_NOT_RESOLVED`
      - `net::ERR_INTERNET_DISCONNECTED`
      - `context deadline exceeded`
      
      ### Gateway / proxy
      - `502 Bad Gateway`
      - `503 Service Unavailable`
      - `504 Gateway Timeout`
      - `Cloudflare ... Error 1020` (blocked by rules)
      
      ### Browser / runtime
      - `browserType.launch`
      - `Browser has been closed`
      - `Target page, context or browser has been closed`
      - `Navigation timeout` (usually — see caveat below)
      
      ### Caveat: Navigation timeout
      `Navigation timeout` on a single page after the app deploys is usually REGRESSION (slow or broken page). `Navigation timeout` across multiple unrelated pages in the same run is usually ENVIRONMENT (infra-wide slowdown). Check the scope before classifying.
      
      ---
      
      ## 4. Error-pattern → classification quick lookup
      
      | Error pattern | Likely classification | Note |
      |---------------|----------------------|------|
      | `Element not found` / `locator.click: Target closed` | REGRESSION | UI changed, selector broken |
      | `Timeout X ms exceeded waiting for locator` | REGRESSION or FLAKY | Check history |
      | `expect(received).toBe(expected)` — assertion mismatch | REGRESSION | Logic or data change |
      | `status code 500` / `status code 502` | ENVIRONMENT or REGRESSION | Isolated → REGRESSION; many tests → ENV |
      | `ECONNREFUSED` | ENVIRONMENT | App down or port wrong |
      | `Navigation timeout` on one page after deploy | REGRESSION | Slow page |
      | `Navigation timeout` across many tests | ENVIRONMENT | Infra slowdown |
      | Intermittent pass/fail on unchanged build | FLAKY | Same build, different outcomes |
      | `Test passed in run #N`, fails in #N+1 with code change between | REGRESSION | Bisect the diff |
      | `SyntaxError` / `TypeError` in test file | REGRESSION (test code) | Test code itself broken |
      | `No snapshot found` | NEW TEST FAILURE | First run of a visual snapshot |
      
      ---
      
      ## 5. Computing flakiness (the >20% rule)
      
      A test is FLAKY if its failure rate over the last N runs on unchanged application builds exceeds 20%.
      
      ### Algorithm
      
      ```
      1. Gather results for this test from the last 10 runs of the same workflow + environment.
         (If < 10 available, use what exists but require at least 5.)
      
      2. Exclude runs that were against a different application build
         (different commit SHA on the main branch between runs, or different deploy).
         The goal is "same build, different outcomes" — the signature of flakiness.
      
      3. Among the remaining runs:
         failure_rate = failed_count / total_count
      
      4. Apply threshold:
         - failure_rate > 0.20 → FLAKY
         - 0 < failure_rate ≤ 0.20 → REGRESSION candidate (unless only-in-last-run, then new failure)
         - failure_rate == 0 → not applicable (test is passing — why are you here?)
      
      5. If N < 5: output "INSUFFICIENT HISTORY" — do not guess.
      ```
      
      ### Retry-aware flakiness (conscious-divergence projects only)
      
      This repo ships `retries: 0` everywhere (`playwright.config.ts` — deterministic tests; a retry hides the flake). With the shipped config a retry-pass signal **cannot occur**: every flake surfaces as a plain failure and is caught by the >20% rule above. Skip this subsection unless your project has consciously diverged.
      
      If a downstream project has deliberately enabled retries (see the "Conscious divergence: enabling retries" box in `ci-cd-integration.md`), a test that passes on retry is a hidden flake. Check Allure `retriesCount` for each result — a `passed` result with `retriesCount > 0` counts as a flake observation even though the final status is green.
      
      When reporting flakiness rate on such a project, include retry-passes in the numerator:
      ```
      effective_failure_rate = (failed + retried_passes) / total
      ```
      
      ### Getting history with gh CLI
      
      ```bash
      # Last 10 runs
      gh run list --workflow=regression.yml --limit=10 --json databaseId,conclusion,createdAt,headSha
      
      # Pair of adjacent runs for comparison
      gh run list --workflow=regression.yml --limit=2 --json databaseId,headSha -q '.[] | "\(.databaseId) \(.headSha)"'
      
      # Download artifacts for trend analysis
      for RUN_ID in $(gh run list --workflow=regression.yml --limit=10 --json databaseId -q '.[].databaseId'); do
        gh run download $RUN_ID -n merged-allure-results-staging -D ./history/$RUN_ID/ 2>/dev/null || true
      done
      ```
      
      ---
      
      ## 6. REGRESSION vs FLAKY — the hard cases
      
      The decision is easy when history is clean. The hard cases:
      
      ### Case 1: First failure after a green streak
      Test passed 5 runs in a row, now fails once.
      - If a code change deployed between the last pass and this failure → REGRESSION.
      - If no deploy, same commit → FLAKY candidate (monitor next run).
      
      ### Case 2: Intermittent pattern matches release cadence
      Test fails every Monday morning but passes other days.
      - Look at scheduled jobs, cron, maintenance windows → probably ENVIRONMENT (infra cycle).
      
      ### Case 3: Passes on retry consistently (retry-enabled projects only)
      Every run shows `failed → passed on retry` — only possible on a project that consciously diverged from the shipped `retries: 0`.
      - This is FLAKY. The user sees green but the underlying test is unstable. Stabilize it.
      
      ### Case 4: One assertion flakes within a test with N assertions
      The same assertion in a multi-assertion test fails intermittently; others always pass.
      - The test itself is FLAKY. Do not mark the entire test REGRESSION. Fix the one assertion (usually a timing issue).
      
      ### Case 5: Fails on one browser only
      Test passes on chromium + firefox, fails on webkit.
      - If the feature uses browser-specific APIs → REGRESSION (browser compat broken).
      - If it is visual or layout-sensitive → could be FLAKY on webkit's slower render. Check history per browser.
      
      ---
      
      ## 7. Severity (orthogonal to classification)
      
      Severity = business impact. A FLAKY test on checkout is still CRITICAL severity.
      
      | Severity | Criteria |
      |----------|----------|
      | CRITICAL | Core user journey (login, signup, checkout, payment, core search). Any test tagged `@critical`. |
      | HIGH | Major feature area (profile, dashboard, primary search filters, account management) |
      | MEDIUM | Secondary feature (sorting, preferences, non-primary filters, notifications) |
      | LOW | Admin-only, edge case, rare scenario, internal tools |
      
      Severity inputs:
      1. Test tags (`@critical`, `@smoke`, `@regression`).
      2. Suite name (Auth, Booking, Payment = CRITICAL; Admin, Settings = LOW/MEDIUM).
      3. TMS ticket priority if linked.
      
      ### Release impact matrix (classification × severity)
      
      |                | CRITICAL | HIGH | MEDIUM | LOW |
      |----------------|----------|------|--------|-----|
      | **REGRESSION** | NO-GO | NO-GO | CAUTION | CAUTION |
      | **FLAKY**      | CAUTION + stabilize now | CAUTION | monitor | monitor |
      | **KNOWN-BLOCKED** | excluded from gating — reassess `{BUG-KEY}` urgency | excluded, document | excluded, document | excluded, document |
      | **KNOWN**      | CAUTION (reassess ticket) | document | document | document |
      | **ENV**        | re-run, escalate infra | re-run | re-run | re-run |
      | **NEW TEST**   | verify manually before GO | verify | verify | verify |
      
      ---
      
      ## 8. Classification report sections
      
      Every classified failure needs this evidence block, regardless of category:
      
      ```markdown
      #### {test_name}
      - Test ID: {atc_id}
      - Suite: {suite}
      - Classification: {KNOWN-BLOCKED / REGRESSION / FLAKY / KNOWN / ENVIRONMENT / NEW}
      - Severity: {CRITICAL / HIGH / MEDIUM / LOW}
      - Run: {run_url}
      - Last passed: {date} (run #{run})
      - Error:
        ```
        {full_error_message}
        ```
      - Probable cause: {one-paragraph analysis}
      - Screenshot: {path or url}
      - Trace: {path or url}
      - Ticket: {created-or-linked-ticket}
      ```
      
      ---
      
      ## 9. Anti-patterns
      
      - **Classifying without reading the error.** The error text is usually definitive. Never classify based on test name alone.
      - **Calling everything "flaky".** Flaky is a last resort after ruling out REGRESSION and ENVIRONMENT. Lazy flaky-tagging hides real regressions.
      - **Calling everything "environment".** If only one test in the suite fails with a network error and that endpoint is hit successfully by other tests in the same run, it is not environment — it is a bug in the code path that test exercises.
      - **Marking NEW TEST as REGRESSION.** A first-run failure has no prior pass to regress from. Mark as NEW TEST, verify manually, then reclassify.
      - **Ignoring retry-passes (retry-enabled projects only).** With the shipped `retries: 0` there are no retry-passes to ignore. On a project that consciously enabled retries, a test that passes on retry is unstable — surface it in the flaky bucket even though Allure shows green.
      - **Guessing flakiness with < 5 runs of history.** Not enough data — mark as "insufficient history" and revisit.
      
      ---
      
      ## 10. Classification flow summary (for report footer)
      
      ```
      Total failed: X
      ├── KNOWN-BLOCKED:  X  ← parked behind {BUG-KEY}, excluded from gating pass-rate
      ├── REGRESSION:     X  ← release blockers (sorted by severity DESC)
      ├── FLAKY:          X  ← schedule stabilization
      ├── KNOWN ISSUE:    X  ← documented, not blocking
      ├── ENVIRONMENT:    X  ← re-run after infra check
      └── NEW TEST:       X  ← manual verification required
      ```
      
    • github-pages-setup.md 5.4 KB
      # GitHub Pages Setup — publish Allure reports for THIS project
      
      > One-time setup that makes the Allure reports your CI already pushes to
      > `gh-pages` actually reachable in a browser. The regression / smoke / sanity
      > workflows shipped with this boilerplate publish to the `gh-pages` branch out
      > of the box via `scripts/ci/publish-allure-pages.ts` (Allure 3, same
      > `allurerc.mjs` as local runs: the Awesome report served directly with its
      > Report | Graphs | Timeline modes, trend history per env/suite, latest-run
      > redirect, last-10-runs retention) — but GitHub does NOT serve that branch
      > until Pages is explicitly enabled on the repo. This reference is the full
      > maneuver, learned the hard way on the boilerplate repo itself.
      
      ## When to run this
      
      - User asks any variant of: "set up GitHub Pages", "publish the Allure
        reports", "why is the report URL 404", "enable the reports site".
      - `/adapt-framework` finished wiring CI and the project wants browsable
        reports.
      - The `Post Report URL` step of a suite run prints a URL that returns 404.
      
      ## Step 0 — Allure version-currency check (MANDATORY)
      
      Before touching Pages, run the **§Allure version-currency check** from
      `SKILL.md` §Local reporting: the boilerplate's pinned `allure` /
      `allure-playwright` / `allure-js-commons` versions are usually behind upstream
      by the time a scaffolded project reaches this setup. Summarize the news to the
      user, offer the same-major `bun update`, never cross a major silently, and
      re-generate one report to confirm the root `index.html` still opens the
      Awesome report directly (Report | Graphs | Timeline). The published site
      inherits whatever version generates in CI, so an outdated local pin means an
      outdated public report.
      
      ## Preconditions (probe, don't assume)
      
      | Check | Command | Blocker if |
      | --- | --- | --- |
      | gh CLI authenticated | `gh auth status` | fails → stop, ask user to `gh auth login` |
      | gh-pages branch exists on origin | `git ls-remote --heads origin gh-pages` | empty → run a suite first (any Allure deploy creates it) |
      | Repo visibility | `gh repo view --json visibility` | `PRIVATE` + free plan → Pages requires a paid plan; surface to user |
      | Pages state | `gh api repos/{owner}/{repo}/pages` | `404` means NOT enabled → proceed with setup |
      
      ## Step 1 — Enable Pages serving the gh-pages branch
      
      ```bash
      gh api -X POST repos/{owner}/{repo}/pages \
        -f "source[branch]=gh-pages" -f "source[path]=/"
      ```
      
      Success returns `"html_url": "https://{owner}.github.io/{repo}/"`. If it
      returns `409 Conflict`, Pages is already enabled — check its source with
      `gh api repos/{owner}/{repo}/pages` and fix the branch if it points elsewhere
      (`gh api -X PUT ... -f "source[branch]=gh-pages"`).
      
      ## Step 2 — Verify the first build (KNOWN GOTCHA: it can silently fail)
      
      The first build after enablement — on a branch that already has content — can
      error with a generic "Page build failed." or hang in `building` for a long
      time. Do NOT push commits to "wake it up"; request a rebuild instead:
      
      ```bash
      # status of the latest build
      gh api repos/{owner}/{repo}/pages/builds/latest --jq '{status, error: .error.message}'
      
      # if status is "errored" (or stuck "building" for >10 min): force a rebuild
      gh api -X POST repos/{owner}/{repo}/pages/builds
      ```
      
      Then poll `builds/latest` until `status: built` and confirm with curl:
      
      ```bash
      curl -s -o /dev/null -w "%{http_code}" https://{owner}.github.io/{repo}/{env}/regression/
      ```
      
      `{env}` is the project's active environment (e.g. `staging`). Expect `200`.
      
      ## Step 3 — Long-term storage hygiene (prevent unbounded branch growth)
      
      Two independent growth vectors, two controls:
      
      1. **Working tree** — already controlled: `scripts/ci/publish-allure-pages.ts`
         prunes to the last 10 run dirs per env/suite (`--keep`, adjustable in each
         workflow). Screenshots/videos live inside each report and rotate with it;
         `history.jsonl` (trend data) persists independently and stays small.
      2. **Git history** — NOT controlled by run pruning: every deploy commit keeps
         its blobs in history forever, so the branch grows on every run even though
         the served site does not. Fix: a scheduled squash job that rewrites
         `gh-pages` to a single orphan commit holding the current content. This is
         the ONLY sanctioned force-push in the project — `gh-pages` is 100%
         workflow-generated, nobody develops on it. Template (adapt repo name; runs
         monthly + on demand): see `.github/workflows/pages-squash.yml` in the
         boilerplate source repo (upex-galaxy/agentic-qa-boilerplate) — copy it
         verbatim; it is repo-agnostic.
      
      ## Report to the user
      
      - Site URL + the per-suite report URLs (`/{env}/regression/`, `/{env}/smoke/`,
        `/{env}/sanity/` — whichever workflows the project runs).
      - Whether the squash job was installed (recommended: yes).
      - Reminder: on public repos the reports are public — screenshots may leak
        UI/data of the app under test; confirm the team is OK with that or keep the
        repo private (Pages on private repos needs a paid plan).
      - If the team needs reports behind a login instead, switch to the PRIVATE
        Test Report Portal mode — runbook: `references/private-hosting-setup.md`
        (the suite workflows are already dual-mode; only secrets are wired).
      
      ## Scope guard
      
      This reference sets up ALLURE report publishing for consumer projects. The
      boilerplate's own `pages.yml` (docs hub: KATA Academy + decks + homepage)
      is boilerplate-EXCLUSIVE — never replicate it in a consumer project; the
      scaffolder deliberately excludes it.
      
    • private-hosting-setup.md 11.2 KB
      # Private Report Hosting — AI-Executed Setup Protocol
      
      > **Purpose**: switch a project's CI Allure reports from public GitHub Pages to
      > the PRIVATE, auth-walled **Test Report Portal**
      > ([upex-test-report-portal](https://github.com/upex-galaxy/upex-test-report-portal),
      > v2). Reports become reachable only after login, bytes live in a private
      > Cloudflare R2 bucket, trends/retention keep working, and the portal indexes
      > every run by environment/strategy.
      >
      > **Execution model**: THE AI RUNS THIS SETUP. Every step below is a command
      > the AI executes, except the blocks marked `HUMAN CHECKPOINT` — those are the
      > only actions that require the human (account sign-ups, one-time auth
      > handshakes, and the optional OAuth app, which has no API). Announce each
      > checkpoint, wait for the human, verify, continue.
      >
      > **When to use**: "reports must be private", "no publiques evidencia
      > pública", "protege los reportes con login". If the org has **GitHub
      > Enterprise Cloud**, offer the zero-infra shortcut first (repo Settings →
      > Pages → visibility Private).
      
      ## Architecture (what you are wiring)
      
      ```
      CI (this repo)                                  Portal (deployed once per org)
        1. tests -> allure-results                      Vercel (Next.js + NextAuth)
        2. GET history from portal        ------->      Supabase Postgres (runs index)
        3. bunx allure generate                         Cloudflare R2 PRIVATE bucket
        4. aws s3 sync -> R2 (direct)     ------->        {project}/{env}/{suite}/{run}/
        5. PUT history + POST /api/runs   ------->        {project}/{env}/{suite}/history.jsonl
                                                        Viewer: login -> /api/view proxy streams bytes
      ```
      
      - The publish step in `regression.yml` / `smoke.yml` / `sanity.yml` is already
        dual-mode: portal **iff the `PORTAL_URL` secret exists**, else public Pages.
      - Publisher: `scripts/ci/publish-allure-portal.ts` (synced downstream by
        `bun run update`). Retention is server-side (portal cron).
      - In portal mode gh-pages is unused: after verification, disable Pages
        serving (Settings → Pages → Source: None); deleting the gh-pages branch
        requires explicit user confirmation (Critical Rule #6).
      
      ## Part 0 — Already-configured detection (idempotency gate, run FIRST)
      
      Probe before provisioning anything — every level short-circuits:
      
      ```bash
      gh secret list | grep -E "PORTAL_URL|PORTAL_PROJECT|PORTAL_API_KEY|R2_"   # repo already wired?
      ```
      
      | Probe result | Meaning | Action |
      |---|---|---|
      | All 7 secrets present | **This repo is fully wired** | Nothing to install. Offer: verify (Part C), rotate key, or change retention. |
      | Some secrets present | Partial/broken wiring | Diff against the Part B table, fill only the missing ones. |
      | No secrets, but user/org has a portal (ask; also check Engram `mem_search "portal URL"`) | Part A done previously | `curl -s -o /dev/null -w "%{http_code}" <PORTAL_URL>/api/metrics` → `401` = portal alive and walled → skip to Part B. |
      | No secrets, no portal | Fresh install | Run Part A → Part B → Part C. |
      
      Part A steps are themselves check-before-create: `supabase projects list`
      before `projects create`, `wrangler r2 bucket list` before `bucket create`,
      `vercel ls` before `vercel link`, and `create-project.ts` upserts (re-running
      it ROTATES the project's API key — only do that deliberately, it invalidates
      the old key in CI secrets).
      
      ## Part A — Portal deployment (once per organization)
      
      Skip to Part B if the org already runs a portal instance (ask for its URL).
      Otherwise, **FORK the portal** (not a plain clone): the org gets its OWN
      repo — Vercel connects to it (every push auto-deploys), branding/tweaks have
      a home, and upstream updates arrive via the `upstream` remote that `gh` wires
      automatically:
      
      ```bash
      gh repo fork upex-galaxy/upex-test-report-portal --clone -- ../test-report-portal
      cd ../test-report-portal && bun install
      # Later upgrades: git pull upstream main && git push   (auto-redeploys)
      ```
      
      The local checkout is the deploy vehicle for the org's own infrastructure —
      after setup it is only revisited for upgrades and `create-project` runs.
      (Humans without an AI can use the "Deploy to Vercel" button in the portal
      README instead — same fork-and-deploy result in one click.)
      
      ### A0 — HUMAN CHECKPOINT: accounts + three one-time credentials
      
      Ask the human for (offer `! <command>` where interactive):
      
      1. **Supabase Personal Access Token** — dashboard → account → Access Tokens →
         generate. Or run `! supabase login` (browser handshake). Export as
         `SUPABASE_ACCESS_TOKEN`.
      2. **Cloudflare**: account with **R2 enabled** (R2 → activate; asks for a
         payment method even though the free 10 GB tier is $0) + a **user API token**
         with permission **API Tokens: Edit** (dashboard → My Profile → API Tokens).
         Export as `CF_MASTER_TOKEN`. Alternative: `! wrangler login`.
      3. **Vercel**: `! vercel login` (or a token from vercel.com/account/tokens →
         export `VERCEL_TOKEN`).
      
      Never echo these values into logs, commits, or files.
      
      ### A1 — Supabase project + schema (AI)
      
      ```bash
      supabase orgs list                                   # get org id
      supabase projects create test-report-portal \
        --org-id <ORG_ID> --region <closest> \
        --db-password "$(openssl rand -hex 16)"            # record ref from output
      supabase link --project-ref <REF>
      supabase db push                                     # applies supabase/migrations/002_v2_schema.sql
      supabase projects api-keys --project-ref <REF>       # collect keys
      ```
      
      Collect: `NEXT_PUBLIC_SUPABASE_URL=https://<REF>.supabase.co`, the
      **publishable** key (`sb_publishable_...` → `NEXT_PUBLIC_SUPABASE_ANON_KEY`)
      and the **secret** key (`sb_secret_...` → `SUPABASE_SERVICE_KEY`). New
      Supabase projects no longer issue legacy `anon`/`service_role` JWTs — the
      `sb_*` keys are drop-in replacements.
      
      ### A2 — R2 bucket + scoped S3 credentials (AI)
      
      ```bash
      bunx wrangler r2 bucket create test-reports          # keep public access OFF (default)
      ```
      
      Create the bucket-scoped S3 credentials **via API** (no dashboard needed):
      `POST https://api.cloudflare.com/client/v4/user/tokens` with
      `Authorization: Bearer $CF_MASTER_TOKEN` and an R2 Object Read & Write policy
      scoped to the bucket (see
      developers.cloudflare.com/r2/api/tokens → "Create API tokens via API").
      Then derive:
      
      - `R2_ACCESS_KEY_ID` = the created token's `id`
      - `R2_SECRET_ACCESS_KEY` = `echo -n "<token value>" | shasum -a 256` (hex)
      - `R2_ACCOUNT_ID` = `bunx wrangler whoami` account id · `R2_BUCKET` = bucket name
      
      Sanity-check before continuing:
      
      ```bash
      AWS_ACCESS_KEY_ID=$R2_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$R2_SECRET_ACCESS_KEY AWS_DEFAULT_REGION=auto \
      aws s3 ls "s3://$R2_BUCKET/" --endpoint-url "https://$R2_ACCOUNT_ID.r2.cloudflarestorage.com"
      ```
      
      ### A3 — HUMAN CHECKPOINT (optional): OAuth app
      
      Google/GitHub OAuth clients **cannot be created via any API or CLI** — this
      is the one irreducible dashboard step (~5 min). The portal works WITHOUT it
      (admin credentials login), so offer both paths:
      
      - Skip now → deploy with credentials-only login; add OAuth later.
      - Do now → Google Cloud console → OAuth client (Web), redirect URI
        `https://<portal-domain>/api/auth/callback/google` → human hands over
        `GOOGLE_ID` + `GOOGLE_SECRET`.
      
      ### A4 — Vercel deploy (AI)
      
      From the portal repo clone (CLI shown; the Vercel MCP is an equivalent path):
      
      ```bash
      vercel link --yes                                    # create/link the project
      # Set every env var (production): loop `vercel env add <NAME> production`
      #   NEXTAUTH_URL=https://<assigned-domain>   NEXTAUTH_SECRET=$(openssl rand -hex 32)
      #   LOGIN_EMAIL / LOGIN_PASSWORD (bcrypt: bun scripts/generate-password-hash.ts)
      #   AUTHORIZED_EMAIL_DOMAINS=<company.com>   AUTHORIZED_EMAILS=
      #   GOOGLE_ID / GOOGLE_SECRET (if A3 done)
      #   Supabase trio (A1) · R2 quartet (A2) · CRON_SECRET=$(openssl rand -hex 24)
      #   NEXT_PUBLIC_APP_URL=https://<assigned-domain>
      vercel deploy --prod --yes
      ```
      
      The retention cron registers automatically from `vercel.json`.
      
      ### A5 — Wall verification (AI, mandatory)
      
      ```bash
      curl -s -o /dev/null -w "%{http_code}" https://<portal>/api/metrics   # expect 401
      ```
      
      Then with browser automation (or ask the human for an incognito check):
      portal root → login page renders; login with admin credentials → dashboard.
      
      ## Part B — Per-project wiring (each downstream repo) (AI)
      
      1. **Provision the project** (in the portal repo clone, Supabase envs loaded):
      
         ```bash
         bun scripts/create-project.ts <project-slug> "<Display Name>" --retention-runs 30
         ```
      
         Capture the one-time API key from stdout — transfer it ONLY into the
         secret below, never into a file or log.
      
      2. **Secrets** in the consuming repo:
      
         ```bash
         gh secret set PORTAL_URL --body "https://<portal-domain>"
         gh secret set PORTAL_PROJECT --body "<project-slug>"
         gh secret set PORTAL_API_KEY --body "<one-time key>"
         gh secret set R2_ACCOUNT_ID --body "..."     # + R2_ACCESS_KEY_ID,
         gh secret set R2_BUCKET --body "..."         #   R2_SECRET_ACCESS_KEY
         ```
      
      3. **Trigger a suite** (`gh workflow run smoke.yml`) and watch the publish
         step: history GET → generate → s3 sync → history PUT → run registered.
      
         No CI available yet? Run the manual publish test instead — portal repo
         `SETUP.md` §6.5 has the copy-paste flow with any local `allure-report/`.
      
      ## Part C — Verification checklist (MANDATORY before declaring done)
      
      - [ ] CI publish step green; job summary shows the portal `viewUrl`.
      - [ ] `viewUrl` logged in → report renders (iframe via `/api/view/...`).
      - [ ] `viewUrl` + a direct asset URL in incognito/curl → login wall / 401,
            never bytes.
      - [ ] Second run on the same stream → trend charts render (history works).
      - [ ] Portal dashboard lists the run under the right environment/strategy.
      - [ ] If migrating from public Pages: Pages serving disabled after user
            confirms.
      
      ## Failure modes
      
      | Symptom | Cause | Fix |
      |---|---|---|
      | `Missing required environment variable: PORTAL_*` in CI | Secret not set | Part B step 2 |
      | `401 Invalid credentials` on history/runs | Wrong `PORTAL_API_KEY` / slug mismatch | Re-run create-project (rotates key), update secret |
      | `400 reportPrefix must be ...` | Publisher/portal contract drift | `bun run update` in the consuming repo |
      | Report iframe 404s assets | Sync hit wrong bucket/prefix | Check `R2_BUCKET` secret + CI log line `r2://...` |
      | `aws s3 ls` in A2 fails with 403 | Token policy not scoped to the bucket / wrong secret derivation | Recreate token; secret = SHA-256 of the token VALUE, not the id |
      | OAuth login rejects a valid teammate | Domain missing in `AUTHORIZED_EMAIL_DOMAINS` | Add + redeploy |
      | Trends empty after 2+ runs | History PUT failing | Check publish log; key rotated mid-stream? |
      | Cron never runs | `CRON_SECRET` unset in Vercel | Set + redeploy |
      
      ## Boundaries
      
      - NEVER print `PORTAL_API_KEY`, R2 secrets, or Supabase secret keys into
        logs, commits, Jira, or chat transcripts beyond what the human must copy.
      - The publisher never deletes from R2; only the portal cron does.
      - One R2 bucket serves ALL projects — isolation is enforced by the portal
        (API key ↔ slug ↔ prefix validation).
      - Human-only steps are ONLY: account sign-ups, the three A0 handshakes, R2
        payment-method activation, and the optional A3 OAuth app. Everything else
        is yours to execute.
      
  • SKILL.md 51.3 KB
    ---
    name: regression-testing
    description: "Execute regression test suites via CI/CD, analyze results, classify failures, and produce GO/NO-GO release decisions. Use when running regression, smoke, or sanity suites through GitHub Actions, monitoring workflow runs, downloading Allure or Playwright artifacts, classifying failures (REGRESSION vs FLAKY vs KNOWN vs ENVIRONMENT vs NEW TEST), computing pass-rate and trend metrics, deciding release readiness, generating executive quality reports, or creating regression issues. Triggers on: run regression, trigger test workflow, analyze test results, quality report, GO/NO-GO decision, release readiness, flaky tests, Allure report, smoke suite, pass rate, nightly test failure, stage 6. Do NOT use for writing new regression tests (that belongs to test-automation) or for manual fix verification (that belongs to sprint-testing)."
    license: MIT
    compatibility: [claude-code, copilot, cursor, codex, opencode]
    complementary_categories: [testing-e2e, ci-cd]
    ---
    
    ## Forbidden invocations
    
    **NEVER invoke `/sdd-*` skills from this workflow.** SDD is an optional
    user-installed ceremony; this skill ships self-contained and does not chain
    SDD under any condition. If you need to refactor KATA, fixtures, cli/,
    scripts/, or api/schemas/ pipeline, exit this skill first and invoke
    `/framework-development` — which itself runs Plan → Code → Verify → Archive
    natively (no SDD required).
    
    This boundary is mechanical, not advisory: `scripts/lint-skills.ts` rejects
    any `/sdd-` mention outside this section. See:
    `.agents/skills/agentic-qa-core/references/skill-composition-strategy.md` §4
    (governs users who manually install SDD).
    
    # Regression Testing — Execute, Analyze, Decide
    
    Orchestrates the full release-readiness pipeline: trigger a CI suite, monitor it to completion, classify failures, score against release criteria, and emit a GO / CAUTION / NO-GO verdict plus a stakeholder report.
    
    Three phases, always in this order: **Execute → Analyze → Report**. Do not skip analysis and jump to a report. Do not guess classification without reading failure logs.
    
    ---
    
    ## Compact Rules
    
    - DO: run Execute → Analyze → Report in that order. Never skip analysis and jump to a report, and never classify a failure without reading its logs.
    - DO: clear the readiness preflight before triggering anything — `gh` authenticated, the suite's workflow file present, GitHub Actions secrets set, Allure resolvable, active env confirmed. A 20-60 minute run that 401s mid-way is the expensive failure.
    - DO: persist `RUN_ID` the moment the trigger returns, before anything else. Resume re-attaches to a live run instead of re-triggering CI; a trigger that landed without the id saved costs the whole run again.
    - DO NOT: mark a failure REGRESSION without checking its history first — the single most common misclassification. A first-ever failure with no history is NEW TEST, unverified, not a regression.
    - DO: classify every failure into exactly one of KNOWN-BLOCKED / KNOWN ISSUE / ENVIRONMENT / NEW TEST / FLAKY / REGRESSION, and assess severity on a separate axis — a FLAKY test on checkout is still CRITICAL.
    - DO: exclude `@blocked:{BUG-KEY}` tests from the gating pass-rate and report their count with each blocking key. They are parked behind an already-filed bug: never REGRESSION, and never a new bug.
    - DO NOT: use ENVIRONMENT as a scapegoat. Many unrelated tests failing on one host is environment; one test failing on an endpoint other tests reach fine is more likely a REGRESSION.
    - DO NOT: call a test flaky on fewer than 5 runs of history — mark "insufficient history" and re-evaluate rather than guessing.
    - DO NOT: emit GO while any REGRESSION-class failure stands. Hard vetoes regardless of score: any `@critical` test failing, any HIGH/CRITICAL-severity regression, or a pass rate below 90%.
    - DO: file only CONFIRMED product failures — the REGRESSION class, plus a NEW TEST failure once manually confirmed to be a real defect. FLAKY, ENVIRONMENT and KNOWN ISSUE get no issue at all. Triage decides WHETHER to file; the defect-management doctrine decides the type and the fields.
    - DO NOT: open a GitHub issue for a quality failure. It is filed in the issue tracker, parented to the QA Defect Management process epic and linked to the source Story — never to a product or dev epic.
    - DO: create every Test Execution with its Test Environment (from `active_env`) and `assignee` = self at create time, close the STR only AFTER the verdict is written, and leave the RTP at its ready status — a suite run never completes the plan it ran from.
    - DO NOT: invent a sprint number. Take `N` from the user or from the STP's own scope-id; a guessed `N` forks a duplicate STP/STR pair. Nothing found and nothing given → ask before creating at sprint altitude.
    - DO NOT: skip the artifact download on a red build (evidence vanishes after the retention window), and never merge smoke and regression results into one pass-rate — their SLOs differ.
    
    **Read full SKILL.md when**: driving the CI commands, applying the GO/CAUTION/NO-GO scoring table, resolving a borderline classification, wiring the TMS artifacts, or writing the report.
    
    ---
    
    ## Inputs
    
    - `.github/workflows/*.yml` — workflow files for regression / smoke / sanity suites; defines triggers, inputs, and artifact uploads. **LOAD `/github-actions-docs` before editing or diagnosing one**: Actions syntax (matrix, `needs`, reusable workflows, artifact retention, permissions) is the part of this skill's surface that changes upstream without telling anyone, and a guessed key fails at runner start with a message that points nowhere. Reading one does not need it; changing one does.
    - `.context/master-test-plan.md` — regression Epic key + expected pass-rate SLOs per suite.
    - `playwright.config.ts` — reporter config, retry policy, project matrix; needed to interpret retry counts and shard splits.
    - Previous run's Allure report (artifact URL or local download under `./analysis/previous/`) — baseline for trend computation.
    - `kata-manifest.json` — registry of tests and ATCs available; used to cross-reference failed test IDs.
    - `.agents/jira-required.yaml` — Jira refs (project key, work types, transitions) for filing regression issues.
    - `agentic-qa-core/references/defect-management-doctrine.md` — **canonical authority** for classifying (Bug/Defect/Improvement), the mandatory field matrix, QA-Assignee ownership, and the QA process epic when a confirmed regression is filed in Jira (Phase 3). Read BEFORE filing any defect.
    - `agentic-qa-core/references/artifact-lifecycle.md` — **canonical authority** for artifact statuses: the STR closes at `{{jira.status.test_execution.close}}` after the verdict, the RTP stays at `{{jira.status.test_plan.ready}}`, every created artifact carries `assignee` = self, and an unmapped transition slug goes through the §4 fallback instead of a silent skip. Read BEFORE firing any transition.
    
    ---
    
    ## Subagent Dispatch Strategy
    
    > **Orchestration & Session contracts**: this skill follows `agentic-qa-core/references/orchestration-doctrine.md` (mandatory subagent dispatch — main thread is command center) AND `agentic-qa-core/references/session-management.md` (Phase 0 resume check, plan-first persistence at `.session/<skill-slug>/<scope>/`, archive on completion). Phase 0 (resume check) and Phase 1 (plan write) are NOT optional. The orchestrator also applies the per-stage **Definition-of-Done gates** in `agentic-qa-core/references/stage-gates.md`: verify a stage's DoD BEFORE recording its progress checkpoint and advancing.
    
    This skill is **per-run scope**: `<scope>` = `<env>-<YYYY-MM-DD>` (e.g. `staging-2026-05-20`). Session state lives at `.session/regression-testing/<scope>/{plan.md, progress.md}` per `agentic-qa-core/references/session-management.md` §3 + §9. The single highest-value resume case: if the Monitor subagent dies while watching a long CI run but `RUN_ID` was captured in `plan.md`, Phase 0 re-attaches via `gh run view <RUN_ID>` instead of re-triggering CI (saves 20–60 min of wall-clock).
    
    This skill is compliant with the doctrine in `AGENTS.md` §"Orchestration Mode (Subagent Strategy)" and the session contract in `.agents/skills/agentic-qa-core/references/session-management.md`. Every dispatch follows the 7-component briefing format defined in `.agents/skills/agentic-qa-core/references/briefing-template.md`, and the pattern selected per stage matches the decision guide in `.agents/skills/agentic-qa-core/references/dispatch-patterns.md`. The two CI-bound stages (long-running watch, multi-artifact download) and the high-volume failure classification step are the hotspots — everything else stays inline because the dispatch overhead is not justified.
    
    | Stage                                                      | Pattern    | Subagent role                                                                                                  |
    |------------------------------------------------------------|------------|----------------------------------------------------------------------------------------------------------------|
    | Trigger workflow (`gh workflow run`)                       | Single     | inline — no dispatch needed (one shell call)                                                                   |
    | Wait/monitor `gh run watch`                                | Background | one Monitor subagent runs the watch; main thread continues with prep work; subagent notifies on exit           |
    | Download 3 artifacts (allure / evidence / playwright)      | Parallel   | 3 simultaneous subagents, one per artifact; cap = 3 (no rate-limit risk)                                       |
    | Classify failures (chunks of ~10 tests each)               | Parallel   | N subagents based on failure volume; cap = 10 to avoid context dilution                                        |
    | Compute metrics (pass-rate, trends)                        | Single     | inline — needs aggregated state, low cost                                                                      |
    | Generate executive report                                  | Single     | inline — final synthesis, decisions live here                                                                  |
    | GO / CAUTION / NO-GO verdict                               | Single     | inline — main thread owns release decisions                                                                    |
    
    - **Error protocol**: On any subagent failure: STOP, report full context to user, present retry / skip / abort options. Do NOT auto-fix. See `.agents/skills/agentic-qa-core/references/orchestration-doctrine.md`.
    
    ---
    
    ## Fleet seam (optional)
    
    Triage itself is never parallelized across sessions: one conductor reads the run, classifies, and owns the verdict. The seam is for what comes AFTER Phase 2, when the classification leaves several **independent failure clusters** that each need code — and only when the user asks for them to be worked at once.
    
    - **Topology: one worktree per failure cluster.** A cluster's fix is code (a spec, a locator, a fixture), so each worker gets its own checkout and its own branch; two sessions in one checkout contend on the git index even on disjoint files. One cluster = one worker = one branch. Never two workers on one cluster.
    - The conductor writes `launch.txt` in `.session/regression-testing/<scope>/` — one self-contained line per cluster — **always**, whether or not any orchestration transport exists on the machine. Launching, supervising and closing those sessions is `orca-orchestration/SKILL.md` (`[ORCHESTRATION_TOOL]`): supervised launch is the native path, and `launch.txt` is the payload for the human-paste fallback when nothing can launch it.
    - **The verdict never moves.** GO / CAUTION / NO-GO, the metrics, the STR and every Jira write stay with the conductor (Phase 3). A worker fixes its cluster and reports; it does not re-score the run, does not file the defect, and does not transition the STR.
    - Each worker's fix is authored under `/test-automation` (Plan → Code → Review) on its own branch, and lands per `git_strategy` — a regression fix is not exempt from the automation gate.
    - **Silence rule**: the absence of an orchestration transport is never named to the user, never appears in the preflight gate, and never appears in the Environment block or the report.
    
    ---
    
    ## Readiness Preflight Gate (MANDATORY — runs before Phase 0)
    
    > Full doctrine: `agentic-qa-core/references/preflight-gate.md`. Runs FIRST, before the resume check and any `gh workflow run`. Two laws: (1) **args-as-answers** — the suite (regression/smoke/sanity), env, and any grep/test_file are provided args; ask only the gaps. (2) **probe, don't assume**. Surface gaps + REDs as ONE `AskUserQuestion` checklist; self-fix with approval + explanation; STOP on any blocking RED. This generalizes the Phase 1 §Preflight (`gh auth`) to a full readiness check pulled to t=0. **Generic baseline** (env resolution, secret/restart handling, the two laws, output contract) is inherited from the reference §3.1 — not repeated here. Below is only this skill's **specific capability delta** (note: test-user creds, MCPs and browsers live inside the CI runner, not the orchestrator).
    
    | Capability | Need | Why here |
    |---|---|---|
    | GitHub CLI authenticated | REQUIRED | Every stage drives CI via `gh` (`gh auth status`, `gh workflow run`, `gh run watch`, `gh run download`). Not authed → user runs `gh auth login` (suggest the `!` prefix); do not proceed. |
    | Workflow files present | REQUIRED | `.github/workflows/` must hold the regression/smoke/sanity workflow for the chosen suite, with the inputs this skill passes. |
    | GitHub Actions Secrets/Variables | REQUIRED | The runner authenticates with env-prefixed creds (`secrets.<ENV>_USER_EMAIL` / `_PASSWORD`) + `XRAY_*` / `ATLASSIAN_*` as Repository/Environment Secrets — the suite 401s mid-run without them. `gh secret list` (add `--env <env>` for environment scope) shows them; missing → `gh secret set <NAME>` from `.env`. `/adapt-framework` only emits a manual list today, so this is the most common silent gap. |
    | Allure 3 local | REQUIRED | `bunx allure` resolves (devDep, no global install); `allurerc.mjs` present for `bun allure:agent` markdown triage. |
    | Active env | REQUIRED | The suite runs against `<<ACTIVE_ENV>>` (default `{{DEFAULT_ENV}}`). Confirm it is the intended target before a 20–60 min run. |
    | `[TMS_TOOL]` (result sync) | OPTIONAL | Only when `.agents/project.yaml` `testing.tms_cli` is set — Stage 3 pushes run status. jira-xray → `/xray-cli` + `XRAY_*`. |
    | `[ISSUE_TRACKER_TOOL]` (file regression issues) | OPTIONAL | Only on NO-GO / CAUTION-with-regressions, to file issues. Load `/acli` then. |
    
    Test-user creds, OpenAPI/`API_TOKEN`, DBHub and Playwright browsers live **inside the CI runner**, not the orchestrator — this skill does not exercise them locally, so they are out of scope for this gate. After the gate clears (all REQUIRED GREEN), continue to Phase 0 below.
    
    ---
    
    ## Phase 0 — Session resume check (MANDATORY, inline)
    
    Before suite selection or any `gh workflow run`, run the resume contract from `agentic-qa-core/references/session-management.md` §4:
    
    1. Compute prospective `<scope>` = `<env>-<YYYY-MM-DD>` from invocation context (env defaults to `{{DEFAULT_ENV}}`).
    2. Check `.session/regression-testing/<scope>/progress.md`.
    3. If it does NOT exist → proceed to suite selection + Phase 1 preflight + plan.md write.
    4. If it DOES exist:
       - Read `plan.md` (captured `suite`, `env`, `workflow_file`, `RUN_ID` if Phase 1 already triggered).
       - Read tail of `progress.md`.
       - If `RUN_ID` is present AND `progress.md` last entry is `Phase 1 — Trigger — status: completed` but Monitor entry is missing/failed: surface the option to **re-attach** to the existing `RUN_ID` via `gh run view <RUN_ID> --json status,conclusion` instead of re-triggering. This is the high-value resume case.
       - Otherwise surface the standard offer **resume / restart / abort**. On `restart`, archive to `.session/.archive/<YYYY-MM-DD>-regression-testing-<scope>-aborted/` first.
    
    ---
    
    ## When to run each suite
    
    | Suite | Workflow file | Duration | Use when |
    |-------|---------------|----------|----------|
    | `regression` | `regression.yml` | 20-60 min | Pre-release validation, nightly full run |
    | `smoke` | `smoke.yml` | 2-5 min | Post-deploy health check, `@critical` only |
    | `sanity` | `sanity.yml` | 1-10 min | Validate one feature / one file / one grep pattern |
    
    If the user says "run regression" with no qualifier, default to `regression` on `{{DEFAULT_ENV}}`. If they say "smoke" or "critical only", use `smoke`. If they specify a file, grep, or single feature, use `sanity`.
    
    ---
    
    ## Local reporting (Allure 3, no global install)
    
    Allure 3 is a devDep — `bunx allure` resolves to the local `node_modules/.bin/allure`, no `brew install allure` / `scoop install allure` required. Configuration lives at `allurerc.mjs`, single-plugin BY DESIGN: with only the **Awesome** plugin the generated `index.html` IS the report (no card-chooser landing), and its top-left mode dropdown covers everything — **Report** (drill-down, tag filters), **Graphs** (complete executive chart set: status, dynamics, severities, stability, testing pyramid, durations…), **Timeline**. Never add `plugin-dashboard` instances — they duplicate Graphs with fewer charts and bring back the landing screen (rationale in `allurerc.mjs` comments). Trend charts are fed by `historyPath: ./.allure/history.jsonl` and populate from the 2nd run onward.
    
    | Use case | Script | Underlying command |
    |---|---|---|
    | Run tests + auto-generate report (human review) | `bun allure:run` | `bunx allure run -- bun test` |
    | Run tests + emit markdown for AI review | `bun allure:agent` | `bunx allure agent -- bun test` |
    | Generate report from existing `./allure-results` | `bun allure:generate` | `bunx allure generate ./allure-results` |
    | Serve last generated report locally | `bun allure:open` | `bunx allure open` |
    | Live-refresh report during iterative dev | `bun allure:watch` | `bunx allure watch ./allure-results` |
    
    `bun allure:agent` is the AI-friendly entry point: it produces a markdown summary the orchestrator (or a Verifier subagent) can read directly without parsing HTML. Use it whenever you need a structured pass/fail breakdown after a local re-run while triaging a CI failure (Phase 2 step 1, before downloading the merged-allure-results artifact from CI).
    
    CI artifacts (`merged-allure-results-{env}`) are still produced by the workflow and downloaded via `gh run download` as documented in Phase 2. The published GitHub Pages reports are generated by `scripts/ci/publish-allure-pages.ts` with the SAME `allurerc.mjs` and `allure` devDep as local runs — the `/{env}/{suite}/` URL redirects straight into the latest run's Awesome report (Report | Graphs | Timeline), with per-suite trend history and last-10-runs retention.
    
    ### Allure version-currency check (MANDATORY during any Allure/Pages setup)
    
    The boilerplate pins `allure` / `allure-playwright` / `allure-js-commons` at scaffold time, so by the time someone installs the repo and runs this setup they are usually behind upstream. Whenever this skill performs **Allure setup** (first local report, preflight RED on the "Allure 3 local" row) or **GitHub Pages setup** (`references/github-pages-setup.md`), run this check FIRST:
    
    1. `npm view allure version && npm view allure-playwright version` → compare against `package.json`.
    2. **Same major behind** → summarize the news for the user (release notes: `gh api repos/allure-framework/allure3/releases`), then offer `bun update allure allure-playwright allure-js-commons` (or bump the `^` ranges + `bun install`). Keep `allure-js-commons` in lockstep with `allure-playwright` (it is imported directly by `tests/components/TestFixture.ts` for the `layer` auto-label).
    3. **New major available** → NEVER upgrade silently. Present breaking changes and wait for explicit user approval.
    4. **Config-currency (older scaffolds)** — `bun run update` syncs skills and appends new devDeps, but it NEVER overwrites `allurerc.mjs` or `tests/components/TestFixture.ts` (project-adapted files). If the local `allurerc.mjs` predates the current template (no `historyPath`, no `categories`, or stale `plugin-dashboard` instances), OFFER to migrate it: fetch the boilerplate's current `allurerc.mjs` as reference (`https://raw.githubusercontent.com/upex-galaxy/agentic-qa-boilerplate/main/allurerc.mjs`), preserve the project's `name`, and port the config. Same for the `_allureLayer` auto-fixture in `TestFixture.ts` (feeds the testingPyramid + durations-by-layer charts in Awesome's Graphs tab) — without it those charts render empty. Never overwrite silently; show the diff and wait for approval.
    5. After any bump: `bun allure:generate` from existing results (or a sandbox run) and confirm the report renders — the root `index.html` must open the Awesome report directly, with the Report | Graphs | Timeline mode dropdown working.
    
    Known gotchas to preserve on upgrade (context in `allurerc.mjs` comments):
    - Dashboard chart `type` values must match `ChartType` in `@allurereport/charts-api` — the plugin README's `trend`/`pie` examples are stale and yield an empty dashboard (404 on `widgets/charts.json`).
    - `historyPath` must stay OUTSIDE `allure-report/` (`./.allure/history.jsonl`) or `test:clean` erases trend history.
    - Multiple instances of one plugin need an explicit `import:` field — a custom key alone does not resolve (relevant only if a project deliberately adds extra report views).
    
    ---
    
    ## Phase 1 — Execute
    
    ### Preflight (always)
    
    ```bash
    gh auth status
    gh repo view --json name,owner
    gh workflow list
    ```
    
    If `gh` is not authenticated, stop and ask the user to run `gh auth login`. Do not proceed.
    
    **Write `.session/regression-testing/<scope>/plan.md`** per `agentic-qa-core/references/session-management.md` §6 BEFORE the Trigger step below. Capture: Goal (suite + env + reason for run), Inputs (workflow file path, env vars, optional grep/test_file for sanity), Approach (subagent pattern per stage from the dispatch table above), Phase breakdown (Trigger → Monitor → Download → Classify → Compute → Report → Verdict), Risks, Verification checklist (all 3 artifacts download + verdict emitted), Cross-references (`.context/reports/regression-<env>-<date>.md` will hold the final verdict). `RUN_ID` lands in `plan.md` §Inputs AFTER the Trigger step captures it — append, do not rewrite the body.
    
    ### Trigger
    
    ```bash
    # Full regression
    gh workflow run regression.yml \
      -f environment=staging \
      -f video_record=false \
      -f generate_allure=true
    
    # Smoke
    gh workflow run smoke.yml -f environment=staging -f generate_allure=true
    
    # Sanity (grep OR test_file, never both)
    gh workflow run sanity.yml -f environment=staging -f test_type=e2e -f grep="@auth"
    gh workflow run sanity.yml -f environment=staging -f test_file="tests/e2e/auth/login.test.ts"
    ```
    
    ### Capture run ID
    
    ```bash
    # Wait 3-5 seconds for the run to register, then:
    gh run list --workflow=regression.yml --limit=1 --json databaseId,status,createdAt -q '.[0].databaseId'
    ```
    
    Store as `RUN_ID`. Every subsequent step uses it.
    
    **Progress checkpoint after Trigger**: append `RUN_ID` to `.session/regression-testing/<scope>/plan.md` §Inputs (so resume can re-attach) AND append a phase entry `## Phase 1.Trigger — <ts>` with `status: completed`, `next: Phase 1.Monitor`, `notes: RUN_ID=<value>` to `progress.md`. This is the critical persistence point — Trigger landing without `RUN_ID` persisted means resume cannot re-attach.
    
    ### Monitor to completion
    
    Use the dispatch defined in §Subagent Dispatch Strategy: **Background**. Delegate `gh run watch <RUN_ID>` to a Monitor subagent so the main thread is freed to prepare the report scaffold and load the classification rubric. See `references/ci-cd-integration.md` §"Monitoring the workflow run (Background dispatch)" for the full briefing.
    
    Reference command (executed inside the subagent, not inline on the main thread):
    
    ```bash
    gh run watch <RUN_ID> --exit-status
    # Fallback polling (only if gh run watch is unavailable):
    gh run view <RUN_ID> --json status,conclusion
    # status: queued | in_progress | completed
    # conclusion (only when completed): success | failure | cancelled | timed_out
    ```
    
    Do not start Phase 2 until the Monitor returns `status: completed`.
    
    ### Output of Phase 1
    
    A short execution summary with: workflow name, run ID, environment, duration, conclusion, per-job status, artifact list, and the Allure URL pattern `https://{owner}.github.io/{repo}/{environment}/{suite}/`.
    
    Read `references/ci-cd-integration.md` when configuring new workflows, debugging CI-only failures, tuning sharding / retries / timeouts, or wiring up secrets and variables.
    
    ---
    
    ## Phase 2 — Analyze
    
    ### Step 1: Collect data
    
    Use the dispatch defined in §Subagent Dispatch Strategy: **Parallel** for the three artifact downloads (allure / evidence / playwright). Fan out three subagents in a single tool-call block — each owns one artifact, writes to its own directory, and reports back when its download is verified. The metadata reads (`gh run view`) stay inline because they are short.
    
    Reference commands (the metadata reads run inline; the three `gh run download` calls live inside the parallel subagents):
    
    ```bash
    # Inline (main thread): full run context
    gh run view <RUN_ID> --json status,conclusion,jobs,createdAt,updatedAt,url,headBranch,event,actor
    
    # Inline (main thread): failed logs only (much smaller than --log)
    gh run view <RUN_ID> --log-failed
    
    # Inline (main thread): list artifacts so the parallel dispatchers know what to fetch
    gh run view <RUN_ID> --json artifacts --jq '.artifacts[].name'
    
    # Parallel subagent A — allure results
    gh run download <RUN_ID> -n merged-allure-results-staging -D ./analysis/
    
    # Parallel subagent B — failure evidence (screenshots, traces, videos)
    gh run download <RUN_ID> -n e2e-failure-evidence       -D ./analysis/evidence/
    
    # Parallel subagent C — playwright HTML report
    gh run download <RUN_ID> -n e2e-playwright-report      -D ./analysis/playwright/
    ```
    
    Each subagent uses the briefing shape in `agentic-qa-core/references/briefing-template.md` §"Parallel — Download 3 CI artifacts in regression-testing". Cap the fan-out at 3 — there are only ever three artifact streams and GitHub's per-run rate limits are not a concern at that size.
    
    ### Step 2: Parse results
    
    Source of truth priority: **Allure results JSON > Playwright `report.json` > raw logs**. Each Allure result has `status`, `statusDetails.message`, `statusDetails.trace`, and `labels[]` (look for `testId` = ATC ID, `suite`, and `severity`).
    
    > **The `suite` label is tag-derived — single source of truth.** Allure suite/grouping labels are NOT a separate taxonomy: they derive from the Playwright tag (`@smoke` / `@regression` / `@e2e` / `@integration` / `@critical`) that also drives CI scope selection. A test tagged `@integration` reports `suite: integration` automatically. So the `suite` you read here is exactly the scope CI ran — never reconcile it against a parallel Allure label set. Convention owner: `test-automation/references/ci-integration.md` §3.2.1.
    
    ### Step 3: Compute metrics
    
    | Metric | Formula |
    |--------|---------|
    | Total | count of results |
    | Passed / Failed / Skipped / Broken | count by `status` |
    | Pass Rate | `Passed / Total * 100` |
    | Duration | `max(stop) - min(start)` |
    | Trend | current pass rate − previous run pass rate |
    
    > **Exclude KNOWN-BLOCKED from the gating pass-rate.** Tests classified
    > KNOWN-BLOCKED (tagged `@blocked:{BUG-KEY}`, see Step 4) are parked behind an
    > already-filed bug — they are NOT regression failures and must not depress the
    > pass-rate that drives the GO/NO-GO score. Compute the gating Pass Rate over
    > `Total − KNOWN-BLOCKED`, and report the blocked count separately (with each
    > `{BUG-KEY}`) so the release decision is not gamed in either direction.
    
    Previous-run comparison requires downloading artifacts of the previous run:
    
    ```bash
    PREV=$(gh run list --workflow=regression.yml --limit=2 --json databaseId -q '.[1].databaseId')
    gh run download $PREV -n merged-allure-results-staging -D ./analysis/previous/
    ```
    
    ### Step 4: Classify every failure
    
    Use the dispatch defined in §Subagent Dispatch Strategy: **Parallel** when the failure list has more than 10 entries. Shard the failures into chunks of ~10 (cap at 10 subagents) and fan out one classification subagent per chunk; merge their JSON reports in the main thread. For ≤10 failures, classify inline (the dispatch overhead is not justified). See `references/failure-classification.md` §"Parallel classification (default for >10 failures)" for the full briefing and merge protocol.
    
    Apply this decision tree to each failed test (whether classified inline or inside a parallel subagent). **Never mark a test REGRESSION without checking history first** — that is the single most common misclassification.
    
    ```
    Failed test
      │
      ├── Tagged @blocked:{BUG-KEY}? ────────────► KNOWN-BLOCKED
      │   (test asserts test.fail('Blocked by {BUG-KEY}') — a deliberately
      │    parked test, not a fresh regression; excluded from gating pass-rate)
      │
      ├── Linked to a known-issue ticket? ───────► KNOWN ISSUE
      │
      ├── Error matches environment pattern? ────► ENVIRONMENT ISSUE
      │   (ECONNREFUSED, ETIMEDOUT, net::ERR_, Navigation timeout,
      │    browserType.launch, 502/503, context deadline exceeded)
      │
      ├── No history (first-ever run)? ──────────► NEW TEST FAILURE
      │
      ├── Failure rate > 20% over last 10 runs? ─► FLAKY
      │
      └── Passed in last ≤ 5 runs, now fails? ───► REGRESSION   (release blocker)
    ```
    
    | Category | Impact | Action |
    |----------|--------|--------|
    | KNOWN-BLOCKED | LOW | Already tracked by `{BUG-KEY}` — exclude from gating pass-rate, list in report with the blocking bug key. **No new Jira bug** (the marker already names the open bug) |
    | REGRESSION | HIGH | Block release, file Jira Bug/Defect (Phase 3 §File defects in Jira, doctrine Part 1), assign |
    | FLAKY | MEDIUM | Schedule stabilization, do not block — **no Jira bug** |
    | KNOWN ISSUE | LOW | Document against existing ticket, do not block — **no new Jira bug** |
    | ENVIRONMENT | MEDIUM | Re-run after infra check — **no Jira bug** |
    | NEW TEST | LOW | Manual verification → if a genuine product defect, file Jira Bug/Defect; else accept or fix |
    
    > **KNOWN-BLOCKED — consuming the blocked-test marker.** The `@blocked:{BUG-KEY}`
    > tag + `test.fail('Blocked by {BUG-KEY}')` marker is **defined in
    > `test-automation`** (`references/automation-standards.md` §7 Stability; the
    > `PROGRESS.md` blocked-tests note lives in `references/planning-playbook.md`) —
    > this skill only *consumes* it. The GO/NO-GO gate MUST recognize `@blocked:{BUG-KEY}` tests and
    > classify them as **KNOWN-BLOCKED, never REGRESSION**: they are deliberately
    > parked behind an already-filed bug, not a fresh failure. Exclude them from the
    > pass-rate that gates the release (see §Compute metrics), and list each in the
    > report under its own heading with the blocking `{BUG-KEY}`. Do NOT file a new
    > Jira bug — the marker already names the open one.
    
    > **`sdet` CI-fallback clause** (integration-trunk suites only): an ENVIRONMENT-class red on a Sanity-CI run for a ticket branch may authorize merging **into the integration trunk** — never the final `trunk → main` PR — when proven by BOTH (a) the change passing locally on `local` AND `staging`, and (b) the same red being present independent of the change (nightly already red, or the failing line is shared pre-existing code). File a separate infra/flake ticket and reference it in the PR. This is NOT a relaxation of the GO bar: a REGRESSION-class failure is never eligible, and the final PR to `main` still requires a genuinely green test step. See `.agents/skills/git-flow-master/references/sdet-integration-trunk.md` §CI-fallback clause.
    
    Read `references/failure-classification.md` when: the decision tree is ambiguous, you need the full error-pattern catalogue, you are classifying a borderline case, or you are computing flakiness over historical runs.
    
    ### Step 5: Assess severity per failure
    
    Severity is independent of classification. A FLAKY test on the checkout flow is still CRITICAL severity.
    
    | Severity | Criteria |
    |----------|----------|
    | CRITICAL | Core user journey (login, checkout, payment). Any `@critical` tagged test. |
    | HIGH | Major feature (search, profile, dashboard) |
    | MEDIUM | Secondary feature (filters, preferences) |
    | LOW | Edge case or admin-only path |
    
    ### Output of Phase 2
    
    An analysis block with: metrics table, trend delta, one section per failure category (Regressions first, then Flaky, Known, Environment, New), per-failed-test detail (name, ATC ID, suite, error, last-pass date, screenshot link), job summary, and a preliminary verdict.
    
    ---
    
    ## Phase 3 — Report & Decide
    
    ### GO / CAUTION / NO-GO scoring
    
    Compute a weighted score from the analysis. Maximum is 9.
    
    | Factor | +3 | +1 | 0 | -1 | -2 | -3 |
    |--------|----|----|---|----|----|----|
    | Pass Rate | ≥ 95% | 90–95% | | | < 90% | |
    | Regressions | 0 | 1-2 Low | | 1+ Medium | | Any High/Critical |
    | Critical tests | All pass | | | | | Any fail |
    | Flaky tests | | ≤ 3 | 4-5 | > 5 | | |
    
    **Verdict thresholds:**
    - Score **≥ 7** → **GO** — release approved
    - Score **4-6** → **CAUTION** — manual review required, document accepted risks
    - Score **< 4** → **NO-GO** — block release, fix regressions, re-run
    
    Never auto-GO if: any `@critical` test fails, any REGRESSION with HIGH/CRITICAL severity exists, or pass rate < 90%. These are hard vetoes regardless of score.
    
    ### File defects in Jira (when decision = NO-GO or CAUTION with regressions)
    
    > **Quality issues go to Jira, not GitHub.** A regression-discovered product
    > failure is a defect-management artifact and follows
    > `agentic-qa-core/references/defect-management-doctrine.md` — the same authority
    > `/sprint-testing` uses. This skill files the issue IN JIRA with the full
    > mandatory field matrix; it does NOT open a GitHub issue.
    
    **Only CONFIRMED real product failures become Jira issues.** Use the Phase 2
    Step 4 triage as the gate: file in Jira **only** for the `REGRESSION` class and
    for a `NEW TEST` failure once it is manually confirmed to be a genuine product
    defect (not a bad assertion). **`FLAKY`, `ENVIRONMENT`, and `KNOWN ISSUE` do NOT
    get a Jira bug** — they route to stabilization / infra / the existing ticket as
    the classification table already prescribes. The failure-triage classification
    and the defect issue-type are **separate axes**: triage decides *whether* to
    file; the doctrine decides *what type* and *what fields*.
    
    For each issue that clears the gate:
    
    1. **Classify Bug vs Defect** by the affected feature's lifecycle stage, NOT by
       where the failure ran (doctrine Part 1): the regressed feature is **already
       live above Staging (production / superior env)** → **Bug**; the feature is
       still **pre-release (Staging or below)** → **Defect**. A genuinely new,
       desirable behavior surfaced beyond the AC → **Improvement** (Part 1).
    2. **File it in Jira with the full mandatory field matrix** (doctrine Part 5):
       `severity` (impact-based) → `priority` auto-derived (Part 5.1), native
       `components` = affected product module (Part 3, mandatory & pre-existing),
       `root_cause` + `error_type` + `test_environment`, `qa_assignee` = the
       authenticated session user (self; never-overwrite, Part 2), and `evidence`
       (Allure link + failure screenshots/traces/logs from `./analysis/evidence/`).
    3. **Parent to the QA Defect Management epic** — the QA process epic
       (`qa.qa_epics.defect_epic.name`), found-or-created; NEVER a product/dev epic
       (Part 4).
    4. **Link to the source Story/feature** for traceability via the causal link
       (Part 4) — the regressed ATC's covering Story.
    5. **Write via acli/REST** (doctrine Part 6): create with acli
       `workitem create --from-json` (create-time customfields under
       `additionalAttributes.customfield_*`, native `components:[{name}]`); set
       customfields/components on an existing issue via REST `PUT
       /rest/api/3/issue/{KEY}`; `qa_assignee` is read-before-write. Because this
       stage may run **from CI**, **load `/acli` first** (it owns auth, syntax, and
       the REST-PUT pattern in `references/acli-integration.md`).
    
    Run the doctrine's **filing gate** (Part 9) before submitting each issue. Save
    the returned Jira key to reference in the report.
    
    ### TMS sync (optional, when `[TMS_TOOL]` is configured via `.agents/project.yaml` `testing.tms_cli`)
    
    > **Prerequisite**: Load `/xray-cli` skill (Modality jira-xray) before executing the `[TMS_TOOL]` commands below. In Modality jira-native, load `/acli` instead and map test-execution operations to native Jira issues (see `test-documentation/references/jira-setup.md`).
    
    The sprint regression maps to two Jira **items** (items-first by excellence — the Story custom field is never used at this altitude).
    
    > **This skill has no sprint concept of its own.** `N` is NOT derivable from a suite run: take it from the user, or from the `Sprint#{N}` scope-id of the STP this skill finds. **Never invent it** — a guessed `N` forks a duplicate STP/STR pair for the sprint. No STP found and no `N` given → ASK before creating anything at sprint altitude.
    
    - **STP** (Sprint Test Plan) — a **Test Plan** item titled `STP: Sprint#{N}: {sprint objective}` (e.g. `STP: Sprint#30: Checkout hardening`). Parents to the **QA Master Test Plan** epic (`qa.qa_epics.master_test_plan_epic.name`); `relates to` the Sprint. **Producer: `/sprint-testing`** — its Session Start find-or-creates the STP on the FIRST ticket of the sprint, and every tested ticket updates it (a live planner: scope, progress). This skill **CONSUMES** the STP as context; it find-or-creates it **only as a fallback** when a suite runs and the STP is missing. **Never write results into it**: an Xray Test Plan aggregates the LATEST status of each of its Tests across all Executions, so the STP rolls up on its own as the ATRs and the STR accumulate — it carries the plan (description) and the human observations (comments), nothing else (`test-documentation/references/xray-platform.md` §4).
    - **STR** (Sprint Test Results) — a **Test Execution** item titled `STR: Sprint#{N}: Regression Testing` (e.g. `STR: Sprint#30: Regression Testing`). Parents to the **QA Test Artifacts** epic (`qa.qa_epics.test_artifacts_epic.name`); `relates to` the Sprint; `testPlan` → STP. Created at sprint **CLOSE** as the recap of all sprint results — by THIS skill when it runs the closing regression, or completed by `/sprint-testing`'s batch close if that already created it: **whoever arrives first creates it, the other completes it**. The run's term is **Regression Testing** — "Sprint" already comes from the `Sprint#{N}` scope-id, so the title carries no redundant "Sprint Regression".
    
    **Environment gate**: every Test Execution this skill creates — the STR included — carries the **Test Environment** taken from `active_env` in `.agents/project.yaml`, set at create time. An Execution without its environment fails the checklist: do not write results into it until the environment is set.
    
    **Ownership gate**: every artifact this skill CREATES (the STR, and the STP in the fallback case) carries `assignee` = the authenticated session user, set at create time — `agentic-qa-core/references/artifact-lifecycle.md` §2. Xray refuses membership edits on a Test Plan the caller does not own, so an unassigned Plan turns into a blocker the moment tests must be added to it. If the find returns an artifact someone ELSE owns, do not reassign it silently: ask first.
    
    **Lifecycle gate** (`agentic-qa-core/references/artifact-lifecycle.md` §1):
    
    - The **STR** is born `{{jira.status.test_execution.active}}` and MUST be transitioned to `{{jira.status.test_execution.close}}` via `{{jira.transition.test_execution.complete}}` **after the GO / CAUTION / NO-GO verdict is written** — never before the verdict, never left open.
    - The **RTP** (and any Test Plan this skill only consumed) stays at `{{jira.status.test_plan.ready}}` and is **never completed** by a regression run: the RTP is long-lived, and a suite execution does not finish the plan it ran from. Do NOT fire `{{jira.transition.test_plan.complete}}` here.
    - The **STP** is closed by whoever owns sprint close, not by this skill — unless this skill IS the sprint close (see the sprint-close DoD in `stage-gates.md`), in which case `{{jira.transition.test_plan.complete}}` moves it to `{{jira.status.test_plan.completed}}` after the STR is closed.
    - **Unmapped slug** → `artifact-lifecycle.md` §4 fallback: list the LIVE transitions, propose the closest synonym in ONE `AskUserQuestion`, fire the live id on yes, recommend `bun run jira:sync-workflows`. Never skip silently, never guess an id.
    
    **Find-or-create the STR before updating it** — never assume another producer already created it; if `/sprint-testing`'s batch close got there first, the find returns its item and this skill only completes it:
    
    ```
    [TMS_TOOL] Find-or-create Test Execution:
      summary: STR: Sprint#{N}: Regression Testing
      parent: {QA Test Artifacts epic — qa.qa_epics.test_artifacts_epic.name}
      links: {relates to → Sprint; testPlan → STP key}
      environment: {active_env from .agents/project.yaml}
    
    [TMS_TOOL] Update Test Execution:
      executionKey: {STR execution-key}
      results: {per-ATC status + failure comments from Phase 2}
    
    # After the Phase 3 verdict is written — close the run, never leave it ACTIVE:
    [ISSUE_TRACKER_TOOL] Transition: {{jira.transition.test_execution.complete}}   # active -> close
      issue: {STR execution-key}
    ```
    
    ### Write the report
    
    Save to `.context/reports/regression-{env}-{date}.md`. Use `references/failure-classification.md` only if you need the pattern catalogue; the report template itself is inline below.
    
    ---
    
    ## Report template
    
    ```markdown
    # Regression Quality Report — {env} — {date}
    
    ## Executive Summary
    **Verdict: {GO / CAUTION / NO-GO}**
    Score: {score}/9. {one-line rationale}
    
    | Metric | Value | Threshold | Status |
    |--------|-------|-----------|--------|
    | Pass Rate | {x}% | >= 95% | {ok/warn/fail} |
    | Regressions | {n} | 0 | {ok/warn/fail} |
    | Critical failures | {n} | 0 | {ok/warn/fail} |
    | Flaky | {n} | <= 3 | {ok/warn/fail} |
    | Duration | {d} | - | - |
    
    ## Release Blockers
    {if NO-GO, enumerate regressions with severity, owner, ETA. Otherwise: "None."}
    
    ## Failure Details
    ### Regressions ({n})
      - {test} | {atc_id} | last passed {date} | [issue]({url}) | probable cause: {...}
    
    ### Flaky ({n}) — schedule stabilization
    ### Known Issues ({n}) — accepted
    ### Known-Blocked ({n}) — excluded from gating pass-rate
      - {test} | {atc_id} | blocked by [{BUG-KEY}]({url})
    ### Environment ({n}) — re-run after infra check
    
    ## Trend (last 5 runs)
    {ASCII sparkline or pass-rate table}
    
    ## Links
    - Workflow run: {url}
    - Allure: {url}
    - Created issues: {list}
    - TMS execution: {key / url}
    
    ## Recommendations
    1. Immediate (pre-release): {...}
    2. Short-term (this sprint): {...}
    3. Long-term (tech debt): {...}
    ```
    
    ### Post-decision actions
    
    | Decision | Actions |
    |----------|---------|
    | GO | Mark release candidate approved; schedule post-deploy smoke |
    | CAUTION | Review with team lead; document accepted risks; proceed deliberately |
    | NO-GO | Block release; assign regression issues; schedule fix verification; plan re-run |
    
    Whatever the verdict, close the run: transition the STR to `{{jira.status.test_execution.close}}` via `{{jira.transition.test_execution.complete}}`, leave the RTP at `{{jira.status.test_plan.ready}}`, then run the **light stage verifier** (`agentic-qa-core/references/artifact-lifecycle.md` §5). Stage-specific lines:
    
    ```
    [ ] STR exists by KEY, carries its Test Environment, assignee = self
    [ ] STR at {{jira.status.test_execution.close}} — via complete, AFTER the verdict
    [ ] STR -> STP linked via the `testPlan` edge
    [ ] RTP untouched at {{jira.status.test_plan.ready}} (a regression run never completes it)
    [ ] Verdict comment posted in the TMS (the durable record — not the local report file)
    [ ] Any unmapped slug went through the §4 fallback (asked), never a silent skip
    ```
    
    ### Per-phase progress + Archive
    
    After Phase 1 Monitor returns, after each Phase 2 step (Collect / Parse / Compute / Classify / Severity), and after Phase 3 Verdict, the orchestrator appends a phase entry to `.session/regression-testing/<scope>/progress.md` per `agentic-qa-core/references/session-management.md` §7. `artifacts_touched` records the downloaded CI artifacts (allure / evidence / playwright dirs) + the final `.context/reports/regression-<env>-<date>.md`.
    
    After the Verdict emits, the orchestrator runs Archive per `agentic-qa-core/references/session-management.md` §8: moves `.session/regression-testing/<scope>/` to `.session/.archive/<YYYY-MM-DD>-regression-testing-<scope>/` (two-file dir preserved) and calls `mem_session_summary` with the archive path. `.context/reports/regression-<env>-<date>.md` stays in the reports dir as a **local generated report** — that directory is gitignored `[LOCAL]` output (`.context/reports/README.md`), so the file exists only on the machine that ran the suite and nothing downstream may depend on it. **The durable record is the STR in the TMS plus the GO / CAUTION / NO-GO comment** posted with it.
    
    On Verdict = NO-GO with regressions still being filed as issues, archive WAITS until the issue-creation step completes (so the session state still references the open issue list at archive time).
    
    ---
    
    ## Gotchas
    
    - **Allure URL is predictable but only live after the "Build & Deploy Allure Report" job succeeds.** If that job failed, the URL 404s — analyze from downloaded artifacts instead.
    - **`gh run watch` can time out** on long suites. Fall back to polling `gh run view <RUN_ID> --json status` every 60-90 seconds.
    - **`gh run view --log` dumps every step's output** and is often >50MB on large suites. Always prefer `--log-failed` during analysis; use `--job=<JOB_ID> --log` for targeted drilldown.
    - **This repo ships `retries: 0` everywhere** (`playwright.config.ts`) — tests must be deterministic, and a retry would only mask the flake. A flaky test therefore surfaces as a plain intermittent failure and is caught by the >20% history rule, never by a retry-pass signal. If a downstream project has consciously enabled retries, a test that passes on retry is still flaky — see the "Conscious divergence: enabling retries" box in `references/ci-cd-integration.md` for how to read retry counts in Allure.
    - **ENVIRONMENT is not a scapegoat.** `ECONNREFUSED` to your app's own API probably means the app crashed, not "infra glitch". Check if the same run has many unrelated tests failing on the same host — that is environment. One test failing with a network error on an endpoint that other tests hit successfully is more likely a REGRESSION.
    - **Never mark NEW TEST as REGRESSION.** A first-ever failure with no history is not a regression — it is unverified. Manually confirm once before classifying.
    - **Flakiness needs 5 runs of history minimum before you can call it at all** (below that, mark "insufficient history" and re-evaluate next sprint — do not guess). The failure-rate itself is computed over a wider window: the last N = min(10, available) runs (see `references/failure-classification.md`). 5 is the floor to have any signal; 10 is the window the percentage is actually computed over.
    - **Sanity + `grep` and `test_file` are mutually exclusive.** Passing both makes the workflow ignore one silently. Pick one.
    - **Video recording inflates artifact size by 5-10x.** Only enable `video_record=true` when debugging flakiness or capturing bug evidence. Never enable it for nightly regression.
    - **CI credentials come from GitHub secrets, not `.env`.** Do not copy values from local `.env` into workflow YAML — reference `${{ secrets.NAME }}` only.
    - **Session-footer contract (mandatory at close).** The final phase is not done until the two chat-facing blocks from `../agentic-qa-core/references/session-footer-contract.md` are printed: (1) consolidated screenshot list — repo-relative paths, verified on disk, bug annotations first — plus in-flow surfacing of every capture's path the instant it lands; (2) Session Footer listing skills/MCPs/CLIs actually used + testing levels touched, with explicit "none" entries for expected-but-untouched levels. Framing for this skill: execution. Multi-subagent sessions: each stage report carries the five footer fields (`skills_loaded`, `mcps_used`, `clis_used`, `testing_levels_touched`, `screenshots_captured`); the orchestrator compiles the footer ONCE at close. Chat only — never in a Jira comment or ATR body.
    
    ---
    
    ## Specific tasks
    
    * **Configuring or debugging GitHub Actions workflows** — read `references/ci-cd-integration.md`
    * **Enabling GitHub Pages so the published Allure reports are browsable ("set up GitHub Pages", "report URL is 404", "publish the reports site")** — read `references/github-pages-setup.md` (enable via `gh api`, first-build stuck/errored gotcha + manual rebuild, gh-pages history squash job). Run the §Allure version-currency check first.
    * **Making CI reports PRIVATE ("reports must be login-protected", "no publiques evidencia pública", "protege los reportes")** — read `references/private-hosting-setup.md` (Test Report Portal: Vercel + Supabase + private R2, work-email login, portal-side retention, history round-trip replacing gh-pages). The publish step in all three suite workflows is already dual-mode — you only wire secrets. GitHub Enterprise orgs have a zero-infra shortcut (Pages visibility → Private); offer it first.
    * **Setting up Allure locally for the first time, or the user asks "is Allure up to date?"** — run the §Allure version-currency check under §Local reporting.
    * **Classifying a borderline failure (REGRESSION vs FLAKY vs ENVIRONMENT)** — read `references/failure-classification.md`
    * **TMS / Xray result import** — load `/xray-cli` skill
    * **Downloading traces or screenshots for a failure** — use `[AUTOMATION_TOOL]` per AGENTS.md Tool Resolution; for Playwright trace inspection load `/playwright-cli`
    * **Session contract (Phase 0 resume, plan.md/progress.md schemas, archive policy, Engram per-phase checkpoint, RUN_ID re-attach mechanism)** — read `../agentic-qa-core/references/session-management.md`. This skill is a producer of `session/regression-testing/<scope>/...` topic keys.
    
    ---
    
    ## Anti-patterns — NEVER do these
    
    - **R1.** NEVER classify a failure as FLAKY without re-running the test in isolation — masks real regressions.
    - **R2.** NEVER emit GO when known REGRESSION class > 0 — quality gate is binary: regressions block.
    - **R3.** NEVER auto-retry failing tests in CI without surfacing the retry count in the report.
    - **R4.** NEVER skip Allure artifact download on red builds — evidence vanishes after the retention window.
    - **R5.** NEVER trigger a regression workflow without `--ref <commit-sha>` pinned — different commit = different baseline.
    - **R6.** NEVER mix smoke + regression suite results into one pass-rate number — different SLOs.
    - **R7.** NEVER mark a test KNOWN-failure without a Jira ticket linking the suppression to a tracking issue.
    
    ---
    
    ## Quick reference
    
    ```bash
    # Trigger + get run ID in one shot
    gh workflow run regression.yml -f environment=staging && sleep 5 && \
      RUN_ID=$(gh run list --workflow=regression.yml --limit=1 --json databaseId -q '.[0].databaseId') && \
      echo "RUN_ID=$RUN_ID"
    
    # Wait for completion
    gh run watch $RUN_ID
    
    # Failed logs only
    gh run view $RUN_ID --log-failed
    
    # All failure evidence
    gh run download $RUN_ID -n e2e-failure-evidence -D ./analysis/evidence/
    
    # Previous run for trend
    PREV=$(gh run list --workflow=regression.yml --limit=2 --json databaseId -q '.[1].databaseId')
    gh run download $PREV -n merged-allure-results-staging -D ./analysis/previous/
    ```
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related