Skip to content

docs: make five example blocks show what they claim - #877

Merged
ocots merged 2 commits into
mainfrom
docs/example-fixes
Aug 23, 2026
Merged

docs: make five example blocks show what they claim#877
ocots merged 2 commits into
mainfrom
docs/example-fixes

Conversation

@ocots

@ocots ocots commented Aug 23, 2026

Copy link
Copy Markdown
Member

Why

The first CI build confirmed what a local build had suggested: five pages render, publish, and
are wrong. None of them fails the build — that is the point. Every fix here was checked by
running the code in the docs/ environment, not by reading it, and two of them turned out
differently from what the review predicted.

The five

1. solve/choosing-a-method.md published an UndefVarError. No ocp was defined anywhere
on the page, and both demonstrations wrap their call in try/catch, so the missing binding was
swallowed and printed as the result:

…so this raises AmbiguousDescription rather than silently picking one:
UndefVarError(:ocp, 0x000000000000b0e3, Main)

and again eighty lines down under "confirmed live".

The page now has a running example — a double integrator, dynamics written coordinatewise so
both :adnlp and :exa accept it. It is a visible @example, not the hidden @setup the
review first proposed: a hidden binding keeps the page from being copy-pasted, which moves the
UndefVarError from the built page to the reader's REPL instead of removing it.

2. flows/overview.md's "no integrator loaded" demonstration could not fail. make.jl loads
OrdinaryDiffEq for the whole site, and a Julia extension stays armed for the session, so the
try block succeeded and the page rendered a fully constructed OptimalControlFlow where it
promised an ExtensionError.

No page in this build can demonstrate it, so the block becomes an inert transcript, captured in a
session loading OptimalControl and NLPModelsIpopt and nothing else — plus a note explaining
why it is inert, so it is not turned back into an @example later. The claim itself holds:
Flow(ocp, law) throws CTBase.Exceptions.ExtensionError at construction time, with
Hint Run: using OrdinaryDiffEqTsit5.

3. results/plot.md contradicted the migration page. It said a flow call "only accepts
variable/unsafe (and augment, for costate augmentation)". augment does not exist:
CTFlows.jl/src/Flows/calling.jl:92 declares variable, unsafe, variable_costate. The
migration page says so twice (:81, :243), and augment= is on the banned-spelling list in
§8.2.

4. flows/accessors.md carried a hidden import. Eight lines of import CTFlows.Systems: with
# hide on every one — needed before #868 re-exported all seven accessors
(src/imports/ctflows.jl:20-27, with a testset). The page was quietly working around a re-export
it should have been demonstrating. Removed; the built page now returns 0.5 from
hamiltonian(f) with no import at all.

5. migration.md spelled one type two ways, on the same page. :51 wrote
CTLie.LiftedHamiltonianFunction, :139 wrote OptimalControl.LiftedHamiltonianFunction. The
four geometry/ pages and the test suite (test/suite/reexport/test_ctlie.jl:96-108) use the
second form, and the same table two rows down states the rule — write against OptimalControl.
The transcript at :196 keeps CTLie. because that is verbatim what src/deprecated.jl:63
prints.

What re-reading the outputs found

With the page executing for the first time, the scheme table turned out to be wrong on four
rows
, not one. Sweeping all ten schemes against both modelers, each cell obtained by actually
solving:

:adnlp :exa
:trapeze, :midpoint, :euler, :euler_implicit
:euler_explicit, :euler_forward, :euler_backward
:gauss_legendre_2, :gauss_legendre_3
:variable

Two surprises. The aliases are rejected under :exa where their canonical form is accepted
:euler_forward fails where :euler succeeds — though under :adnlp the two name one scheme;
the table presented them as interchangeable. And :variable is rejected everywhere: it
dispatches to CTDirect.VariableStepODE (CTDirect.jl/src/DOCP_data.jl:338-340) whose
implementation is not compiled in — CTDirect.jl/src/CTDirect.jl:63 has the include commented
out — so a solve raises UndefVarError(:VariableStepODE, …, CTDirect).

:variable stays in the table, marked unavailable on both sides, because
describe(:collocation) runs ten lines above on the same page and still advertises it. Removing
the row would leave two adjacent blocks contradicting each other. It comes out when CTDirect is
fixed.

Upstream, not fixed here

  • CTDirect:variable advertised by the registry, not compiled in, UndefVarError.
    The most serious of the three: it reaches anyone who follows the docs.
  • CTParser — an unknown scheme is thrown as a bare String
    (onepass.jl:941, :1035, :1106). typeof(e) === String, outside the seven typed
    exceptions, and a catch cannot discriminate on it.
  • CTParseronepass.jl:1483 calls the deprecated ExaCore(). This page is the first in
    the site to run :exa live (solve/gpu.md is Draft = true, solve/options.md's :exa
    blocks are inert), so without intervention the published page would carry a deprecation warning
    and the build machine's package path/home/runner/.julia/packages/ExaModels/… in CI. It
    is silenced in the block visibly, with a comment naming the cause; hiding it behind
    # hide would have been the same mistake as fix 4 above. The scaffolding comes out when
    CTParser is fixed.

