Skip to content

finding: retrieving a failed CI job's actual assertion takes a manual log-zip dance — script it #9777

Description

@os-zhuang

Departure-report category ② (可机械化项) from the domain:cli seat (#6024). ⛔ Unassigned,
no domain:* label — this seat does not produce routing.

The measured problem

When a required check goes red, the two obvious tools do not carry the failing assertion:

  • get_check_runoutput.text is empty for these jobs.
  • get_job_logs (even with failed_only, even with a large tail_lines) → returns only the
    post-step service-container dump, because the container teardown output is what sits at the
    end of the log. The test output is thousands of lines earlier.

Measured on PR #9774's Temporal Conformance (live PG + MySQL) failure: both returned nothing
usable, and the seat post carried "the failing assertion could not be retrieved" as a fact for
several hours. It was retrievable the whole time — via the run's log archive:

actions_get method=get_workflow_run_logs_url resource_id={run id}
curl -sSL -o logs.zip "{signed url}"
unzip -q logs.zip -d logs/
# per-step files: logs/{Job name}/{step number}_{step name}.txt

That surfaced the assertion in one grep:

FAIL src/sql-driver-datetime-mysql-storage.test.ts > … > is idempotent — a second sync leaves the schema alone
Error: Test timed out in 5000ms.

Why a script, not a paragraph

The cost is not the knowledge, it is the five-step sequence and its two sharp edges: the signed URL
is short-lived (mint and download in the same minute), and the archive is ~4MB of ANSI-coded text
that has to be de-escaped before it reads. Every PM and dev who hits a red required check pays this
again, and the failure mode when they do not is worse than paying it — it is concluding "the
assertion is unavailable" and then either guessing at the cause or re-running the job, which is how
a real gate defect turns into folklore.

Suggested shape

scripts/pm/fetch-job-logs.mjs {run id} [job name substring] → downloads, extracts, strips ANSI,
prints the failing step's tail (or the whole step with --full). ⭐ The complementary cheap call is
worth naming in the same place: actions_get method=get_workflow_job reports each step's own
conclusion, so which step failed is one call away with no download at all — and that is
exactly the discriminator the "re-run only when no test body ran" rule turns on.

⛔ Shape is a suggestion, not a spec; sizing, ownership and whether this belongs in scripts/pm/
at all are the receiving seat's call.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions