Skip to content

docs: page-by-page review of the documentation - #953

Merged
ocots merged 57 commits into
mainfrom
docs/page-by-page-review
Oct 9, 2026
Merged

ocots merged 57 commits into
mainfrom
docs/page-by-page-review

Conversation

@ocots

@ocots ocots commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

Page-by-page documentation review

A critical re-reading of every hand-written docs page, one at a time: correctness of every claim, prose and progression, links, and executed code. v2.0.4 is the reference: what it explained (derivations, analytic values, figures, summary tables) is kept, and the presentation is improved.

Draft until every page has been through. One commit per page.

Principles

  • Execute as much as possible. Every claim that can run in the build runs, visible or hidden. Analytic values are checked with hidden @asserts, so a wrong value fails the build.
  • Probes for the rest. Claims the build cannot execute (errors when a package is not loaded, other environments, session rules, silent output, external URLs) are checked by the scripts in docs/probes/ (julia --project=docs docs/probes/run.jl). A probe for a known upstream bug checks the current behaviour, so it fails when the fix is released, as a reminder to update the page.
  • Bugs go upstream. Each bug found gets an issue in the package concerned, and a one-line note with the link in the page. No history or maintainer notes in the pages.

Progress (45 / 45)

Section Pages Status
Home, Getting started index, installation, first problem, guided tour ✅
Modelling formulation, abstract syntax, functional API, control-free problems, inspect, with AI ✅
Solve overview, initial guess, choosing a method, options, explicit mode, GPU ✅
Results solution, plot, plot with Makie, save & load ✅
Flows overview, from an OCP, from Hamiltonians, simulation, accessors, multi-phase, constrained arcs, shooting ✅
Geometry overview, lift, Lie derivative and bracket, Poisson bracket, @Lie, AD backend ✅
Examples gallery, energy, time, control-free, control and variable, turnpike, singular control, state constraint, logo ✅
Reference ecosystem, migration ✅

Mechanics

  • During the review, a local draft = true and a @meta Draft = false marker on the page under review made only that page execute. Neither is committed: docs/make.jl has draft = false, as on main.
  • Plan, decisions and per-page log: .reports/ (git-ignored).

Before merging

  • draft = false in docs/make.jl, full build green (every page executes).
  • No @meta Draft marker left.
  • julia --project=docs docs/probes/run.jl passes (11 / 11), after updating the probes and notes of the upstream fixes released in the meantime.
  • Link texts and titles swept (Flows overview, Geometry overview, control-free problems).

🤖 Generated with Claude Code

First page of the page-by-page documentation review.

index.md
- Motivation: one dense paragraph split into four.
- Basic usage: a transition line before the "each step has its own guide" list.
- Mathematical formulation: the Mayer term reworded as a boundary/pointwise cost
  on the initial and final times and states and the optimisation variables, not
  just the final state.
- Testing: one dense paragraph split into three.
- Reproducibility: dropped the `_downloads_toml` helper and three raw-HTML
  `<details>` blocks (one emoji used twice); now a lead paragraph, a two-row
  table for the two project files, and one `::: details` block holding
  versioninfo / Pkg.status / Pkg.status(manifest).

Logo
- `logo.png` -> `logo.svg` (cropped artwork from .extras/logos/logo-gagnant/).
- Home page dark mode: an exact light/dark SVG pair. `docs/make.jl` generates
  `logo-dark.svg` from `logo.svg` (white backdrop -> #1b1b1f, Julia colours
  unchanged), git-ignored; two <img> with a plain display toggle.
- Navbar: single `/logo.svg` recoloured in dark mode by a `.dark` filter (24px,
  the ~10% desaturation is imperceptible; a light/dark <img> pair double-renders
  in the DocumenterVitepress navbar title).

Environment download (fixes a live 404 on the dev site)
- VitePress does not bundle `.toml` referenced from a Markdown link, so the
  Project.toml / Manifest.toml download links have been 404 on `dev` since the
  DocumenterVitepress migration. `docs/make.jl` now copies each into
  `src/public/assets/` (served verbatim) as well as `src/assets/` (Documenter's
  link check). `src/public/` is git-ignored.

Dark-mode figures
- `.dark .vp-doc img[alt=""] { filter: invert(0.894) hue-rotate(180deg) }` in
  style.css: a = 1 - 27/255 lands white on the VitePress dark surface. Catches
  every local `![]` image (DVP drops their alt); exclude one with a `@raw html`
  `<img alt="...">`.

