fix(rtd-sphinx): probe docs/sphinx, add a docs_dir input, and fail on a missing conf.py#14
Merged
Merged
Conversation
…sing conf.py The reusable probed conf.py at docs/, docs/source/ and docs/src/ only, and `exit 0`d when it found none. Measured across scitex-ai on 2026-07-22 (74 repos, every conf.py path in every default branch via the git-trees API): 66 repos keep conf.py at docs/sphinx/conf.py, 1 at docs/sphinx/source/conf.py, 8 ship none, and ZERO use any of the three probed paths. 15 repos already call the reusable, so in 15 of 15 the gate matched nothing and exited 0 -- green while building no documentation at all, and indistinguishable from a real build. Three changes: * docs/sphinx/conf.py joins the probe list. * docs_dir becomes an INPUT (default docs/sphinx). Zero-input reusables are the documented root cause of the rtd-sphinx variant sprawl; a repo with an unusual layout now overrides the input instead of forking the workflow. * A missing conf.py is a HARD FAILURE by default, with `required: false` as the explicit opt-out for repos that genuinely ship no docs. The skip path is annotated ::warning:: and states that nothing was built, so it can never be read as a successful build. The failure names every path searched and prints a remediation hint that is pasteable as-is. Tests execute the real discovery shell sliced out of the real workflow file against real temp trees -- no stubs, no network. Mutation-proven: all 10 mutations (drop either candidate path, revert to exit 0, flip the required default, silence the opt-out, drop the searched-paths listing, drop the remediation hint, move the docs_dir default, remove the input, drop the "NO DOCUMENTATION WAS BUILT" prose) turn the suite red; restoring turns it green. An 11th test was added after the first harness run showed that dropping docs/sphinx/conf.py from CANDIDATES left the suite GREEN -- the org-layout test had passed docs_dir explicitly, masking the fallback.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The defect
The org reusable probed for
conf.pyatdocs/,docs/source/anddocs/src/only, and on a miss did:No repo in this org uses any of those three paths. So the gate matched nothing, exited 0, and reported the same green as a successful build. It is the "skipped counted as clean" failure at fleet scale, and because the skip is indistinguishable from a pass it self-conceals — nobody had reason to look.
scitex-agent-container already diagnosed this and refused to adopt the reusable because of it. From its own
rtd-sphinx-build-on-ubuntu-latest.yml:This PR teaches it that path.
Measurement
Every
conf.pyin every default branch, enumerated via the git-trees API (not guessed paths), on 2026-07-22:docs/sphinx/conf.pydocs/sphinx/source/conf.pyconf.pyat allCross-checked with a second, independent method (direct contents-API probes). Controls in the same batch: positive
scitex-stats/README.md→ 200; negativescitex-stats/docs/sphinx/conf_NO_SUCH_FILE_ZZZ.py→ 404; second negativescitex-stats/docs/source/conf.py(a probed path) → 404. The probe discriminates.The caller count needed its own control. A first pass grepping for the reusable's path anywhere in a workflow file returned 16 — and scored scitex-agent-container as a caller, which is impossible, since the only thing it contains is the refusal comment quoted above. That negative control voided the count. Re-run matching only real
uses:lines: 15 callers, agent-containeruses=0 mentions=1, scitex-statsuses=1. Both controls pass.A prior sweep put this figure at 40. That is superseded: its artifacts contain no
uses:references at all (0 rows carryuses:orscitex-ai/.github), so it cannot have been counting reusable-callers; 60 repos have a workflow file namedrtd-sphinx*, and rows are recorded per branch (821 instances across main+develop vs 457 files on default branches, 54 repos appearing on both). Mention-matching plus branch double-counting, not calls.Blast radius — say this out loud
15 repos are green-no-op today. After this merges they run a real
sphinx-build. 51 more repos have docs atdocs/sphinx/and would join on adoption.Adopting repos will see REAL failures where they previously saw green. That is the point of this PR, not a regression. A red that appears after this merge is a documentation build that was already broken and was being hidden by
exit 0. Please do not read the new reds as "this PR broke our CI" — it removed the thing that was concealing them.One measured detail makes that exact rather than a caveat: all 15 current callers have
conf.pyatdocs/sphinx/. So none of them goes red for a missing conf.py — all 15 flip straight from green-no-op to a genuine build, and any red they show is a real doc-build failure that was invisible until now. The 8 repos with no docs at all are not callers; they would needrequired: falseif they ever adopt.The change
docs/sphinx/conf.pyadded to the probe list.docs_diris now an input (defaultdocs/sphinx, the org convention — so the 66 repos on it need nowith:block). The caller's directory is probed first; the legacy layouts remain as fallbacks so no existing repo breaks. Zero-input reusables are the documented root cause of the rtd-sphinx variant sprawl, so this is added as a real input rather than one more hardcoded path.conf.pyis a hard failure by default.required: falseis the explicit, auditable opt-out for repos that genuinely ship no docs — and it is annotated::warning::and statesNO DOCUMENTATION WAS BUILT, so an opted-out run can never be misread as a successful build. The failure names every path searched and prints a remediation block that is pasteable as printed:A gate that cannot fail is not a gate.
Tests
tests/test_rtd_sphinx_probe.py— 25 new tests, 38 in the suite, run by the existingself-test.yml.These execute the real discovery shell, sliced out of the real workflow file, against real temp trees. No stubs, no network, no
gh; the slice stops before the uv/sphinx install so nothing needs installing. A text-only test would assert that the right string is present, which is not the same as asserting the gate behaves.Mutation table — all 10 red, restore green
docs/sphinx/conf.pyfrom CANDIDATEStest_org_layout_is_found_without_docs_dir_pointing_at_it,…_via_fallback_succeeds$DOCS_DIR/conf.py(input ignored)custom_docs_dirtestsexit 0test_missing_conf_py_fails_by_defaultrequireddefault to falsetest_required_defaults_to_true::warning::)test_opt_out_is_annotatedtest_failure_names_every_path_it_searched×4test_failure_hint_is_executable_as_printeddocs_dirdefault off the conventiontest_docs_dir_defaults_to_the_org_conventiondocs_dirinput entirely…_defaults_to…,test_docs_dir_input_is_declaredNO DOCUMENTATION WAS BUILTprosetest_opt_out_states_that_nothing_was_builtM1 was GREEN on the first run — and that is the most important line here
The first harness run reported M1 green: deleting
docs/sphinx/conf.pyfrom the candidate list — the entire point of this PR — changed nothing, and the suite still passed.The cause: the org-layout test passed
docs_dir="docs/sphinx"explicitly, so$DOCS_DIR/conf.pymatched first and masked the hardcoded fallback. The test could not fail. It was verifying the input while believing it was verifying the path.That is precisely the defect class this PR exists to fix, reproduced inside the fix for it — a check that reports success without exercising the thing it claims to check. It was caught only because every property was mutation-tested rather than assumed.
The repair is a case that points
docs_dirat a directory that does not exist, so a hit can only come from the fallback list. M1 has been red ever since.Based on
main(notdevelop) — org reusables resolve from the default branch.