Skip to content
Cockpit0.29.0
A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live

I1520

A step that runs out of time says so itself

Where it stands

devtask.issue
Readiness
complete completion is recorded and every required evidence token is present
Status
DONE
Can start
not now
Milestone
Milestone status
ACTIVE
Wave
0
Waiting on
none
Holds back
none
Behind it in all
0
Evidence
2 of 2
A move writes the repository: it stamps one field of this issue's record and appends one event to the ledger, and a commit will carry both.
The same moves from a terminal

majordomus plan start I1520

majordomus plan verify I1520

majordomus plan done I1520

What it is

Objective
Make a CI step that exceeds its time report a failure naming the bound and the elapsed time, instead of being killed by its job and reported by GitHub as a cancellation that every reader in this repository treats as not-a-failure.
Why
The site job's 'audit the UI in a browser' step has been killed at exactly its job's 50-minute timeout-minutes bound on master at 6a8d47a47 (01:14 to 02:04), at 70685d473 (23:13 to 00:03), and on both runs of the integration branch #310 — three consecutive runs, each to the second, and nothing was ever red. GitHub reports a job killed by its own bound as `cancelled`, and `cancelled` is what the gates, the summaries and three sessions in one night all read as 'not a failure'. I read it that way myself an hour before measuring it.\n\nThe cause was in the instrument. scripts/ci/timed computed the elapsed time after the command returned, so a command that never returned was never measured and no row was ever written to say otherwise. The only thing that could have reported the problem was the thing the problem prevented from running. That is the class: a verdict with no measurement behind it, the same family as english-only-check dying on its own regex and announcing that every file is English, and coverage-differential being declared, planned, named in a job's if: and invoked by no step.
Now
All 13 timeout-minutes in .github/workflows/validate.yml are job-level; no step carries a bound of its own. scripts/ci/timed measures after the fact and cannot report a step it never saw finish. The UI audit is over its job's bound and has been for as long as the run retention window goes back.
Wanted
Every timed step declares a bound smaller than its job's, so a runaway step always loses the race to its own message; the timing row is written even when the bound fires, because that is exactly when it is the only evidence; and a gate holds the relation so a new step cannot be added without one.
Done when
unknown: the record declares no `completion`
Risk
This makes the site job red rather than cancelled, loudly and on every run, until the UI audit finishes inside its bound or somebody raises the bound with a reason. That is the intended effect and it is worth saying plainly: a silent kill is exchanged for a visible failure, not for a fix.

Acceptance

  • A step over its bound exits non-zero with a message naming the bound and the elapsed time
  • The timing row is written when the bound fires, not only when the command returns
  • Every scripts/ci/timed call declares a bound strictly smaller than its job's timeout-minutes
  • A gate refuses a timed step with no bound, and one whose bound reaches its job's
Validation
bash scripts/ci/step-bound-checkbash test/run.sh 349_a_step_reports_its_own_time
Evidence required
a_step_over_its_bound_reports_itno_step_can_be_killed_by_its_job_first
Evidence present
a_step_over_its_bound_reports_itno_step_can_be_killed_by_its_job_first

Scope

Touches
scripts/ci.github/workflows.ai/repo/citest/cases
Not
Making the UI audit faster, or deciding what its bound should be. This converts a silent kill into a named failure; what the right bound is, is a separate and deliberate decision.The sum of a job's step bounds. Several steps can still add up past their job's bound and be killed together; the job bound remains the backstop it always was.
Depends on
none
Priority
p1
Profile
implementation
Parallel safe
true
Owner
unknown: the record declares no `owner`

The work so far

Branches
none
Merged
none
Commits
0
Trunk
master
Sessions
none
Created
2026-09-15
Updated
2026-10-07T13:27:30Z
Started
2026-09-15
Verified
2026-10-07T13:27:27Z
Completed
2026-10-07T13:27:30Z

Synchronisation

Adapter
scripts/github-sync
Repository
unknown: the derived plan's header carries no repository
External issue
unknown: a live GitHub state; this executable makes no network call, so only `scripts/github-sync --check` can answer it
State there
unknown: a live GitHub state; this executable makes no network call, so only `scripts/github-sync --check` can answer it

Findings

Nothing is wrong with these records.