Plan and per-page log: .reports/documentation-review-2026-09.md (git-ignored).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ocots

ocots commented Sep 2, 2026 •

Copy link
Copy Markdown
Member Author

Status: page 1/45 (index.md) validated and committed.

This first commit is larger than the following ones will be — besides the index.md review it also carries three infra fixes found along the way (environment download 404 on dev, logo .png→.svg + dark mode, dark-mode figure filter).

Next: getting-started/installation.md, then the rest of the sidebar in order. One commit per page. The PR stays in draft until the end.

ocots and others added 22 commits October 8, 2026 22:08
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…on; add Makie

- Flows: OrdinaryDiffEqVern9 does not exist (OrdinaryDiffEqVerner does), and a
  non-Tsit5 integrator only works with OrdinaryDiffEqTsit5 still loaded
  (CTSolvers.jl#230). The warning becomes a tip with a verified alg= example.
- Solver table: the :madnlp row no longer contradicts the GPU section.
- Show a real ExtensionError transcript in the current boxed format.
- Plotting: mention Makie; describe the missing-package errors precisely.
- GPU: keep the three packages and CUDA.functional(), drop internal
  extension names and version history (kept on the GPU page).
- Remove the page's Draft = false review marker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The home page already shows the bare code, so this page becomes the annotated
version: the wagon story and figure, a line-by-line reading of the @def block,
how to read the solve output and the plot panels, and a "Check it" section that
compares the numerical solution with the exact one (u = 6 - 12t, J = 6).
Hidden @asserts make the build fail if the solution drifts.

Also: x = (q, v) in the code as in the maths, no "bounded" force, and the
"1-D is a scalar" link now lands on the Control section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…asserts

- Binder badge (dead branch, uncommitted notebook) replaced by downloads: Literate
  writes the notebook and the script to src/public/assets/, linked in raw HTML
  because Documenter rewrites ../assets Markdown links to a 404 path.
- Notebook links: stable/ (404) -> dev/; tutorial link to tutorial-iss.html.
- CTLie in the ecosystem list; Installation link; callback argument v -> var;
  NLP variables up to u_{N-1}; link texts match page titles.
- Goddard: Ipopt and MadNLP reach the same r(tf); grid-continuation prose
  without hard-coded counts; bang-bang gain computed and explained, with an
  altitude-vs-time figure built from time_grid/state.
- GPU: neutral prose, CUDA warnings silenced, prints CUDA.functional().
- PMP introduced once; u_max -> u_feedback; OrdinaryDiffEqTsit5 loaded once.
- Hidden @asserts: J = 6, r(tf), MadNLP vs Ipopt, cascade iterations,
  bang-bang altitude, p0 = (12, 6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- x ∈ ℝⁿ, u ∈ ℝᵐ, v ∈ ℝ^q are defined (m and k were used undefined).
- Name the constraint kinds; mention → max and autonomy.
- New "Notation and conventions" section, the single reference for the
  indirect-method pages: pseudo-Hamiltonian H and maximised Hamiltonian 𝐇
  (PseudoHamiltonian / Hamiltonian), maximum principle, state constraints
  c(x) ≥ 0 with + μ c, minimal time in Mayer form (𝐇(t_f) = 1), and the
  variable costate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed rules

- New "Structure of a definition": declarations first (the variable before the
  time when the bounds use it), the two named forms, and when names are read
  (constants at build time, functions at solve time). This replaces two
  contradictory notes on defining names before or after the block.
- One table for the ASCII alternatives (in, R^2, derivative, integral, <=, =>).
- Labels: dual(sol, ocp, :label) works, a number (1) is stored as :eq1
  (new anchor results-solution-duals on the solution page).
- Constraint kinds named box / general instead of linear / nonlinear; the
  "damped" integrator is now damped (- c(t) v(t)).
- Known upstream problems as one-liners: CTParser#352 (generic hint),
  #353 (single = in the dynamics), #354 (gensyms in trace mode).
- Known issues section removed: the #481 examples all solve with the
  current versions.
- Warnings shown without the local package path; wording fixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The functional API page lays out each @def model beside its functional twin
with .responsive-columns-40-60, a class only defined in custom.css, which the
VitePress theme never loads: the columns were stacked on the live site. The
rule moves to style.css; narrow screens stack the two columns instead of
hiding the second one. custom.css held nothing else that style.css lacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ence

- Problem 7: the velocity bound is a labelled box (v(t) ≤ VMAX, and
  constraint!(pre, :state; rg=2:2, …)) instead of the "+ 0.0" path
  constraint, whose justification was wrong.
- Problem 1 loads Plots before plotting; its @def body is indented.
- Hidden asserts: macro and functional forms reach the same cost (or the
  same λ) on all seven problems; J = 6, t_f = 2, λ ≈ 0.5 where known.
- No typeof output, no test-file path, no "one place on the site" claim;
  "Mayer (boundary) cost", "general" constraints, "optimised".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Title and sidebar: "Control-free problems" (was "No control").
- Drop the implementation details (EmptyControlModel, dispatch on the
  control field's type), shown twice; show is_control_free(ocp) instead.
- The harmonic oscillator is now solved: ω = π/2 is recovered.
- Hidden asserts: λ ≈ 0.5, ω ≈ π/2.
- "Adding a control back" removed: it described two Flow guards, which belong
  to the Flows pages (constrained-arcs already shows the second one).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s vs times

- Autonomy: a path constraint depending on t also makes the problem
  non-autonomous (stated twice, now with an executed example).
- The label (1) is stored as :eq1, with a link to Labels.
- times(ocp) is a struct, times(sol) a vector: say so.
- Evaluation points no longer reuse the model's names q, u, v.
- The final_time / mayer error hints are not helpful yet: CTModels#431.
- "API trap: time is gone" becomes "times, not time", without history;
  the alias note moves to the end; no internal type names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… claim

- The prompt and the four "Try with" buttons pointed to stable/, a 404 until
  the next stable release: now dev/ (no trailing dot in the prompt).
- The AI answers are @example blocks: the build constructs and solves them
  (minimal time tf ≈ 6.5; the rocket reaches the guided tour's Goddard
  altitude), with hidden asserts.
- The "compatible with ExaModels" follow-up is kept as a real exchange, but
  the page now shows that the vector form solves with :exa too.
- No dated model name; the gallery has no rocket, link the guided tour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guided tour no longer offers a Binder badge: its notebook and script are
downloads served with the docs. Nothing else used binder/. CHANGELOG and
BREAKING keep their historical mentions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Solve overview"

- "Reading the display" described :user/:default/:computed tags that the
  box never shows. It now walks through the actual Configuration box (as
  v2.0.4 did): options per strategy, [cpu-dependent] defaults, defaults
  hidden, describe for the full list.
- display=false silences the solver log too: say so.
- "Two ways to steer it": the rule for users (don't mix tokens and typed
  components) instead of the type-based mode detection.
- "When it fails" shows a failed solve (max_iter=0: :max_iter, violation
  1.1) next to a converged one, with hidden asserts.
- H1 "Solve overview" (C8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ct a guess

- The short form `u := 2` is shown (the example did not use it) and the
  table lists every form, including grids.
- v2.0.4 content restored: the labels/time-variable note, and the
  cross-spec rules with the constant → temporal, constant → constant and
  alias cases.
- New: the named-tuple form (state/control/variable), and "Inspect a
  guess" with state/control/variable on build_initial_guess output
  (replaces a typeof printout).
- variable on a solution is a scalar for a 1-D variable.
- The init/initial_guess inconsistency becomes a one-liner
  (OptimalControl#964); the "not yet public API" maintainer note moves to
  OptimalControl#965.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/probes/ holds one script per page or section for claims that an
executed block cannot show: errors when a package is not loaded,
another environment (OrdinaryDiffEqVerner without Tsit5), user-session
rules for @def, the absence of output with display=false, external URLs,
and the #481 regression that justified removing "Known issues".
run.jl runs each in a fresh Julia process with the docs environment.
A probe for a known upstream bug checks the current behaviour, so it fails
once the fix lands (CTBase#565, CTSolvers#230).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y, real errors

- :exa accepts the vector form of the dynamics: the coordinatewise
  requirement is gone from the page; the shared problem is written in
  vector form and solved with :exa.
- "Ambiguity" becomes "Incompatible tokens": the error is "no description
  contains all symbols", with the closest matches.
- v2.0.4 content restored: the "Understanding default values"
  (NotProvided) note, describe for every modeler and solver (in details
  blocks), one-line scheme descriptions, and the official documentation
  links (ExaModels and MadNLP now under madsuite-org).
- :di is the AD backend, :sciml the ODE integrator; the internal registry
  section is dropped; no authoring remarks.
- Known upstream problems as one-liners: CTParser#355 (scheme aliases
  under :exa, the error shown is now the alias one) and CTDirect#638
  (time_grid ignored or crashing under :exa).
- Hidden asserts on methods(); probe solve_completion.jl checks the
  completion examples and describe(:sciml) / describe(:di).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…computed explained

- The routing example uses a quiet modeler option (backend) instead of
  show_time, which flooded the page with timings.
- No placeholder option: say that no two built-in strategies of a method
  share an option name today; route_to is shown executed, including its
  keyword form route_to(madnlp=1000).
- :computed means "depends on the :cpu/:gpu parameter" (MadNLP's
  linear_solver), not "computed from the problem"; the display shows :user
  and :computed options, not defaults. Hidden asserts on option_source.
- No internal type names (BypassValue, RoutedOption).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mport

- discretizer / modeler / solver / sol everywhere (mod shadowed Base.mod,
  sol was a solver and result the solution).
- "using CTDirect: Collocation would also work" removed: an indirect
  dependency cannot be loaded from a user environment.
- The per-component example now solves with the components it builds
  (Gauss–Legendre on 50 steps recovers J = 6, hidden assert) instead of
  building unused ones with show_time=true.
- No mode-detection internals; link texts updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… madsuite links

- "The problem must be coordinatewise" is gone: :exa accepts the vector
  form of the dynamics and of path constraints (verified, same cost as
  :adnlp); the example problem uses it.
- v2.0.4 content restored: the CPU vs GPU defaults (Exa backend, MadNLP
  linear solver) and the "beneficial for" list. The timing block now
  compares :cpu and :gpu at the same grid size on a GPU machine.
- CUDSS warning without version history; the ExaModels name clash is
  still real (#882 closed, clash checked by a probe).
- `parameter`, not `strategy`; modeler/solver names.
- ExaModels and MadNLP moved to madsuite-org: page links and InterLinks
  updated, placeholder inventories replaced by the real ones (225 and 157
  entries).
- Probe solve_gpu.jl: "Missing CUDSS" error and the ExaModels clash.
  common.jl now mirrors make.jl's load path (docs environment first), which
  also fixes CUDA failing to load in the probes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…solutions

- Check the trajectories, the objective and the free final time against the closed
  forms (hidden asserts); one minimum-time problem (t_f = 25/12) for the horizon and
  the duals, with labels that are not "eq_" on inequalities.
- Explain that the direct costate is shifted by half a step, and that the
  multiplier of the initial condition gives p(t0).
- Evaluate the dual accessors at a time instead of printing CoercedTrajectory;
  plot the path multipliers; state the box sign convention and its two
  differences with nonlinear constraints (CTDirect#639), and the zeros under :exa
  (CTDirect#405).
- Restore the v2.0.4 intro, the print and plot of a solution, and the summary
  tables; variable(sol) is a number, a vector or an empty vector.
- Show that a flow returns a Solution, and what it lacks (duals, iterations).
- Drop the CTModels >= 0.18 history, the type-annotation paragraph and
  is_empty_time_grid.
- Probe solution_duals.jl for the claims the build cannot execute.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ocots

ocots commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

Status: pages 1–16 of 45 pushed

Getting started, Modelling and Solve are done (22 commits). Results has started: the Solution object page is committed locally, and will be pushed with the rest of the section.

What changed, across the pages

  • Executed rather than written. Many julia blocks became @example blocks, and analytic values are checked by hidden @asserts: the energy double integrator (u = 6 − 12t, J = 6, p₀ = (12, 6)), the minimum-time problem with a speed limit (t_f = 25/12), the harmonic oscillator, the guided tour, and the 7 macro/functional pairs (identical solutions).
  • Restored from v2.0.4: the wagon figures, the "Understanding default values" note, the describe of every strategy, the scheme table, the official-documentation links, the summary tables of the Solution page, the cross-spec initial-guess cases.
  • Corrected: integrator advice on the installation page, :exa and vector-form dynamics/constraints (they work), the sign and scale of the multipliers, the "Reading the display" section, variable(sol) (a number for a 1-D variable), the state-constraint notation (c(x) ≥ 0 with + μc).
  • New: "Notation and conventions" (Formulation), "Structure" and "Labels" (abstract syntax), a real failing solve, the keyword form of route_to, CPU vs GPU defaults, the half-step shift of the direct costate, dual(sol, ocp, :start) = p(t₀), and the fact that a flow returns a Solution.
  • Infrastructure: binder/ removed (notebook and script downloads instead), ExaModels/MadNLP InterLinks moved to madsuite-org with real inventories, the 40/60 columns CSS restored, docs/probes/ (10 probes, all passing).

Upstream issues filed

Issue What Status
CTBase.jl#565 solve(ocp, :gpu) routing ignored the parameter (MadNLP{CPU}) ✅ fixed (#566), released in v0.30.6
CTSolvers.jl#230 Flow(…; alg=Vern9()) failed without OrdinaryDiffEqTsit5 ✅ fixed (#231), release pending
CTModels.jl#431 accessor hints (final_time, initial_time, mayer, lagrange) ✅ fixed (#432), release pending
CTDirect.jl#638 :exa with an explicit time_grid: crash, or silently uniform open
CTDirect.jl#639 constraint multipliers: scale (quadrature weights) and sign differ between boxes, path and boundary constraints; derivation in the comments open, maths to check first
CTDirect.jl#640 costate time stamps: p(t_i + h/2), or p(t_{i+1}) with Gauss–Legendre open, maths to check first
CTDirect.jl#405 (comment) under :exa, path and boundary duals are zeros, without a warning open
CTParser.jl#352 the "move the term" hint always quotes the same constraint open
CTParser.jl#353 ẋ(t) = … (single =): misleading error open
CTParser.jl#354 trace mode prints internal gensyms open
CTParser.jl#355 :exa rejects the scheme aliases open
OptimalControl.jl#964 init + initial_guess: misleading error in descriptive mode open
OptimalControl.jl#965 which initial-guess helpers to re-export open, to decide

Once the CTSolvers and CTModels releases are out

  • Bump the docs environment.
  • Drop the "keep OrdinaryDiffEqTsit5 loaded" advice and the CTModels#431 notes.
  • Add OrdinaryDiffEqVerner and execute a Flow(…; alg=Vern9()) example.
  • Flip the two probes that check the old behaviour.

Next

Results (Plot, Plot with Makie, Save & load), then Flows, Geometry and the examples, where the remaining correctness items are (state-constraint example, shooting, multi-phase flows).

ocots and others added 4 commits October 9, 2026 13:42
… flow caveats

- Restore the v2.0.4 opening (plot / plot! / plot!(plt, …)) and the argument overview
  table, with anchors for each section.
- Constraints: a speed-limited thrust u + v ≤ 1 (a path constraint, not a box in
  disguise), with its analytic final time checked; say that boxes are drawn as bounds
  only.
- control=:norm on a 2-D control (u = ((16 − 6t)/13, 6/13), J = 8/13 checked), not on
  a scalar.
- title, xlabel and ylabel are set by plot and user values are ignored (CTBase#569):
  drop the ineffective xlabel="s", show the subplot workaround (hidden asserts).
- Flow: start from the exact p(0) = (12, 6); the 5-point grid (CTFlows#435); saveat
  needs dense=false, otherwise the call crashes (CTFlows#434), checked by the new probe
  plot_flow_saveat.jl.
- Real ExtensionError transcript; drop the redundant Styling section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…al path constraint

- The diff block's error line is the bare plot(sol), not Makie.plot(sol) twice (B3).
- The switching time of the minimum-time example is 1 + √2/2, read off the control and
  checked (with t_f = 1 + √2), instead of t_f/2.
- OptimalControl exports RecipesBase's plot, not Plots'; the ambiguity hint also lists
  the modules loaded by the build.
- The constraints example uses the speed-limited thrust of the Plot page instead of
  1 ≤ v + 1 ≤ 1.8.
- Shorten the 3 000-character type in the Makie.plot!(ax, sol) error; a phase portrait
  for the figure built from scratch; the flow starts from the exact p(0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rt checked

- File names: a name that already ends with the extension is used as is (B4; the
  doubling was fixed by CTModels#399), checked with isfile and cleaned up.
- Both formats give back the same solution value for value (grid, state, control,
  costate, status): hidden asserts replace the vague claim that JSON is not exact; the
  choice is about the file (JLD2 compact, JSON readable anywhere, sizes shown).
- The model passed to import_ocp_solution must be the original one; the error with
  another model is obscure (CTModels#435).
- Real ExtensionError transcript; the warm start is solved and checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tory calls, no internals

- H1 "Flows overview" (C8); the PMP recap uses the notation of Formulation (H, 𝐇,
  p⁰ = −1, the control maximises H) and links to it.
- Derive the control law of the example (u = p_v) and execute both calls of the flow:
  the point call reaches the target with p(1) = (12, −6), the trajectory call returns
  a Solution with J = 6 (hidden asserts).
- Drop the maintainer note on why the ExtensionError is not executed, and the paragraph
  on the internal get_full_strategy_registry.
- describe(:sciml) and describe(:di) in collapsible blocks; saveat needs dense=false
  (CTFlows#434).
- method=:gpu: what it selects (integrator, Mooncake AD backend, device arrays), the
  CTFlows GPU page, and the obscure errors without a GPU or Mooncake (CTFlows#436).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ocots and others added 2 commits October 9, 2026 15:44
…, Symbol form caveat

- Restore the first-order example (ẋ = u, x ≥ 0.1, ∫x², Bonnard–Faubourg–Launay–
  Trélat 2003): derivation of u = 0 and μ = 2x on the arc, three arcs with t₁ = 0.9,
  t₂ = 1.6; the flow reaches x(2) = 1/2, and the direct method finds the same arc and
  the same cost (asserts).
- Restore the costate-jump example (Bryson–Denham, l = 1/9, order two): derivation,
  jumps of 18 on p₁ at 1/3 and 2/3, J = 4/(9l) = 4 for both the flow and the direct
  method, overlaid on a plot.
- Function form everywhere (decision C6), with the c([t,]x,u[,v]), u([t,]x,p[,v]),
  μ([t,]x,p[,v]) signatures; the `+ 0.0` trick is gone. The Symbol form is mentioned with
  its limitation: it ignores the bound and the side of the constraint (CTFlows#440,
  derivation and measurements in the issue).
- With saveat, a flow's point call returns the value at the last saved time
  (CTFlows#441): warned on this page, on Plot and on Flows overview.
- Drop the arbitrary t1, t2, p1 demo and the positional-form section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… from the direct solve

- Transversality of the free final time written as in Formulation: for the Mayer cost
  t_f, p(t_f)·f = 1 (the page said H(t_f) = −1); the switching condition is "the
  switching function p₂ vanishes at t₁", not the circular "H_u = 0".
- shoot! uses unsafe=true, as the page recommends.
- The shooting starts from the direct solution: p₀ = dual(sol, ocp, :start), t₁ read
  off the control, t_f = variable(sol); Newton converges to p₀ = (1, 1), t₁ = 1,
  t_f = 2 (asserts), and the indirect and direct final times agree.
- Drop the variable_costate example (p_v ≡ 0 there, since t_f only sets the horizon);
  link the section where the variable costate matters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ocots

ocots commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

Status: Flows section done (28 / 45)

Pages 23–28 are pushed (1df71d69 … 67d581e9). Every page executes, and the analytic values are checked by hidden @asserts.

Page What changed
From Hamiltonians v2.0.4 introduction restored (extremals). One extremal of the double integrator is computed with each of the six constructors, and the results are asserted equal. The claimed "silent mis-dispatch" was wrong: the actual behaviour is a MethodError. For SciML flows, the parameter p is the flow's variable.
Simulation Open and closed loop are checked against the exact solutions. Controls are evaluated on the energy problem: u = 6 − 12t costs 6 and reaches the target; u = 1 costs 1/2 and ends at (−1/2, 1). A table says what each kind of flow returns (Solution, state trajectory, costate, objective); every row is checked.
Accessors Every accessor is evaluated on the extremal at x = (−1, 0), p = (12, 6), e.g. 𝐇 = 18. The availability table was rebuilt from measurements.
Multi-phase B2: the point call of a concatenation returns [x; p], so the code reads zf[1:2]. A vector jump on a Hamiltonian flow acts on the costate, and this is checked. The v2.0.4 L¹ off–bang example is restored, with p₀ and t₁ in closed form.
Constrained arcs Both v2.0.4 examples are restored, in function form: the order-1 constraint (Bonnard–Faubourg–Launay–Trélat; t₁ = 0.9, t₂ = 1.6) and Bryson–Denham (costate jumps of 18, J = 4). Each is compared with the direct solve. The Symbol form constraint=:label is documented with a caveat.
Shooting B8: transversality is p·f = 1 in the Mayer form. unsafe=true is explained on a blow-up example. The guess is taken from the direct solve (dual(sol, ocp, :start), switch read off the control, t_f), and Newton converges to (1, 1, 1, 2).

New upstream issues

Probes

11 / 11 pass. The new probes are plot_flow_saveat.jl (#434, #441) and solution_duals.jl (#639, #640, #405).

Next

  • Geometry (29–34).
  • Examples (35–43), including B1 on the state-constraint example.
  • Ecosystem and Migration.
  • The pre-merge checklist.

ocots and others added 21 commits October 9, 2026 16:09
…dge identity derived and asserted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ump, CTLie#41

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…riable forms, ∂ₜ section

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd checked, singular control derived

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wn, scope requirement → CTLie#40

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd constructed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ution derived, p₀ = (12, 6) and J = 6 asserted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Mayer transversality, (1, 1, 1, 2) asserted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/2 and p₀ = (0, −2) asserted, exact overlay

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, the ω = 0 extremal and why it is not optimal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… introduces after the review

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ks, p₀ = −1, t₁ = 1, t₂ = 3/2, J = 3/8 asserted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bracket sign), non-degeneracy, all-singular extremal stated, asserts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ham regimes restored, analytic values asserted, references

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and Colors named, boundary values asserted, no .extras path

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ted, augment and positional constraint now caught, user-facing tables

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e SolverFailure

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….19.6, CTSolvers 0.5.8, OrdinaryDiffEqVerner)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ocots

ocots commented Oct 9, 2026

Copy link
Copy Markdown
Member Author

Status: review complete (45 / 45), ready for a final read

All 45 pages are reviewed and pushed (HEAD d3cc96dc). The pre-merge checklist in the description is ticked:

  • full build with draft = false: green (15.5 min), every page executes, and the hidden @asserts check the analytic values;
  • no @meta Draft marker left;
  • docs/probes/run.jl: 11 / 11 pass;
  • link texts are the titles of their targets (21 links fixed).

Since the last status

Section What changed
Geometry (29–34) v2.0.4 restored: Poisson properties, {H, G} = H⃗·G, d/dt G = ∂ₜG + {H, G}, summary table. The singular control is derived on an example where H₁₀₁ ≠ 0 (u = sin²θ).
Examples (35–43) Wagon figures, side-by-side formulations and derivations restored; exact values asserted (energy p₀ = (12, 6); time (1, 1, 1, 2); control-free ω = π/2; turnpike J = 3/8; singular-control brackets; logo boundary values). State constraint (B1): function form, (38.4, 9.6, 0.25, 0.75), J = 7.68; Bryson–Denham touch point (J = 2.24) and boundary arc (3a, 1 − 3a, jumps 2/(9a²), J = 4/(9a)).
Reference (44–45) Ecosystem: role of each package. Migration: titled "Migrating from v2.0", shim messages executed, augment=true and positional constraints documented as now caught.

New upstream issues

Notes for review

  • Examples compute the shooting and the objectives with plain flows, and use flows with saveat only for plots. After CTFlows#442 is released, plots can use the output grid at the call, and plot_flow_saveat.jl will fail as a reminder.
  • The objective of a concatenated trajectory is recomputed at the integrator tolerance (relative error about 1e-6), so those asserts use that tolerance.
  • X ⋅ f with a plain function X raises a MethodError, not the replacement message; the migration page says so.
  • Geometry keeps its 6 pages. The review suggested merging them into 3; I did not do it.

@ocots ocots added the run documentation Trigger the Documentation workflow on this PR label Oct 9, 2026
@ocots
ocots marked this pull request as ready for review October 9, 2026 18:02
@ocots
ocots merged commit dea4547 into main Oct 9, 2026
13 checks passed
@ocots
ocots deleted the docs/page-by-page-review branch October 9, 2026 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run documentation Trigger the Documentation workflow on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant