Repository navigation
Documentation: issues to settle in the other packages before the final read and the stable release #968
Description
Context
The page-by-page review of the documentation is merged (#953, 45 / 45 pages). Many pages point to issues of the other packages, either as a note ("see CTFlows#441"), or as a probe in docs/probes/ that checks the current behaviour and fails once the fix is released. Before a final read of the documentation, and the release of a new stable version, these issues must be settled, and the pages updated.
For each item: when the fix is released, bump the compat if needed, update the page and the probe (the probe fails on purpose, as a reminder), and tick the box.
Other packages: open issues
CTFlows
- With saveat, the point call returns the state at the last saved time, not at tf CTFlows.jl#441: with
saveat, the point call returns the state at the last saved time, not attf(wrong result, no error). Pages: Flows overview, Constrained arcs, Plot. - Flow(ocp, law; constraint=:label, …) uses the raw constraint function, ignoring its bound and its side CTFlows.jl#440:
constraint=:labeluses the raw constraint function and ignores its bound and its side. Page: Constrained arcs. - Point call of a concatenated Hamiltonian flow: a flat vector [x; p], where a single flow returns (x, p) CTFlows.jl#439: the point call of a concatenated Hamiltonian flow returns a flat
[x; p]. Page: Multi-phase flows (the code readszf[1:2]). - Flow accessors: MethodError or IncorrectArgument depending on the flow, and gradients that only take (t, x, p, v) CTFlows.jl#438: errors of the accessors, and gradients that only take
(t, x, p, v). Page: Accessors. - variable_costate=true on a trajectory call: raw MethodError, while the old augment=true gets a clear error CTFlows.jl#437:
variable_costate=trueon a trajectory call: rawMethodError. Page: From an OCP. - Flow(ocp, law; method=:gpu): obscure MethodErrors at call time (Mooncake not loaded, or CPU arrays) CTFlows.jl#436:
method=:gpuraises obscureMethodErrors. Page: Flows overview. Closed: once released, quote the new errors and update the section "CPU and GPU" (it says the error does not name the cause yet). - The Solution of a flow keeps only the integrator steps (5 points), so its plot is a polyline CTFlows.jl#435: the
Solutionof a flow keeps only 5 points. Page: Plot. - Default output grid: adaptive grid of 250 points when the solver returns fewer CTFlows.jl#446: default output grid, an adaptive grid of 250 points when the solver returns fewer (so that a flow
Solutionis not polygonal by default). If adopted, the wording ongrid=n/AdaptiveGrid(n)in the Plot and Flows overview pages changes (opt-out withgrid=nothing). Pages: Plot, Flows overview.
CTFlows#434 is closed (control-toolbox/CTFlows.jl#442), and control-toolbox/CTFlows.jl#435 too (control-toolbox/CTFlows.jl#444, which replaces the output-grid rule of #442). Once released: (1) dense=false can be dropped from the plots (pages Plot, Flows overview, and the examples; probe plot_flow_saveat.jl); (2) the Plot page (and Flows overview) should say what to do when an integrated trajectory looks polygonal: the default grid is the solver steps, so pass grid=n or grid=AdaptiveGrid(n) (curvature-based, denser where the curves bend) at the call, e.g. f((t0, tf), x0, p0; grid=200). A grid cannot be combined with saveat or with a list of times (IncorrectArgument). Check the wording against the released API. Same check for the closed issues control-toolbox/CTBase.jl#570 (OpenLoop, pages Simulation and Migration), control-toolbox/CTModels.jl#435 (import_ocp_solution, page Save & load), control-toolbox/CTSolvers.jl#234 and control-toolbox/CTBase.jl#565 (GPU errors, probe installation_gpu_errors.jl), control-toolbox/CTSolvers.jl#230 (probe installation_integrators.jl).
CTDirect
- Box multipliers are not divided by the time step, and their sign is the opposite of the path multipliers CTDirect.jl#639: box multipliers are not divided by the time step, and their sign is the opposite of the path multipliers. Page: Solution object. Probe
solution_duals.jl. - Costate time stamps: costate(sol)(t_i) approximates p(t_i + h/2), or p(t_{i+1}) with Gauss–Legendre CTDirect.jl#640: time stamps of the costate. Same page and probe.
- Dual variable of the path constraints CTDirect.jl#405: dual variables of the path constraints, zeros with
:exa. Same page and probe. -
:examodeler with an explicittime_grid: crash with the defaultgrid_size, silently uniform otherwise CTDirect.jl#638::exawith an explicittime_grid. Page: Choosing a method.
CTParser
- Align with CTBase 0.29 / CTModels 0.18 / ExaModels 0.12 CTParser.jl#326 (PR): alignment with ExaModels 0.12, errors as
CTExceptions. Pages that quote errors of@defneed a re-read. - The "move the term to the constrained side" hint always quotes
x₂(0) - v == 0, whatever the constraint CTParser.jl#352, add aqua #353, CompatHelper: bump compat for JLD2 to 0.5 for package docs, (drop existing compat) #354: messages of@def. Page: Abstract syntax. -
:exarejects the scheme aliases that:adnlpaccepts (:euler_forward,:euler_explicit,:euler_backward) CTParser.jl#355::exaand the scheme aliases. Page: Choosing a method. - Make @def hygienic: the generated code should contain the modules, not their names CTParser.jl#356: make
@defhygienic (modules instead of names in the generated code).
CTLie
- Make the @Lie expansion hygienic: put CTLie and CTBase in the generated code, not their names CTLie.jl#40: make
@Liehygienic. Page: The@Liemacro (section "using OptimalControlis needed"). - Lift on a HamiltonianVectorField: error message names ad instead of Lift CTLie.jl#41: the error of
Lifton aHamiltonianVectorFieldnamesad. Page: Lift.
CTBase
- plot(sol; xlabel=…): title, xlabel and ylabel are ignored without a warning CTBase.jl#569:
title,xlabelandylabelare ignored without a warning inplot. Page: Plot.
OptimalControl
-
initandinitial_guesstogether: clear error in explicit mode, "unknown option :init" in descriptive mode #964:initandinitial_guesstogether. Page: Initial guess. - Decide which CTModels initial-guess helpers OptimalControl re-exports #965: which initial-guess helpers of CTModels are re-exported.
- Stop exporting the module name CTLie once @Lie is hygienic #966: stop exporting the module name
CTLie, after CTLie#40. - Remove the re-exports of CTModels and ExaModels once @def is hygienic #967: remove the re-exports of
CTModelsandExaModels(and reviewCTBase,CTFlows), after CTParser#356. - [Bug] Reverse over forward AD issues with ADNLP #481: constant component of the dynamics with
:adnlp. Page: Abstract syntax. Probeabstract_syntax_constants_ad.jl. - Documentation: GPU for the indirect method (flows and shooting) #976: documentation of the GPU for the indirect method (flows and shooting). The direct method has a page; the indirect one has only a short section in the Flows overview.
To think about later
- The Geometry pages: the section has 6 pages for 4 functions. The review suggested 3 pages (overview and lift, brackets with
ad, Poisson,@Lieand∂ₜ, and AD backend). They were kept as they are in docs: page-by-page review of the documentation #953. Decide the structure, once the macros are hygienic (the page on@Liechanges).
Then
- Update the pages and the probes for each released fix:
julia --project=docs docs/probes/run.jlis the checklist, since a probe for a known bug fails when the bug is fixed. - Final read of the documentation (the review notes and the per-page log are kept by the maintainers).
- Release of the new stable version, and switch back the links of "Chat with an AI" to
stable/(they point todev/meanwhile).
Activity
ocots commentedon Oct 9, 2026
cc @jbcaillau
ocots commentedon Oct 11, 2026
How each fix is validated: docs examples, probes, tests
A fix is only "done" once it is acted in the documentation. Three places can validate it, and each one has a different job.
1. A documentation example with a hidden
@assert(default choice). It runs at every docs build ("run documentation" label), against the released packages, on the path a user follows. It acts the fix for the reader (what used to fail, what works now, with the value checked) and it fails the build if the fix regresses. When an issue is settled, replace the one-line note on the page by a short worked example, with@asserts on the values (rtolof the order of the integrator tolerance, see CTFlows#441/#442). Examples already in place: #481 (the constant dynamics, solved with:adnlpand:exa), the single-flow vs concatenated objectives (CTFlows#441), theLifterror (CTLie#41), the@Liehygiene trap (CTLie#40).2. A probe in
docs/probes/only for what the build cannot execute: a package that must not be loaded, another environment, a fresh session, the absence of output, external URLs. A probe for a known bug checks the current behaviour and fails once the fix is released, as a reminder (not run in CI).3. A test in
test/suite/of OptimalControl only when the behaviour belongs to OptimalControl or to the boundary between packages. The behaviour of CTFlows, CTDirect or CTBase is tested in those packages (for instance CTFlows#442/#444 bring about 4000 tests): duplicating it here would tie our CI to their internals and break on their releases.@def× ADNLPModels ×solve, and no single package owns it. Add a small regression test intest/suite/problems/, with0 * u(t)/ constant component,:adnlpand:exa.import OptimalControl+OptimalControl.@Lieworks (replaces the trap section)test/suite/reexport/test_ctlie.jl,@Lieevaluated in a module that only hasimport OptimalControl; and theCTLiename is no longer exported.import OptimalControl+OptimalControl.@defworkstest_ctparser.jl; and the removed re-exports intest_ctmodels.jl/test_examodels.jl.@def; show the new messages in@replCTException, if we want to pin the contract)grid=n/AdaptiveGrid(n)withoutdense=false; Constrained arcs: point call withsaveatequals the plain flowplot_flow_saveat.jl(turns into a reminder)zfis a pair, notzf[1:2])installation_gpu_errors.jlfor #436solution_duals.jl:exawith an explicittime_gridsolverouting test (doestime_gridreach:exa?) if OptimalControl forwards itinit+initial_guessbehaviour assertedtest/suite/solve/,reexport/)xlabel/title/ylabelparagraph, asserted (its hidden assert on the old behaviour fails on purpose)Rule of thumb: example first (it is the proof for the reader), test only if OptimalControl owns the contract or the bug lives between two packages, probe only if the build cannot run it. The tests listed as "yes" can be written now for #481, and together with the fix for #966/#967 and #964/#965.
ocots commentedon Oct 13, 2026
CTFlows #441, #438, #440: what changes in the docs
Each of these three CTFlows issues now has an open PR (not merged yet). Here is what each page needs once they are released.
control-toolbox/CTFlows.jl#441:
saveatand the point call (PR control-toolbox/CTFlows.jl#457, tests only)This is already fixed by CTSolvers 0.6.0 (control-toolbox/CTSolvers.jl#235), which no longer passes
saveatto the point call. No CTFlows release is needed for it.results/plot.md): remove the sentence "its point callf(t0, x0, p0, tf)returns the value at the lastsaveattime beforetf". Thedense=falsecaveat goes away with CompatHelper: bump compat for CTDirect to 0.14, (drop existing compat) #434/CompatHelper: bump compat for CTBase to 0.15, (drop existing compat) #442, as already listed above.control-toolbox/CTFlows.jl#438: accessors (PR control-toolbox/CTFlows.jl#458)
flows/accessors.md), section Gradients:(t, x, p, v)".∇H(x, p),(t, x, p)or(x, p, v); for the pseudo-Hamiltonian ones,(x, p, u), …@assert ∇H(x, p) == ∇H(0.0, x, p, Float64[]).MethodErrorfor now".IncorrectArgumentthat says what the flow holds and which accessor to use. For a state flow, the suggestion isvector_field(flow).showerrorblock as the one forHamiltonianVectorField.control_law(f)also returns the law of a state flow built from a law, e.g.Flow(ocp, OpenLoop(u)).control-toolbox/CTFlows.jl#440:
constraint=:label(PR control-toolbox/CTFlows.jl#459)The Symbol form now builds
g ≥ 0from the bounds stored in the model:g = c - lbfor a lower bound or an equality;g = ub - cfor an upper bound.A two-sided constraint needs its active side,
constraint = :label => :loweror:label => :upper(one side per component for a vector constraint). Without it, the call raisesIncorrectArgument.flows/constrained-arcs.md):x(t) - lb ≥ 0,x(t) ≥ lbandlb - x(t) ≤ 0give the same flow (@assertonp(t₂) = 0).Pairform for a two-sided constraint.migration.md, around line 83): the sentence "TheSymbolform uses the constraint function stored in the problem, without its bound" is no longer true. Say that it is normalised from its bounds, and mention thePairform.#459 is a breaking change. A label declared with an upper bound (
c ≤ ub) changes sign. The release will likely be CTFlows 0.19, soCTFlows = "0.19"must be bumped inProject.tomland indocs/Project.toml.Checklist
IncorrectArgumenton state flows,control_lawon controlled flows (after CTFlows#458 is released).Pairforms ofconstraint(after CTFlows#459 is released, compat 0.19).