You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(ci): count only automation-dispatched runs toward a workflow outage (#10266)
`escalate-workflow-outage.ts` counted every non-success at the head of a
workflow's run history, so a maintainer retrying a publish by hand escalated
as a standing outage. That is what #10171 was: six consecutive
publish-miner.yml failures, every one a hand `gh workflow run` against main
failing ETARGET on a @loopover/contract version that was not published yet.
The next run after contract landed succeeded with no code change.
Filtering on the run's `event` / `triggering_actor` / `head_branch` cannot
work here, and the header records why so it is not tried again. The reconcile
path in mcp-release-please.yml dispatches a bare `gh workflow run "$workflow"`
under a PAT, so its runs land as `workflow_dispatch` / `main` / the PAT owner
-- the identical triple a laptop produces. Verified against live history:
publish-miner run #484, which the reconcile job's own log shows it dispatched,
is indistinguishable on every one of those fields from the six manual #10171
failures, and `GET /actions/runs/:id` exposes no `inputs` key either.
So provenance is stamped at dispatch instead. `run-name:` is rendered into
`display_title`, which the runs API does return -- the same mechanism
visual-capture-fallback.yml already uses to correlate a dispatch to its PR.
The five publish workflows take a `dispatched_by_automation` input and stamp a
marker into their run name; both dispatch sites pass it; the streak counts only
runs carrying it.
Manual runs are excluded rather than merely not resetting the streak: a run
nobody automated is not evidence about the automated path in either direction.
Non-dispatch triggers still count exactly as before, so selfhost.yml -- the
other caller, and push-triggered -- is unchanged.
Runs already in the history carry no stamp and so read as unattributable. The
publish escalation therefore stays quiet until three stamped automated failures
accumulate; under-alerting briefly is the fail-safe direction and beats
re-creating the false alarm this removes.
check-dispatch-provenance-stamped.ts asserts the lockstep, since both sides of
the marker fail silently: a drifted `run-name:` leaves the escalation reading
every automated run as manual, still green and still "wired" while covering
nothing. It also rejects an unconditional marker, which would stamp a human's
dispatch as automated and restore the original false alarm.
Closes#10234
Copy file name to clipboardExpand all lines: .github/workflows/publish-contract.yml
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -23,6 +23,18 @@ on:
23
23
description: "Internal: set by the release automation's dispatch so this run skips re-creating the GitHub release it already made."
24
24
type: boolean
25
25
default: false
26
+
dispatched_by_automation:
27
+
description: "Internal: set by the release automation's dispatch so a hand retry is not counted as an outage. Informational -- it feeds run-name below and nothing else."
28
+
type: boolean
29
+
default: false
30
+
31
+
# PROVENANCE STAMP (#10234). `run-name` is the ONLY dispatch-time signal the runs API gives back (as
32
+
# `display_title`): the reconcile path dispatches bare against main under a PAT, so `event`, `head_branch`
33
+
# and `triggering_actor` are identical to a human's `gh workflow run`, and run objects carry no `inputs`.
34
+
# scripts/escalate-workflow-outage.ts recovers "was this automated?" from the marker below -- see its
35
+
# header for the full story. The marker must stay in lockstep with that script's
36
+
# AUTOMATION_RUN_NAME_MARKER; scripts/check-dispatch-provenance-stamped.ts fails the build if they drift.
Copy file name to clipboardExpand all lines: .github/workflows/publish-engine.yml
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,18 @@ on:
18
18
description: "Internal: set by the release automation's dispatch so this run skips re-creating the GitHub release it already made."
19
19
type: boolean
20
20
default: false
21
+
dispatched_by_automation:
22
+
description: "Internal: set by the release automation's dispatch so a hand retry is not counted as an outage. Informational -- it feeds run-name below and nothing else."
23
+
type: boolean
24
+
default: false
25
+
26
+
# PROVENANCE STAMP (#10234). `run-name` is the ONLY dispatch-time signal the runs API gives back (as
27
+
# `display_title`): the reconcile path dispatches bare against main under a PAT, so `event`, `head_branch`
28
+
# and `triggering_actor` are identical to a human's `gh workflow run`, and run objects carry no `inputs`.
29
+
# scripts/escalate-workflow-outage.ts recovers "was this automated?" from the marker below -- see its
30
+
# header for the full story. The marker must stay in lockstep with that script's
31
+
# AUTOMATION_RUN_NAME_MARKER; scripts/check-dispatch-provenance-stamped.ts fails the build if they drift.
Copy file name to clipboardExpand all lines: .github/workflows/publish-mcp.yml
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -12,6 +12,18 @@ on:
12
12
description: "Internal: set by the release automation's dispatch so this run skips re-creating the GitHub release it already made."
13
13
type: boolean
14
14
default: false
15
+
dispatched_by_automation:
16
+
description: "Internal: set by the release automation's dispatch so a hand retry is not counted as an outage. Informational -- it feeds run-name below and nothing else."
17
+
type: boolean
18
+
default: false
19
+
20
+
# PROVENANCE STAMP (#10234). `run-name` is the ONLY dispatch-time signal the runs API gives back (as
21
+
# `display_title`): the reconcile path dispatches bare against main under a PAT, so `event`, `head_branch`
22
+
# and `triggering_actor` are identical to a human's `gh workflow run`, and run objects carry no `inputs`.
23
+
# scripts/escalate-workflow-outage.ts recovers "was this automated?" from the marker below -- see its
24
+
# header for the full story. The marker must stay in lockstep with that script's
25
+
# AUTOMATION_RUN_NAME_MARKER; scripts/check-dispatch-provenance-stamped.ts fails the build if they drift.
Copy file name to clipboardExpand all lines: .github/workflows/publish-miner.yml
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,18 @@ on:
18
18
description: "Internal: set by the release automation's dispatch so this run skips re-creating the GitHub release it already made."
19
19
type: boolean
20
20
default: false
21
+
dispatched_by_automation:
22
+
description: "Internal: set by the release automation's dispatch so a hand retry is not counted as an outage. Informational -- it feeds run-name below and nothing else."
23
+
type: boolean
24
+
default: false
25
+
26
+
# PROVENANCE STAMP (#10234). `run-name` is the ONLY dispatch-time signal the runs API gives back (as
27
+
# `display_title`): the reconcile path dispatches bare against main under a PAT, so `event`, `head_branch`
28
+
# and `triggering_actor` are identical to a human's `gh workflow run`, and run objects carry no `inputs`.
29
+
# scripts/escalate-workflow-outage.ts recovers "was this automated?" from the marker below -- see its
30
+
# header for the full story. The marker must stay in lockstep with that script's
31
+
# AUTOMATION_RUN_NAME_MARKER; scripts/check-dispatch-provenance-stamped.ts fails the build if they drift.
Copy file name to clipboardExpand all lines: .github/workflows/publish-ui-kit.yml
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,18 @@ on:
18
18
description: "Internal: set by the release automation's dispatch so this run skips re-creating the GitHub release it already made."
19
19
type: boolean
20
20
default: false
21
+
dispatched_by_automation:
22
+
description: "Internal: set by the release automation's dispatch so a hand retry is not counted as an outage. Informational -- it feeds run-name below and nothing else."
23
+
type: boolean
24
+
default: false
25
+
26
+
# PROVENANCE STAMP (#10234). `run-name` is the ONLY dispatch-time signal the runs API gives back (as
27
+
# `display_title`): the reconcile path dispatches bare against main under a PAT, so `event`, `head_branch`
28
+
# and `triggering_actor` are identical to a human's `gh workflow run`, and run objects carry no `inputs`.
29
+
# scripts/escalate-workflow-outage.ts recovers "was this automated?" from the marker below -- see its
30
+
# header for the full story. The marker must stay in lockstep with that script's
31
+
# AUTOMATION_RUN_NAME_MARKER; scripts/check-dispatch-provenance-stamped.ts fails the build if they drift.
"test:ci": "git diff --check && npm run actionlint && npm run lint:composite-actions && npm run db:migrations:check && npm run db:migrations:immutable:check && npm run turbo-inputs:check && npm run workspace-dep-ranges:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run miner:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run build --workspace @loopover/engine && npm run build --workspace @loopover/discovery-index && npm run build:mcp && npm run build:miner && npm run build --workspace @loopover/ui-kit && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:live-gate-parity && npm run test:driver-parity && npm run validate:mcp && npm run test --workspace @loopover/engine && npm run test:workers && npm run test:mcp-pack && npm run test:contract-pack && npm run test:miner-pack && npm run test:engine-pack && npm run test:ui-kit-pack && npm run test:miner-deployment-docs-audit && npm run rees:test && npm run ui:openapi:check && npm run control-plane:contract:check && npm run control-plane:openapi:check && npm run ui:version-audit && npm run docs:drift-check && npm run coverage-boltons:check && npm run import-specifiers:check && npm run ui-derived-types:check && npm run server-manifest:check && npm run dead-source-files:check && npm run dead-exports:check && npm run publishable-deps:check && npm run fixture-clock-races:check && npm run typecheck-coverage:check && npm run test-wiring:check && npm run checkers-wired:check && npm run focus-manifest-fields:check && npm run release-commit-parsing:check && npm run releasable-commit-types:check && npm run regate-sort-key:check && npm run maintainer-associations:check && npm run command-redelivery-guards:check && npm run dispatch-gate-reasons:check && npm run validate:no-hand-written-js && npm run replay-runner-manifest:check && npm run coco-dev-versions:check && npm run branding-drift:check && npm run manifest:drift-check && npm run engine-parity:drift-check && npm run engines-nvmrc:check && npm run release-manifest:sync:check && npm run release-linked-versions:check && npm run command-reference:check && npm run mcp:tool-reference:check && npm run mcp:client-config:check && npm run contract:api-schemas:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build",
153
+
"test:ci": "git diff --check && npm run actionlint && npm run lint:composite-actions && npm run db:migrations:check && npm run db:migrations:immutable:check && npm run turbo-inputs:check && npm run workspace-dep-ranges:check && npm run db:schema-drift:check && npm run selfhost:env-reference:check && npm run miner:env-reference:check && npm run selfhost:validate-observability && npm run cf-typegen:check && npm run build --workspace @loopover/engine && npm run build --workspace @loopover/discovery-index && npm run build:mcp && npm run build:miner && npm run build --workspace @loopover/ui-kit && npm run typecheck && npm run test:coverage && npm run test:engine-parity && npm run test:live-gate-parity && npm run test:driver-parity && npm run validate:mcp && npm run test --workspace @loopover/engine && npm run test:workers && npm run test:mcp-pack && npm run test:contract-pack && npm run test:miner-pack && npm run test:engine-pack && npm run test:ui-kit-pack && npm run test:miner-deployment-docs-audit && npm run rees:test && npm run ui:openapi:check && npm run control-plane:contract:check && npm run control-plane:openapi:check && npm run ui:version-audit && npm run docs:drift-check && npm run coverage-boltons:check && npm run import-specifiers:check && npm run ui-derived-types:check && npm run server-manifest:check && npm run dead-source-files:check && npm run dead-exports:check && npm run publishable-deps:check && npm run fixture-clock-races:check && npm run typecheck-coverage:check && npm run test-wiring:check && npm run checkers-wired:check && npm run focus-manifest-fields:check && npm run release-commit-parsing:check && npm run releasable-commit-types:check && npm run regate-sort-key:check && npm run maintainer-associations:check && npm run command-redelivery-guards:check && npm run dispatch-gate-reasons:check && npm run dispatch-provenance:check && npm run validate:no-hand-written-js && npm run replay-runner-manifest:check && npm run coco-dev-versions:check && npm run branding-drift:check && npm run manifest:drift-check && npm run engine-parity:drift-check && npm run engines-nvmrc:check && npm run release-manifest:sync:check && npm run release-linked-versions:check && npm run command-reference:check && npm run mcp:tool-reference:check && npm run mcp:client-config:check && npm run contract:api-schemas:check && npm run ui:lint && npm run ui:typecheck && npm run ui:test && npm run ui:build",
153
154
"test:release": "npm run test:ci && npm run changelog:check",
0 commit comments