Insert Stage 9 (Solver & Run Integrity), renumber Stages 9-15 to 10-16 - #91
Merged
Merged
Conversation
An end-to-end audit on 2026-09-12 found four defects behind a green `make ci` (1209 tests, 99% coverage, all fifteen structural checks passing). Two of them falsify use cases Stage 4 wrote down for itself: - Solid walls are permeable to advection. `FirstOrderUpwindAdvection` takes a boundary face's transporting velocity from the owner cell rather than the prescribed value, so a sealed box loses 14.27% of a purely advected tracer in 400 steps with diffusion zeroed. - A diverged run reports success. `DivergenceDidNotConvergeError` raised inside the frame callback is swallowed by rendercanvas's own `log_exception`, so `pyflow run` prints "pyflow exited cleanly" and exits 0 after 22 of 40 frames failed. On glfw the same raise kills the reschedule, so a --max-frames run hangs instead. And two more: nothing checks a configured timestep against the stability limit (refining the shipped cavity to 64x64 diverges at step 17, silently), and `BoundaryFaceConfig.velocity` is a validated, documented configuration field no engine code reads -- two docstrings claim it drives the divergence operator, and it reaches no scheme at all. This commit is the stage, not the fixes. Placed before Better Numerics by dependency rather than preference: Stage 10's own Criterion 7 locates Rayleigh-Benard onset between heated walls, which is not meaningful while those walls leak. Fifth divergence of the same shape as the first, third and fourth; seven completion criteria written before the first task, per the standing rule. The renumbering sweep covers 42 occurrences in the roadmap and 15 files outside it, each checked individually rather than substituted blindly. `docs/CHANGELOG-DESIGN.md` is append-only and is deliberately untouched, as are the Was/Is now tables and the prose around each describing what that divergence found. What is renumbered is every live forward pointer. Two things found stale on the way past, both fixed here rather than flagged: the first divergence's "Stage 10 below therefore carries an explicit architectural caution" had been stale through three renumberings, because it omitted the Stage's name and so had nothing for a grep to check against; and `docs/practices.md`'s own "Stage 13 (Three Dimensions)" illustration, which that rule requires to track the live number. One new standing rule, `docs/practices.md`: when a test is found weak, ask why its fixture had to be that shape. The Stage 4 exit audit found the closed-domain advection-conservation scenario vacuous by mutation and correctly replaced it -- but nobody asked why the fixture needed every boundary cell's velocity to be exactly zero. It needed it because of the defect above. The weak test was a symptom sitting next to its own cause. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An end-to-end audit on 2026-09-12 found four defects behind a green
make ci— 1209 tests, 99% coverage, all fifteen structural checks passing. This PR is the stage that owns fixing them, not the fixes.What the audit found
Two of the four falsify use cases Stage 4 wrote down for itself:
FirstOrderUpwindAdvectiontakes a boundary face's transporting velocity from the owner cell, not the prescribed valueDivergenceDidNotConvergeErroris swallowed by rendercanvas'slog_exceptionpyflow exited cleanly, exit 0, after 22 of 40 frames failed. On glfw the raise kills the reschedule, so--max-frameshangsmax|u| = 6.4e+04against a lid speed of 1BoundaryFaceConfig.velocityis validated, documented, and read by no engine codeWhy a new Stage rather than reopening Stage 4
Three placements were considered and all three are recorded in the roadmap rather than smoothed over. Reopening Stage 4 (the Stage 8 precedent) would drag a rendering-loop fix into a stage that predates the render loop by three stages. Folding into Better Numerics would mean drafting criteria against a Goal of improve accuracy without changing architecture — criteria that would not test what the work claims, which is the failure
stage-specification.mdexists to prevent.Placed before Better Numerics by dependency, not preference: Stage 10's own Criterion 7 locates Rayleigh-Bénard onset between a heated lower wall and a cooled upper one. That measurement is not meaningful while those walls leak.
What's here
Was/Is nowtable; Stages 9–15 renumbered to 10–16 across the roadmap's 42 occurrences and 15 files outside it, each checked individually rather than substituted blindly.docs/CHANGELOG-DESIGN.mddeliberately untouched (append-only; it still says "3D at Stage 10" from 2026-08-18), as are theWas/Is nowtables and the prose describing what each divergence found. What is renumbered is every live forward pointer.*Unblock condition:*.Two things found stale on the way past, fixed rather than flagged
docs/practices.md's own "Stage 13 (Three Dimensions)" illustration, which that rule explicitly requires to track the live number.One new standing rule
"When a test is found weak, ask why its fixture had to be that shape." The Stage 4 exit audit found the closed-domain advection-conservation scenario vacuous by mutation, correctly recorded it, and correctly added a periodic scenario to carry the criterion. What nobody asked was why the fixture needed every boundary cell's velocity to be exactly zero — it needed it because of F1. The weak test was a symptom sitting next to its own cause, and the audit that found the weakness stopped one question short.
Verification
make cigreen in full locally. No source behaviour changes in this PR — the four fixes land as TASK-052/053/054 on their own branches.🤖 Generated with Claude Code