Not done here

The site uses println(e) 30 times and the Handbook's canonical exception form
(VITEPRESS-DOC.md:241-260@repl + try/catch # hide +
showerror(IOContext(stdout, :color => false), e) # hide) zero times, where CTBase applies it
24/24, CTSolvers 13/13 and CTModels 10/10. That is the same theme as this PR but thirty more
blocks, so it goes in its own change.

Verification

julia --project=docs docs/make.jl locally: 786 log lines, 12 errors, 186 warnings, 166
unresolved @ref, zero failing @example block
, exit 0 — identical to the baseline from #875.
The 166 are the generated API reference and are untouched here. Both corrected outputs were read
in the built HTML, not only counted in the log.

🤖 Generated with Claude Code

ocots and others added 2 commits August 23, 2026 19:19
The first CI build confirmed what a local build had suggested: several pages
render, publish, and are wrong, without failing the build. Each fix below was
checked by running the code in the docs environment, not by reading it.

flows/overview.md — the "no integrator loaded" demonstration could not fail.
`docs/make.jl` loads OrdinaryDiffEq for the whole site and a Julia extension
stays armed for the session, so the `try` block succeeded and the page rendered
a fully constructed OptimalControlFlow where it promised an ExtensionError. No
page in this build can demonstrate it, so the block becomes an inert transcript
captured in a session that loads OptimalControl and NLPModelsIpopt and nothing
else, plus a note explaining why it is inert so it is not turned back into an
`@example` later. The claim itself holds: `Flow(ocp, law)` throws
`CTBase.Exceptions.ExtensionError` at construction time, naming the `using` to
add.

results/plot.md — the page said a flow call "only accepts variable/unsafe (and
augment, for costate augmentation)". `augment` does not exist;
CTFlows.jl/src/Flows/calling.jl:92 declares variable, unsafe, variable_costate.
The migration page says so twice, and `augment=` is on the banned-spelling list
in the cahier des charges §8.2.

flows/accessors.md — eight lines of `import CTFlows.Systems:` with `# hide` on
every one, needed before #868 re-exported all seven accessors. The page was
quietly working around a re-export it should have been demonstrating. Removed;
the built page now returns 0.5 from `hamiltonian(f)` with no import at all.

migration.md — `LiftedHamiltonianFunction` was spelled two ways eighty-eight
lines apart on the same page. Line 51 now matches line 139, the four geometry
pages, and the test suite. The transcript further down keeps `CTLie.` because
that is verbatim what src/deprecated.jl prints.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The page defined no `ocp` anywhere, and both demonstrations wrap their call in
try/catch, so the missing binding was swallowed and published as the result.
The rendered page read "…so this raises AmbiguousDescription rather than
silently picking one:" followed by UndefVarError(:ocp, …), and again eighty
lines down under "confirmed live".

Give the page a running example. It is a visible `@example`, not a hidden
`@setup`: a hidden binding would keep the page from being copy-pasted, which
moves the UndefVarError from the built page to the reader's REPL rather than
removing it. The dynamics are written coordinatewise so both the `:adnlp` and
the `:exa` modeler accept the problem.

With the page executing, both outputs could be read for the first time, and the
scheme table turned out to be wrong on four rows rather than one. Sweeping all
ten schemes against both modelers, each cell obtained by actually solving:

  - `:exa` accepts only :trapeze, :midpoint, :euler and :euler_implicit.
    The aliases are rejected where their canonical form is accepted —
    :euler_forward fails where :euler succeeds, :euler_backward where
    :euler_implicit succeeds — though under :adnlp the two name one scheme.
    The table presented them as interchangeable.
  - `:variable` is rejected under both modelers. It dispatches to
    CTDirect.VariableStepODE, whose implementation is not compiled in
    (CTDirect.jl/src/CTDirect.jl:63 has the include commented out), so a solve
    raises UndefVarError rather than any typed error.

The table becomes a scheme × modeler matrix. `:variable` stays in it, marked
unavailable on both sides, because `describe(:collocation)` runs ten lines above
on the same page and still advertises it — removing the row would leave two
adjacent blocks contradicting each other.

The Gauss-Legendre demonstration silences ExaModels' `ExaCore()` deprecation
warning, visibly and with a comment. This page is the first in the site to run
the `:exa` modeler live — solve/gpu.md is Draft = true and solve/options.md's
:exa blocks are inert — so without it the published page would carry a warning
and the build machine's package path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant