@@ -123,11 +123,20 @@ are rendered under :doc:`tool_reference/index`.
123123 * - **Sphinx (Docs) **
124124 - ``score_build `` (``src/sphinx_wrapper.py ``),
125125 ``html_merge_tool `` (``src/sphinx_html_merge.py ``),
126- ``sphinx_module_ext `` / ``bazel_sphinx_needs ``
126+ ``sphinx_module_ext ``,
127+ ``trlc `` Sphinx extension (``@trlc ``)
127128 - ``sphinx_module ``, ``dependable_element ``
128- - Two-phase documentation build: phase 1 emits ``needs.json `` for
129- sphinx-needs cross-referencing, phase 2 builds HTML and merges
130- dependency modules into one site.
129+ - Two-phase documentation build: **phase 1 ** (``<name>_needs `` target)
130+ runs Sphinx with ``--builder needs `` to emit ``needs.json `` containing
131+ any native ``sphinx-needs `` (``.. need:: ``) directives found in the
132+ sources. **Phase 2 ** (``<name> `` target) runs Sphinx with
133+ ``--builder html ``, resolving ``trlc `` ``.. requirement:definition:: ``
134+ cross-references within the relocated source tree and consuming
135+ ``needs.json `` files of all ``deps `` via ``needs_external_needs_json ``
136+ for cross-module ``sphinx-needs `` links.
137+ ``src/sphinx_html_merge.py `` then merges dependency HTML directories
138+ into the final output site.
139+ See :ref: `two-phase-sphinx-build ` for details.
131140 * - **Lobster Bazel **
132141 - ``//lobster_bazel:lobster_linker `` (``parse_source_files.py ``)
133142 - ``rules_score_impl `` (tool-qualification chain)
@@ -169,3 +178,86 @@ feed that pipeline:
169178* **FMEA ** (``failuremodes.trlc `` / ``controlmeasures.trlc ``) → ``lobster-trlc ``;
170179 **FTA ** (``fta.puml ``) → ``safety_analysis_tools `` → ``root_causes.lobster ``.
171180* **Unit tests ** (gtest) → ``gtest_report `` → ``<unit>.lobster ``.
181+
182+ .. _two-phase-sphinx-build :
183+
184+ Two-phase Sphinx build
185+ ----------------------
186+
187+ Every ``sphinx_module `` call expands into **two ** Bazel targets that run
188+ sequentially:
189+
190+ .. code-block :: text
191+
192+ <name>_needs (phase 1 — needs builder)
193+ <name> (phase 2 — HTML builder)
194+
195+ Phase 1 — ``<name>_needs ``
196+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
197+
198+ Sphinx is invoked with ``--builder needs `` against the **static docs/ source
199+ tree ** (only ``srcs `` files — the checked-in ``.rst ``/``.md `` files plus the
200+ generated ``trlc_rst `` outputs that are listed as label targets in ``srcs ``).
201+ Generated/external files from ``renamed_srcs `` and ``docs_library_deps `` are
202+ **not ** included; their toctree entries produce ``toc.not_readable `` warnings
203+ that are suppressed in ``conf.template.py `` (see below for why this is safe).
204+
205+ The needs builder scans every document for ``.. need:: `` directives
206+ (``sphinx-needs `` native format) and writes them to a ``needs.json `` file.
207+
208+ The ``toc.not_readable `` suppression in ``conf.template.py `` is safe for the
209+ HTML phase because that phase relocates every file into a staging directory, so
210+ it never encounters an unresolvable toctree entry.
211+
212+ The resulting ``needs.json `` (empty for modules whose requirements are authored
213+ in TRLC rather than native ``sphinx-needs `` format) is wrapped in a
214+ ``SphinxNeedsInfo `` provider and propagated transitively so that every
215+ downstream module can consume it.
216+
217+ Phase 2 — ``<name> ``
218+ ~~~~~~~~~~~~~~~~~~~~
219+
220+ Sphinx is invoked with ``--builder html `` against a **relocated copy ** of all
221+ source files (``srcs ``, ``renamed_srcs ``, ``docs_library_deps ``) symlinked into
222+ a unified staging directory under ``bazel-bin/ ``.
223+
224+ This is also where ``.. requirement:definition:: `` directives (from the ``trlc ``
225+ Sphinx extension) are processed and cross-references resolved. The raw
226+ requirement records come from ``.trlc `` source files compiled by the
227+ ``trlc_rst `` Bazel rule into ``.rst `` files that contain the directives. The
228+ chain is:
229+
230+ .. code-block :: text
231+
232+ *.trlc
233+ └─ trlc_rst (Bazel rule, @trlc)
234+ └─ requirements_rst.rst (.. requirement:definition:: <ID> ...)
235+ └─ Sphinx HTML builder (resolves {requirement:downstream-ref})
236+
237+ Before the HTML build starts, ``sphinx_module_ext.py `` reads the aggregated
238+ ``needs_external_needs.json ``
239+ (written by the Bazel rule from all incoming ``SphinxNeedsInfo `` providers) and
240+ populates the ``needs_external_needs `` Sphinx configuration key. This tells
241+ ``sphinx-needs `` where to find the ``needs.json `` of each dependency and what
242+ base URL to use for generated hyperlinks, so a ``{requirement:downstream-ref} ``
243+ role in a spec file can link directly to the requirement definition page in the
244+ dependency's HTML.
245+
246+ After the HTML build, ``src/sphinx_html_merge.py `` copies each dependency's
247+ output directory into ``<name>/html/<dep-name>/ `` so the final site is
248+ self-contained.
249+
250+ .. code-block :: text
251+
252+ deps[*].needs.json ──► needs_external_needs.json
253+ │
254+ sources (all relocated) ───────┤
255+ ▼
256+ Sphinx HTML builder
257+ │
258+ <name>/_html/ ──► sphinx_html_merge
259+ │
260+ <name>/html/
261+ ├── index.html
262+ ├── dep1/ ← merged
263+ └── dep2/ ← merged
0 commit comments