A passing GitHub Actions job is a weak unit of evidence when the release contract is “every intended matrix case ran and produced an acceptable result.” Matrix expansion can add cases, remove cases, or re-add excluded cases; strategy.fail-fast can cancel queued or in-progress siblings after one matrix child fails; and GitHub’s required-check machinery can treat some skipped jobs as successful. GitHub documents each behavior separately, but a release decision still needs a denominator: the exact case identities that were supposed to exist. The matrix documentation, workflow syntax reference, contexts reference, and workflow-jobs REST API provide the platform contract; they do not author your release oracle for you.
This playbook narrows the question to three things: include/exclude expansion, fail-fast cancellation, and required-job completeness. It deliberately avoids a general GitHub Actions tutorial. The fixture below is executable, uses synthetic values, requires no production credentials, and records source hashes and runtime identities. The GitHub-hosted fixture has not been executed. Therefore every run outcome in this article is labeled EXPECTED / NOT EXECUTED; no log line, case count, cancellation pattern, runner version, or API response is presented as observed. That separation is part of the method, not a caveat to hide. The acceptance question is: after comparing an independently authored expected-case manifest with GitHub’s recorded jobs, do we have enough evidence to choose ACCEPT, REPAIR, RERUN, or HOLD?
Define the Operational Contract and Release Gate
The operational contract should be written before the workflow is triggered. For this fixture, the contract is not “workflow conclusion is green” and not “a named job passed.” It is: the matrix expansion must produce exactly the independently specified case identities; every required identity must appear exactly once in the selected run attempt; no required identity may end as cancelled, skipped, timed_out, or absent; and the designated release gate must evaluate the evidence rather than infer completeness from an aggregate status. GitHub documents that matrix.exclude removes matching configurations, matrix.include can augment compatible original combinations or create new ones, and include entries are processed after exclude such that an excluded configuration can be added back.
The release procedure has four artifacts: the workflow YAML, expected-cases.json, a raw REST response for jobs, and reconcile.py output. The manifest is the independent oracle; it must not be generated from the REST response it later judges. The job API supports filter=latest and filter=all; all is important during rerun analysis because it includes jobs from earlier executions of the same workflow run, while latest returns only the most recent execution.
The pass condition is strict: expected identities equal observed identities for the chosen attempt, cardinalities match, duplicates are zero, and every required case has an allowed conclusion. A success elsewhere does not compensate for a missing case. That principle overlaps in method, but not in technical subject, with Refonte Learning’s pytest xfail strict xpass release gate validation, which also separates process-level success from per-case evidence. This article does not reuse its pytest fixture or XPASS decision; the denominator here is GitHub Actions matrix identities.
Capture the Baseline and Versioned Environment
A reproducible diagnosis starts with version and source identity, not screenshots. Before dispatching the fixture, record the repository commit, workflow bytes, oracle bytes, local client versions, and the API version used to query GitHub. GitHub’s current REST documentation shows X-GitHub-Api-Version: 2026-03-10 in examples; use the version you actually invoke and record it beside the response rather than assuming the documentation version will remain unchanged.
Use a disposable clone or purpose-built test repository and capture commands verbatim:
set -euo pipefail
mkdir -p evidence
git --version | tee evidence/git-version.txt
python3 --version | tee evidence/python-version.txt
curl --version | head -n1 | tee evidence/curl-version.txt
git rev-parse HEAD | tee evidence/source-commit.txt
sha256sum \
.github/workflows/matrix-proof.yml \
expected-cases.json \
reconcile.py \
| tee evidence/source-sha256.txt
git status --porcelain=v1 | tee evidence/worktree-status.txtDo not fill the evidence files with sample values. The measurable assertion is that worktree-status.txt is empty when the run is launched and that the recorded source-commit.txt equals the commit referenced by the GitHub run. If either differs, the evidence set is not bound to the code you think you tested, so the decision is HOLD rather than “close enough.”
GitHub’s contexts expose github.sha, github.run_id, github.run_attempt, the matrix object, and strategy properties including job-index and job-total; these are appropriate runtime evidence because they describe the current run and matrix child rather than ambient assumptions. The article does not state any concrete runner image version because the fixture was not executed; capture the runner-provided values at execution time.
Treat the version bundle as evidence, not decoration. If curl or python3 changes between attempts, that does not automatically invalidate the GitHub-side observation, but it changes the collector environment and should be recorded. More importantly, if the workflow commit or oracle hash changes, the attempts are no longer tests of the same contract. Keep a small evidence/README.txt that names the UTC capture time, repository owner/name, run ID, attempt, API version, and analyst. That file is not proof by itself; it is an index into the cryptographic hashes and raw responses. When a later reviewer asks whether a rerun used the same source, the answer should come from those recorded identifiers rather than memory or the web UI.
Construct a Disposable Controlled Fixture
The fixture uses synthetic matrix labels and a single runner family so that the experiment tests scheduling and evidence semantics, not OS-specific application behavior. The matrix has two base flavors, two shards, and a baseline marker. One base combination is excluded, then re-added with a different marker; another entirely new flavor is added; and an include rule adds a note field to compatible vanilla combinations. That exercises both “augment an existing combination” and “create a new combination” behavior described by GitHub.
# .github/workflows/matrix-proof.yml
name: matrix-proof
on: workflow_dispatch
permissions:
contents: read
jobs:
probe:
name: probe-${{ matrix.flavor }}-${{ matrix.shard }}-${{ matrix.marker }}
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
flavor: [vanilla, chocolate]
shard: [1, 2]
marker: [baseline]
exclude:
- flavor: chocolate
shard: 2
marker: baseline
include:
- flavor: vanilla
note: included
- flavor: chocolate
shard: 2
marker: readded
- flavor: strawberry
shard: 1
marker: include-only
steps:
- name: Emit identity
shell: bash
run: |
set -euo pipefail
printf '%s\n' \
"sha=${GITHUB_SHA}" \
"run_id=${GITHUB_RUN_ID}" \
"attempt=${GITHUB_RUN_ATTEMPT}" \
"case=${{ matrix.flavor }}|${{ matrix.shard }}|${{ matrix.marker }}" \
"note=${{ matrix.note || 'none' }}"This workflow intentionally has no checkout, secret use, deployment, package publication, or external mutation. It can therefore be placed in an isolated repository without exposing production credentials.
Pin Inputs and Isolate Side Effects
The boundary example is simple: ubuntu-24.04 is part of the workflow source, but the semantic test inputs are only flavor, shard, marker, and optional note. No test case should write to an external system. The measurable assertion is that the workflow’s permissions remain contents: read, no secrets.* references exist, and no step invokes a network write. If the fixture grows a deployment token or repository write permission, stop: the diagnostic has crossed its disposable boundary.
That boundary resembles the Refonte article on git diff untracked staged build input validation: its narrow contract distinguishes allowed build inputs from ambient workspace state. Here the analogous discipline is to distinguish declared matrix inputs from unrelated runner behavior; the Git-specific test and decision are not repeated.
Define an Independent Evidence Oracle
Author the expected-case manifest by reasoning from the workflow source and the documented matrix rules, then freeze its hash before execution. Do not ask GitHub what jobs it created and serialize that answer as “expected.” That would make the oracle circular. The base Cartesian product contains four combinations. chocolate|2|baseline is excluded. The vanilla include adds only a non-axis note to compatible vanilla originals. The re-added chocolate case cannot overwrite the excluded original’s marker and therefore exists as a new combination with marker=readded; strawberry is also new. Under the documented include/exclude rules, the expected denominator is five case identities.
{
"schema": 1,
"workflow": "matrix-proof",
"job_prefix": "probe-",
"required": [
{"id": "vanilla|1|baseline", "note": "included"},
{"id": "vanilla|2|baseline", "note": "included"},
{"id": "chocolate|1|baseline", "note": "none"},
{"id": "chocolate|2|readded", "note": "none"},
{"id": "strawberry|1|include-only", "note": "none"}
],
"allowed_conclusions": ["success"]
}There are two independent assertions. First, the manifest must have five unique IDs. Second, the REST job inventory for the selected attempt must contain those same five probe names exactly once. strategy.job-total is useful corroborating evidence inside each child, but it is not the independent oracle because GitHub computes it from the matrix expansion being tested. The contexts reference says strategy.job-total is the total number of jobs in the matrix and job-index is zero-based; record them as platform evidence, not as the denominator you authored.
The independence rule also changes how you review pull requests. A workflow edit that changes matrix axes, exclude, or include must be accompanied by a separately reviewed oracle edit that explains the new denominator. Reviewers should be able to derive each manifest row from source without consulting a completed run. If the workflow adds flavor: mint but the manifest remains unchanged, the correct pre-run decision is REPAIR because the contract and executable configuration disagree. If the manifest adds mint but the workflow does not, that is equally invalid. This two-file tension is intentional: it makes accidental matrix drift visible before the first API call.
Reproduce the Misleading Success Case
The negative control needs a passing job beside an incomplete matrix. Add a second matrix job with fail-fast: true, max-parallel: 1, and an intentional failure in one early case, plus a sentinel job that always succeeds. GitHub documents that when fail-fast is true, a failing non-tolerated matrix job causes in-progress and queued matrix jobs to be cancelled; the default for fail-fast is true. Setting it explicitly avoids relying on the default.
negative:
name: negative-${{ matrix.flavor }}-${{ matrix.shard }}
runs-on: ubuntu-24.04
strategy:
fail-fast: true
max-parallel: 1
matrix:
flavor: [vanilla, chocolate]
shard: [1, 2]
steps:
- name: Controlled failure
shell: bash
run: |
set -euo pipefail
if [[ "${{ matrix.flavor }}|${{ matrix.shard }}" == "vanilla|1" ]]; then
exit 23
fi
sleep 20
sentinel:
runs-on: ubuntu-24.04
steps:
- run: printf '%s\n' 'sentinel reached'EXPECTED / NOT EXECUTED: sentinel should pass independently, while the negative matrix should contain at least one failure and, under fail-fast, cancellation of siblings that are queued or in progress. The exact cancellation pattern must not be fabricated in advance because scheduling is runtime evidence. The test is successful as a negative control if the evidence shows that “a job passed” coexisted with an incomplete matrix.
Do not use the overall workflow conclusion as the sole negative-control assertion. The workflow is expected to be non-green because one matrix child intentionally fails, so it cannot demonstrate the narrower mistake by itself. The point is that a visible, potentially required check can be green while the evidence set for another required semantic contract is incomplete. GitHub’s required-check documentation is especially relevant here because it separates check conclusions from whether intended work actually ran, including the documented case where a conditionally skipped job reports success. The negative control therefore records job-level identities and conclusions side by side instead of collapsing them into a single badge.
Record the Negative Control Before Repair
Do not remove fail-fast: true before preserving the first job inventory. The measurable assertion is not “three siblings cancelled”; it is “the observed probe set does not satisfy the four-case negative manifest because one or more required identities lack an allowed completed conclusion.” If every negative child somehow completes before cancellation takes effect, record that as an environmental boundary and RERUN with stronger serialization rather than rewriting the expected observation after the fact.
Run a Contrasting Correctness Case
The positive control should remove the intentional failure and set fail-fast: false so that no sibling is cancelled merely because another child fails in a future mutation. GitHub documents that fail-fast: false prevents the matrix-wide cancellation behavior that true triggers. This does not make failed cases acceptable; it only makes case completion evidence easier to obtain.
For the probe job shown earlier, the expected release condition is five completed matrix children with conclusion success, exact identity equality with expected-cases.json, and no duplicates. EXPECTED / NOT EXECUTED: if the workflow source and GitHub’s documented expansion semantics agree, the five names should be probe-vanilla-1-baseline, probe-vanilla-2-baseline, probe-chocolate-1-baseline, probe-chocolate-2-readded, and probe-strawberry-1-include-only. This sentence is an expected manifest projection, not an observation.
A useful contrast is Refonte Learning’s ansible check mode task coverage validation, which treats a green dry-run recap as insufficient when intended validators did not execute. The shared method is coverage reconciliation; the technical mechanism here is different. This playbook does not reuse its Ansible task fixture, commands, or decisions.
The pass/fail split is important: fail-fast: false is not a repair for broken tests. A matrix child that fails is still a failed required identity. The setting only prevents that failure from erasing evidence about siblings. Therefore a correctness run with one failure and four success conclusions is complete but not acceptable; it moves to REPAIR, not ACCEPT.
Explore Failure and Boundary Conditions
Three boundaries deserve explicit tests. First, mutate expected-cases.json to remove one valid case; the reconciler must detect an unexpected observed identity rather than “helpfully” accepting it. Second, duplicate one expected ID; the reconciler must reject the oracle itself before looking at GitHub. Third, analyze a rerun with the jobs endpoint’s filter=all; old executions and the current attempt can coexist, so an attempt-selection rule is mandatory. GitHub documents that filter=all includes old executions while latest limits results to the most recent execution.
Also test non-success conclusions explicitly. GitHub’s status-check reference distinguishes conclusions including success, failure, cancelled, skipped, neutral, timed_out, action_required, and stale. For this release contract, only success is allowed for required matrix identities. That is a project policy layered on top of GitHub’s broader status vocabulary.
Check Missing and Duplicate Evidence
The boundary example is a ledger with five expected IDs but only four unique observed probe names. The measurable assertion is missing_count == 1, duplicate_count == 0, and decision HOLD if the cause is unknown or RERUN if the cause is a known transient cancellation. Conversely, if six job rows map to five unique IDs, do not silently de-duplicate: retain the duplicate job IDs and attempt metadata and mark the set HOLD until you can explain whether a rerun, duplicate naming rule, or collector error produced the extra row.
A branch-protection nuance reinforces this conservatism. GitHub states that a job skipped by a conditional reports success and does not block merging even when it is a required check. Therefore “required check passed” and “required semantic work executed” are not interchangeable claims.
Another boundary is pagination. The workflow-jobs endpoint allows up to 100 items per page, while GitHub’s matrix syntax allows substantially more than the five cases used here. A production collector must either paginate or prove that its matrix cannot exceed the requested page size; otherwise a truncated response can masquerade as missing jobs. GitHub documents both the jobs endpoint pagination parameters and a matrix maximum of 256 generated jobs per workflow run. The sample fixture stays below one page, but the acceptance design should still make truncation impossible to confuse with cancellation.
Capture Complete Per-Case Evidence
After a run completes, capture the workflow-run object and the job inventory as raw JSON before transforming them. The workflow-runs API exposes run identifiers and run_attempt; the jobs endpoint lists jobs and supports pagination. Preserve both raw responses so the ledger can be re-derived without another API call.
set -euo pipefail
: "${OWNER:?set OWNER}"
: "${REPO:?set REPO}"
: "${RUN_ID:?set RUN_ID}"
: "${GITHUB_TOKEN:?set a read-only token for the disposable repo}"
api='2026-03-10'
base="https://api.github.com/repos/${OWNER}/${REPO}/actions/runs/${RUN_ID}"
curl --fail-with-body --silent --show-error \
-H 'Accept: application/vnd.github+json' \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: ${api}" \
"${base}" > evidence/run.json
curl --fail-with-body --silent --show-error \
-H 'Accept: application/vnd.github+json' \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: ${api}" \
"${base}/jobs?filter=all&per_page=100" > evidence/jobs-all.json
sha256sum evidence/run.json evidence/jobs-all.json \
> evidence/api-response-sha256.txtDo not echo the token, store it in the evidence directory, or embed a production credential in the fixture. For a public disposable repository, GitHub documents that the jobs endpoint can be used without authentication; for private repositories, use the minimum read permission appropriate to the endpoint.
The per-case ledger should retain GitHub job ID, job name, status, conclusion, started/completed timestamps, head SHA where present, and source attempt context from run.json. The acceptance assertion is that every expected identity maps to one job row in the chosen attempt and that each conclusion is permitted by policy.
Prefer machine-readable capture over copied console text. Console logs are valuable when diagnosing why a child failed, but the job inventory is the authoritative index for identity, status, and conclusion in this protocol. Store human notes separately so they cannot overwrite raw fields. If a UI label appears to disagree with the API, capture the UI only as supplemental evidence and keep the REST response unchanged. The workflow-jobs API returns job identifiers, names, statuses, conclusions, timestamps, steps, and runner-related fields in its response schema; those fields are suitable for the ledger because they are tied to the run rather than retyped by an analyst.
Reconcile Expected and Observed Identities
The reconciler should fail closed on malformed input, duplicate expected IDs, missing expected rows, unexpected rows, duplicate observed names, and disallowed conclusions. A compact standard-library implementation keeps the fixture independently runnable:
# reconcile.py
import json, sys
from collections import Counter
manifest = json.load(open(sys.argv[1], encoding="utf-8"))
jobs_doc = json.load(open(sys.argv[2], encoding="utf-8"))
expected = [
"probe-" + r["id"].replace("|", "-")
for r in manifest["required"]
]
if len(expected) != len(set(expected)):
raise SystemExit("HOLD duplicate expected identity")
observed = [j for j in jobs_doc["jobs"] if j["name"].startswith("probe-")]
names = [j["name"] for j in observed]
counts = Counter(names)
missing = sorted(set(expected) - set(names))
unexpected = sorted(set(names) - set(expected))
duplicates = sorted(n for n, c in counts.items() if c != 1)
allowed = set(manifest["allowed_conclusions"])
bad = sorted(
(j["name"], j.get("conclusion"))
for j in observed
if j["name"] in set(expected) and j.get("conclusion") not in allowed
)
ledger = {
"expected_count": len(expected),
"observed_count": len(observed),
"missing": missing,
"unexpected": unexpected,
"duplicates": duplicates,
"disallowed": bad,
}
print(json.dumps(ledger, indent=2, sort_keys=True))
raise SystemExit(1 if any([missing, unexpected, duplicates, bad]) else 0)Run it as python3 reconcile.py expected-cases.json evidence/jobs-latest-attempt.json > evidence/ledger.json; the filtering step that creates jobs-latest-attempt.json must be documented, deterministic, and tied to run_attempt. Because the jobs endpoint itself documents latest versus all, an even simpler policy is to capture both endpoints: use latest for acceptance and all for audit history.
The related Refonte article on git force with lease explicit expected commit validation similarly binds a decision to an independently recorded expected commit instead of a mutable tracking reference. That page’s Git push problem is distinct; the relevant analogy is “pin the expectation before observing the mutable system.”
For production use, extend the reconciler with explicit schema checks instead of relying on Python key errors. Validate that every job has a string name, a terminal status, and a conclusion when completed; reject null or unfamiliar values rather than treating them as success. Also write the reconciler’s own version or source hash into the ledger. A release gate that can change independently of the manifest is itself part of the trusted computing base. If reconcile.py is edited between the failed run and the rerun, keep both hashes and review the behavioral change before comparing decisions.
Retain Failure Artifacts Before Rerun
Before any rerun, copy run.json, jobs-all.json, ledger.json, source hashes, and the manifest into an immutable evidence directory named with the original RUN_ID and attempt. The measurable assertion is that the original artifact hashes still verify after the rerun. If the first evidence set is overwritten, you lose the ability to distinguish recovery from history rewriting and should mark the audit trail HOLD.
Separate Documented Behavior From Observation
A disciplined report has four columns of truth: documented contract, test hypothesis, actual observation, and inference. For this fixture, the documented contract is sourced from GitHub; the hypotheses are derived from the fixture; the observation column is NOT EXECUTED; and no inference is promoted to fact. GitHub documents the matrix include/exclude rules, fail-fast cancellation semantics, matrix/strategy contexts, REST job listing behavior, and status-check conclusions.
Claim | Classification | Evidence status |
Exclude removes matching configurations; include can add or augment configurations | Documented contract | Confirmed in GitHub docs |
fail-fast: true cancels queued/in-progress matrix siblings after a relevant failure | Documented contract | Confirmed in GitHub docs |
This fixture expands to five probe-* identities | Test hypothesis from documented rules | EXPECTED / NOT EXECUTED |
The negative control will show a passing sentinel beside incomplete matrix coverage | Test hypothesis | EXPECTED / NOT EXECUTED |
The positive case will reconcile five successful identities | Test hypothesis | EXPECTED / NOT EXECUTED |
A specific runner image, cancellation count, or job timing occurred | Observation | NOT EXECUTED; do not assert |
This separation matters because GitHub’s scheduler may affect which in-progress jobs reach cancellation before they finish, even though the fail-fast rule itself is documented. The exact cancellation pattern is therefore runtime evidence. Likewise, a job name produced by matrix interpolation should be recorded and compared, not hand-copied from a UI after the fact.
Where documentation and observation later contradict, retain both. A contradiction can mean an API-version difference, a workflow-source mismatch, a service behavior change, or a flaw in the oracle. The decision is HOLD until the contradiction is resolved; it is never acceptable to edit the expected manifest retroactively merely to make the ledger green.
Repair the Workflow Without Masking Errors
The primary repair is to make completeness a first-class gate, not to suppress failures. In a production-adapted workflow, keep fail-fast: false on matrix jobs whose complete evidence matters, then run a dedicated gate after the matrix with if: always() so it executes even when dependencies fail. The gate should query the current run’s jobs, compare them with a checked-in manifest, and fail if identities are missing, duplicated, cancelled, skipped, timed out, or failed. GitHub’s troubleshooting guide specifically recommends always() for required jobs that depend on other jobs, because dependent jobs can otherwise be skipped after failures.
Do not “repair” the workflow by adding continue-on-error: true to required cases. GitHub documents that continue-on-error applies to an individual job and can be combined with fail-fast; that changes failure propagation, not test correctness. If a required case fails, the evidence ledger should show a failure and the release decision should be REPAIR.
A safe gate also avoids dynamic job-name ambiguity. GitHub’s branch-protection documentation warns that job names should be unique across workflows when they are used as required status checks. Give the final completeness gate a stable, repository-unique name such as matrix-coverage-release-gate; let matrix children use identity-bearing names for evidence.
If branch protection or a ruleset requires that gate, verify that the workflow event is one GitHub evaluates for pull-request required checks. GitHub’s troubleshooting documentation notes that checks from workflow_dispatch runs do not satisfy a pull request’s required status check, while events such as push and pull_request are evaluated; merge queues require the separate merge_group event. The disposable fixture can remain manual, but a migrated production gate must use an event appropriate to the repository’s merge policy. Do not mistake a successful manual validation run for a branch-protection-enforced release gate.
Explain the Scope of the Fix
The boundary example is a test failure in probe-chocolate-1-baseline. Setting fail-fast: false is in scope because it preserves sibling evidence; changing that case’s assertion to always return zero is out of scope because it masks the defect. The measurable assertion after repair is twofold: the ledger has zero missing/duplicate identities, and every required identity has conclusion success. Completeness without correctness is REPAIR; correctness claims without completeness are HOLD.
Test Recovery, Rollback and Rerun Safety
A rerun is a new execution of the same workflow run, not permission to discard the first attempt. GitHub documents that reruns use the same GITHUB_SHA and GITHUB_REF as the original event, and that users with write permission can rerun workflows or jobs; the REST jobs endpoint can return either only the latest execution or all executions.
Recovery testing should therefore preserve attempt one, trigger the rerun, then capture both filter=latest and filter=all. The latest set answers “does the recovered attempt satisfy the contract?” The all-attempts set answers “what happened during recovery?” If a case failed in attempt one and passed in attempt two, acceptance may be possible only if your policy permits reruns and the source SHA is unchanged; the failure history must still remain auditable.
Be precise about what is rerun. GitHub supports rerunning an entire workflow, all failed jobs, or a specific job, and notes that dependent jobs are rerun with failed or selected jobs as applicable. A partial rerun can therefore produce an audit history in which some successful jobs are inherited from an earlier attempt while others are newly executed. If your contract requires one coherent attempt in which every matrix identity executed under the same attempt number, prefer a full rerun. If policy permits mixed-attempt evidence, state that explicitly and make the reconciler model provenance per job instead of flattening the run into a single set.
Rollback safety is a source-control question: if the repaired workflow changes semantics, keep the previous workflow commit identifiable and make the repair a separate commit. Reverting should restore the previous workflow bytes, not mutate a live run. Re-run safety also means the oracle remains independent: never regenerate expected-cases.json from attempt two just because attempt one exposed missing cases.
Apply the Acceptance and Ownership Matrix
A release decision needs an owner and a recovery action, not just a color. The table below is policy for this fixture, not GitHub’s built-in semantics.
Evidence state | Decision | Primary owner | Required action |
Exact expected identities; no duplicates; every required case success; source/run binding verified | ACCEPT | Release owner | Record ledger and approve |
Exact identities, but one or more required cases failure | REPAIR | Test/service owner | Fix cause, preserve evidence, rerun |
Missing cases explained by fail-fast cancellation or known transient scheduler condition; source unchanged | RERUN | CI owner | Preserve attempt, rerun under evidence-preserving settings |
Missing/duplicate identities with unknown cause; source hash mismatch; contradictory API/UI evidence; oracle defect | HOLD | CI + release owner | Reconcile before any release decision |
GitHub’s required-check behavior is deliberately not treated as equivalent to this table. A skipped job can report success for required-check purposes, and successful status conclusions can include success, skipped, and neutral; this playbook’s release gate is stricter because the contract requires execution of each intended matrix case.
Record ACCEPT, REPAIR, RERUN or HOLD
For this unexecuted fixture, the only defensible record is HOLD: NOT EXECUTED. There is no observed GitHub job inventory to reconcile. After a real run, the measurable assertion for ACCEPT is: reconcile.py exits 0, the ledger reports five expected and five observed probe identities, all difference sets are empty, all required conclusions are success, and the run SHA equals the captured source commit. Any deviation maps to the table above; no single passing job can override it.
That final line is the practical release gate: “passed” is a property of an individual check; “complete enough to release” is a property of the evidence set.
Build Related Skills With Refonte Learning
Refonte Learning’s QA Automation Engineering page identifies the program as “Quality Assurance Automation Engineering / Quality Assurance Engineering,” states a 3-month period and 12–14 hours/week dedication, lists CI/CD pipeline integration among the competencies, and says the program includes hands-on automated test work. It also states a bachelor’s-degree-related requirement and describes certificates offered upon successful completion. These are the program page’s claims, not independently audited outcomes.
The label “QA Automation Engineering” appears elsewhere on the same page, while the main page heading uses broader wording. The page names CI/CD integration but does not establish a dedicated GitHub Actions module. Its stated internship language is “Potential Internship”; broader internship terms, mentorship scope beyond the named educational mentor section, and any outcome guarantee are not established by the cited page.
For an engineer who wants to practice this playbook’s underlying discipline (authoring independent test oracles, separating execution evidence from aggregate status, and integrating automated checks into CI/CD), the program page is a relevant place to review the current curriculum. Keep the release standard unchanged: training material can improve skill, but an ACCEPT decision for a GitHub Actions matrix still requires the repository-specific manifest, versioned evidence, and case-by-case reconciliation described above.
