Skip to content

DOCS: Rewrite tutorials around the examples/ controllers (one per example, single-sourced) #408

Description

@coretl

Rewrite the tutorials as a single pass once the fastcs.demo example controllers exist, sourcing all tutorial code directly from those living modules. Implements #388 §6.

Decisions (settled with Tom, 2026-07-22)

  1. Single source of truth = fastcs.demo. Tutorials literalinclude the finished example modules (consolidated into src/fastcs/demo/, mirroring ophyd-async); CI (tox -e docs) keeps them green so docs can't drift.

  2. Four tutorials — a hello-world → complicated-device ladder (five example modules; the old "reusable io= object" rung is gone, because io= objects were replaced by getter/setter callables):

    # Tutorial Teaches Backend Module(s)
    1 hello world pure-soft @attr decorator none hello_world.py (Example 1 — hello-world: pure-soft @attr decorator device #398)
    2 getter/setter getter/setter callables in __init__; closes with "for a real family, go declarative →" temperature temperature_attr.py (Example 2 — attr getter/setter via __init__ (temperature backend) #404)
    3 declarative annotated SCPIParam + filler (static metadata) plus composition — sub-controllers/vector + @scan + @command on the full temp controller temperature temperature_scpi.py + scpi.py (Example 4 — SCPI device: annotated attributes + per-attribute filler data #405), drawing on controllers.py (Example — composition & methods (temperature controller) #390)
    4 introspectable bare hints filled from a runtime REST parameter tree Eiger REST eiger.py (Example 5 — cut-down Eiger: introspectable controller + REST sim #391)
  3. Finished-example walkthrough pedagogy (not the old 15-diff "Code N" build). Retire docs/snippets/static01–15.py and docs/snippets/dynamic.py.

  4. One umbrella docs pass, after the examples land (see Blocked by:).

Scope

  • Four tutorial pages replacing the current static-drivers / dynamic-drivers split; update tutorials.md nav; keep installation.md.
  • All code blocks come from the fastcs.demo modules via literalinclude with region markers (:start-after: / :end-before:). Add the markers to each module as part of writing its tutorial here.
  • State the declarative (class-body) / procedural (instance-scope) rule up front, mirroring ophyd-async's declarative-vs-procedural page.
  • Teach the post-refactor API only: getter/setter callables and @attr (no io= objects, no AttributeIORef, no DataType, no hand-rolled pydantic filler).
  • Framing to reinforce: the io= tutorial is replaced by a recommendation in tut 2 to use declarative for families; tut 3's SCPI is not introspectable (static SCPIParam; SCPIController/SCPIParam in the demo layer, not core); tut 4's backend switch is the lesson.

Key files

docs/tutorials/*, docs/tutorials.md, docs/snippets/* (removed), docs/explanations/, src/fastcs/demo/* (+ its README), docs/conf.py.

Acceptance

uv run --locked tox -e docs green (real CI — docs env doesn't run in the nightly sandbox); every tutorial renders code pulled live from fastcs.demo; no docs/snippets/static*.py remain.

Labels / process

documentation. Deliberately NOT api-convergence — human pedagogy pass, can't verify in the nightly sandbox, depends on the examples; the autonomous nightly job ignores it.

ADR: #388 §6 (0013 declarative/procedural rule)
Parent: #388
Blocked by: #398, #404, #390, #405, #391

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions