feat(docs-only): make the docs-only verdict reachable from any workflow - #48
Conversation
A `workflow_call` output is reachable only from jobs in the SAME FILE as the call. thumos's `kernel` job lives in `ci.yml` while its gate call lives in `gate-attestation.yml`, so hybrid-gate's `docs_only` output cannot reach the job that needs it, and thumos#775 is blocked on that alone. `docs-only.yml` is that verdict as a standalone reusable, so any workflow can hang a seconds-long preflight `needs:` off it. hybrid-gate.yml now CALLS it rather than keeping its own copy, and that is the part worth insisting on. This verdict decides whether a full build runs, so a second implementation that drifts permissive would report success having built nothing — and two copies drift silently, because any given repo exercises only one of them. thumos declined to re-implement it locally for exactly this reason: one shared implementation or none. The step is moved byte-identically rather than retyped — extracted from hybrid-gate.yml programmatically — so every WHY it carries about three-dot vs two-dot ranges, empty `github.base_ref` on push events, and case-glob `*` spanning `/` moves with it intact. `docs-only` is added to the `needs:` of both consumers, not merely referenced. `needs.<job>` is undefined for a job you do not depend on and evaluates EMPTY rather than erroring; here that happens to fail safe — empty != 'true', so the full build always runs — but it would have disabled the docs-only exemption fleet-wide with nothing going red. `tests/docs-only.sh` drives the classification against nine changesets, including both conservative branches: an empty diff and a repo that opted out must each produce an explicit `false`, never an absent output that a consumer reads as empty. Refs thumos#775.
Splitting this out because the half that repoints hybrid-gate at the new reusable rests on an assumption I have not established: whether `uses: ./.github/workflows/docs-only.yml` inside a reusable that is itself called from ANOTHER repository resolves against this repo or the caller's. This repo has no nested-reusable precedent to read the answer off, and getting it wrong takes out the gate on every repo that bumps its pin. Adding docs-only.yml is risk-free and unblocks thumos#775 today. The de-duplication follows immediately in its own PR, where it can pin the merged SHA — matching how callers already pin hybrid-gate — and where CI proves the nesting works instead of a merge discovering it. Two implementations existing for one PR's width is a cost worth paying to avoid guessing on a required context. It does not stay that way.
|
Scoped this down while it was in flight, and the reason is worth recording. The original commit also repointed Two things make splitting clearly right rather than merely cautious:
So this PR is now purely additive: The de-duplication follows immediately. Two implementations existing for one PR's width is a cost |
…ing it (#49) refactor(hybrid-gate): consume the docs-only reusable instead of copying it #48 added `docs-only.yml` so a caller's job in a different workflow file could reach the verdict. It left hybrid-gate with its own copy, deliberately and for one PR's width. This removes the copy. The duplication is the thing that mattered. This verdict decides whether a full build runs, so a second implementation that drifts permissive reports success having built nothing — and two copies drift silently, because any given repo exercises only one of them. thumos#775 declined to re-implement it locally for exactly that reason, and the same reasoning applies inside this repo. Pinned by SHA rather than `./` or `@main`. A relative `uses:` inside a reusable that is itself called from another repository is ambiguous about which repo it resolves against, this repo had no nested-reusable precedent to settle it, and guessing wrong takes out the gate on every repo that bumps its pin. A pinned absolute reference is unambiguous in both positions and matches how callers already pin this file. That question is why this is a separate PR: CI here proves the nesting works, where a merge would only have discovered it. `docs-only` is added to the `needs:` of both consumers, not merely referenced. `needs.<job>` is undefined for a job you do not depend on and evaluates EMPTY rather than erroring; here that fails safe — empty != 'true', so the full build always runs — but it would have disabled the docs-only exemption fleet-wide with nothing going red. No caller change is required: the `workflow_call` output keeps its name, its description, and its conservative contract that any value other than the literal `'true'` means not-docs-only. Refs thumos#775.
Unblocks thumos#775.
Finding
A
workflow_calloutput is reachable only from jobs in the same file as the call. thumos'skerneljob lives inci.ymlwhile its gate call lives ingate-attestation.yml, sohybrid-gate.yml'sdocs_onlyoutput cannot reach the job that needs it. thumos#775 is blocked onthat and nothing else.
@t0-thumosraised it and was explicit about the one thing that must not happen:What changes
docs-only.yml— the verdict as a standalone reusable. Any workflow can now hang aseconds-long preflight
needs:off it.hybrid-gate.ymlcalls it instead of keeping its own copy. That is the load-bearing half. Asecond implementation of this verdict would decide whether a full build runs, so a copy that drifts
permissive reports success having built nothing — and two copies drift silently, because any given
repo exercises only one of them.
The step is moved byte-identically, extracted programmatically rather than retyped, so every WHY
it carries travels with it intact: three-dot vs two-dot ranges against a moving base, empty
github.base_refon push events, and case-glob*spanning/so*.mdalready covers nestedpaths.
The subtle part
docs-onlyis added to theneeds:of both consumers, not merely referenced.needs.<job>isundefined for a job you do not depend on, and the expression evaluates empty rather than
erroring.
Here that happens to fail safe — empty
!= 'true', sofull-gate-buildalways runs — but it wouldhave disabled the docs-only exemption fleet-wide with nothing going red. A bug whose only symptom is
"the optimisation stopped working" is one nobody reports.
Verification
tests/docs-only.shdrives the classification against nine changesets:Both conservative branches are tested deliberately. An empty diff must not be guessed as docs-only,
and a repo that opted out must produce an explicit
falserather than an absent output a consumerreads as empty — a caller wires this dependency unconditionally, so "skipped" is not available as an
answer.
shellcheck -s bash tests/docs-only.shexits 0. This is the second such harness in the repo, aftertests/dependabot-auto-merge.sh— which caught two real bugs in its own fix before either reached arunner, and is why this one was written before pushing rather than after.
Adoption
No caller change is required by this PR. A workflow that wants the verdict adds:
Note the
!= 'true'rather than== 'false': any value other than the literal string isnot-docs-only, which is the conservative direction and what the output's own description specifies.
Refs thumos#775.