How to build these docs
=======================

The documentation is a Sphinx project written in reStructuredText and rendered with
the Book theme. Sources are in ``docs/``; the generated site goes to
``docs/_build/html/`` and is not committed.

Install
-------

The ``docs`` extra installs Sphinx and the Book theme into the active virtual
environment:

.. code:: powershell

   .\.venv\Scripts\Activate.ps1
   python -m pip install -e ".[docs]"

Build and view
--------------

.. code:: powershell

   python -m sphinx -b html -W -E docs docs/_build/html
   start docs/_build/html/index.html

.. list-table::
   :header-rows: 1

   * - Option
     - Effect
   * - ``-b html``
     - Build the HTML site.
   * - ``-W``
     - Treat warnings as errors, so a broken link, a missing toctree entry or a bad
       heading reference fails the build instead of shipping.
   * - ``-E``
     - Ignore the cached environment and re-read every file. Use it to pick up the
       version and the "last updated" time, which are computed when ``conf.py`` runs.

For a quicker edit loop, drop ``-E`` and ``-W`` and rebuild; Sphinx then rebuilds only
changed pages. Run the full strict command before committing.

Where the pieces live
---------------------

.. list-table::
   :header-rows: 1

   * - File
     - Purpose
   * - ``docs/conf.py``
     - Sphinx settings: the ``sphinx_book_theme`` theme, the browser title, the date
       format, and the version, which is read from ``pyproject.toml`` so it is bumped in
       one place.
   * - ``docs/index.rst``
     - The landing page, with the version and build time, and the top-level
       ``toctree``.
   * - ``docs/<folder>/index.rst``
     - The page that lists a folder's documents in its own ``toctree``
       (``database/``, ``appendix/``).
   * - ``docs/_build/``
     - Generated output; listed in ``.gitignore`` and excluded in ``conf.py``.

The sources sit directly in ``docs/`` rather than in a ``docs/source/`` folder,
because the build output is already kept apart in ``docs/_build/``.

Version and last updated
------------------------

- The **version** shown in the browser title and on the landing page comes from the
  ``version`` line in ``pyproject.toml``.
- **Last updated** appears in every page footer and on the landing page. It is the
  time of the build, not of the last edit to each page, because the project is not
  required to be a Git repository. Per-page edit dates would need a Git-aware
  extension such as ``sphinx-last-updated-by-git``.

Publishing the docs to GitHub Pages
-----------------------------------

The built site is published from a separate repository,
https://github.com/samkhalilian/samkhalilian.github.io, which GitHub Pages serves from
the root of its ``main`` branch at ``https://samkhalilian.dev/`` (the custom domain
comes from the ``CNAME`` file). That repository contains **only** the contents of
``docs/_build/html``, plus two Pages files that are not part of the Sphinx output:

- ``CNAME``: the custom domain. Deleting it breaks ``samkhalilian.dev``.
- ``.nojekyll``: lets GitHub Pages serve the ``_static`` and ``_sources`` folders.

Publishing mirrors ``docs/_build/html`` into a clone of that repository, keeping those
two files and ``.git``:

.. code:: powershell

   Remove-Item -Recurse -Force docs\_build
   python -m sphinx -b html -W -E docs docs/_build/html

   git clone https://github.com/samkhalilian/samkhalilian.github.io.git $env:TEMP\pages
   robocopy docs\_build\html $env:TEMP\pages /MIR /XD .git .doctrees /XF CNAME .nojekyll
   git -C $env:TEMP\pages add -A
   git -C $env:TEMP\pages status
   git -C $env:TEMP\pages commit -m "Publish trade-engine docs"
   git -C $env:TEMP\pages push

Notes:

- **Start from a clean build.** Sphinx does not delete pages that no longer exist, so
  removing ``docs/_build`` first stops renamed or deleted pages from being published.
- **``robocopy /MIR`` deletes anything in the target that is not in the source**, apart
  from what is excluded (``.git``, ``CNAME``, ``.nojekyll``). Run it only against the
  temporary clone, and read ``git status`` before committing.
- **Robocopy exit codes 0 to 7 mean success** (for example 1 means files were copied);
  8 or higher is a failure.
- **Copy ``html``, not all of ``_build``.** ``.doctrees`` is Sphinx's build cache and
  is excluded.
- **The previous site is kept on a branch.** Before this repository was changed to hold
  only these docs, its earlier contents (a separate blog) were saved on the
  ``backup-before-docs-replace`` branch, and they also remain in the Git history of
  ``main``. To restore them, check out that branch or revert the publishing commit.
- **Anything else published to this repository replaces these docs.** If the blog is
  built and copied into ``samkhalilian.github.io`` again, run the commands above
  afterwards.
- **The published site is public**, even though both repositories are private. This
  includes the ``_sources`` folder with the reStructuredText sources. Review the docs
  before publishing.

Naming conventions
------------------

- **reStructuredText file names use snake_case**, for example ``multi_asset.rst`` and
  ``build_docs.rst``, not ``multi-asset.rst``. The name in a ``toctree`` or a
  ``:doc:`` reference is the same name without the extension. Folder names are single
  lowercase words where possible (``database``, ``appendix``).
- **Repository names use kebab-case**, for example ``trade-engine``, not
  ``trade_engine`` (see :doc:`/appendix/repo_setup`).

Writing pages
-------------

- Put a page in the folder that matches its subject: storage and schemas in
  ``docs/database/``, calculations and process pages in ``docs/``, project and
  tooling notes in ``docs/appendix/``.
- Add every new page to a ``toctree``. A page that is in no ``toctree`` triggers a
  warning, which fails the strict build.
- Link pages with ``:doc:`/folder/page``` and sections with ``:ref:`` rather than
  file paths, so Sphinx checks the links.
- Write formulas with the ``math`` directive or the ``:math:`` role; they are
  rendered by MathJax. Use ``code:: text`` blocks for architecture sketches.
- Use **Implemented** and **Required** as defined in :doc:`/SPEC`, and label planned
  designs as planned.
- When code changes behaviour, update the page that describes it in the same
  commit.

Converting Markdown drafts
--------------------------

The first drafts were Markdown. They were converted once with pandoc through the
``pypandoc_binary`` package, which bundles pandoc so nothing else needs installing.
It is not in the ``docs`` extra because it was only needed for that one-off
conversion:

.. code:: python

   import pypandoc
   rst = pypandoc.convert_file(
       "page.md", "rst", format="gfm+tex_math_dollars", extra_args=["--list-tables"]
   )

``--list-tables`` produces ``list-table`` directives instead of grid tables that
break when text changes, and ``tex_math_dollars`` turns ``$...$`` into ``:math:``
roles. Links between documents must then be rewritten from ``page.md`` to ``:doc:``
references by hand or with a small script.

Troubleshooting
---------------

.. list-table::
   :header-rows: 1

   * - Symptom
     - Cause and fix
   * - ``Could not import extension`` or ``sphinx_book_theme`` not found
     - The ``docs`` extra is not installed in the active environment; run the install
       command above.
   * - ``document isn't included in any toctree``
     - Add the page to a ``toctree``.
   * - ``toctree contains reference to nonexisting document``
     - A name in a ``toctree`` does not match a file; check the path and that it has no
       ``.rst`` extension.
   * - ``Unknown target name``
     - A section reference such as ``Some heading`` followed by ``_`` does not match the
       heading text exactly, or the heading is in another file. Use ``:doc:`` or ``:ref:``
       for another page.
   * - The version or the build time looks stale
     - Rebuild with ``-E``.
   * - ``Title underline too short``
     - The line of ``=``, ``-`` or ``~`` under a heading must be at least as long as
       the heading.
