Skip to content

Implement TASK-030 (Periodic Boundary), Stage 4's ninth and last task - #38

Merged
AdamClemens merged 2 commits into
mainfrom
feat/task-030-periodic-boundary
Aug 28, 2026
Merged

Implement TASK-030 (Periodic Boundary), Stage 4's ninth and last task#38
AdamClemens merged 2 commits into
mainfrom
feat/task-030-periodic-boundary

Conversation

@AdamClemens

Copy link
Copy Markdown
Owner

Summary

  • Adds StructuredCartesianMesh.wrapped_neighbour_cell (mesh geometry, not a third BoundaryCondition shape, per this task's own recorded Design decision) and threads a new periodic_pairs mapping into FirstOrderUpwindAdvection/CentralDifferenceDiffusion alongside boundary_conditions — no interface change, no new ADR (mirrors diffusion_coefficient's own TASK-024 precedent).
  • The round-trip invariant (Stage 4's own Intent for this task) is checked as convergence under mesh refinement, not exact equality at one resolution — a genuine numerical finding, verified before writing the assertion: first-order upwind's own O(dx) numerical diffusion smooths any field over the distance it travels regardless of whether the wrap is correct, so "matches exactly" is the wrong claim even for a correct wrap. A real wrap's own round-trip error drops ~62% over a 4x mesh refinement; a mirrored/clamped wrap (a throwaway mutation, built and run specifically to check this) drops only ~16% and stays several times larger throughout.
  • Builds Stage 4's own golden demo, Passive Scalar Transport — the first pyflow run that steps a real simulation forward live, one timestep per rendered frame, via a new SimulationConfig section and bootstrap.py's _add_passive_scalar_transport wired through RenderWindow.run(on_frame=...). The demo's own centroid-displacement tolerance was likewise measured from a real run (~4% agreement with the closed-form prediction), not guessed.
  • Full Blast Radius documentation sweep: docs/planning/roadmap.md (TASK-030's own entry, Stage 4's closing status table), docs/architecture/{sequences,icds,engine}.md, adr/ADR-003, docs/implementation/golden-demos.md, and every touched CLAUDE.md — including correcting two now-stale claims found mid-sweep (src/pyflow/engine/CLAUDE.md had said a periodic face raises UnconfiguredBoundaryFaceError, which TASK-030 makes untrue) and one honestly-flagged still-open gap (docs/planning/backlog.md: periodic boundaries now exist, but total-quantity conservation under a periodic wrap specifically is still unchecked).

Test plan

  • Strict TDD throughout: wrapped_neighbour_cell's own tests, periodic_boundary.feature's three scenarios, and the golden demo's own scenario all written and confirmed red before the corresponding production code.
  • Mutation testing: wrong wrap (mirrored to owner), wrong periodic distance (un-doubled), and a frozen-simulation-loop mutation each confirmed to fail the scenario meant to catch them, then reverted via targeted edits.
  • make ci green locally: 603 tests, 53 Gherkin scenarios (all bound, make check-scenarios), 99% coverage, all doc-consistency checks (check-references/check-manifest/check-inventory/check-dependency-tree/check-docs/check-docs-index/check-graph/check-status) passing.
  • Verified visually, not only by the regression test: the demo rendered offscreen at increasing frame counts shows the blob translating downstream and, by one full domain width of travel, wrapping around the periodic boundary.
  • Real CI run on this PR — Stage 4 Completion Criterion 9 is left honestly pending in the roadmap's own status table until this run completes; will update that row once it does.

🤖 Generated with Claude Code

AdamClemens and others added 2 commits August 28, 2026 10:27
Adds StructuredCartesianMesh.wrapped_neighbour_cell (mesh geometry, not
a third BoundaryCondition shape) and threads a periodic_pairs mapping
into FirstOrderUpwindAdvection/CentralDifferenceDiffusion alongside
boundary_conditions. The round-trip invariant is checked as convergence
under mesh refinement rather than exact equality at one resolution -- a
real wrap's own error drops ~62% over a 4x refinement, a mirrored/
clamped mutation only ~16% -- since first-order upwind's own numerical
diffusion makes "matches exactly" the wrong claim even for a correct
wrap, verified numerically before writing the assertion.

Also builds Stage 4's own golden demo, Passive Scalar Transport: a new
SimulationConfig section, and bootstrap.py's first wiring of a real
simulation.step() call into RenderWindow.run(on_frame=...) via
_add_passive_scalar_transport. The demo's centroid-displacement
tolerance was likewise measured from a real run (~4% agreement), not
guessed, and confirmed to fail under a frozen-state mutation.

This closes Stage 4: nine of ten Completion Criteria met locally
(make ci green, 603 tests, 53 Gherkin scenarios, all doc-consistency
checks passing); Criterion 9 (a real CI run) is left honestly pending
in the roadmap's own status table until this PR's own run completes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR #38, run 33159480722: ci (ubuntu-latest) and ci (windows-latest) both
green, checked directly via gh pr checks --watch rather than inferred
from the PR merging. All ten of Stage 4's Completion Criteria are now
genuinely met, not just locally green -- matching Stage 3's own
precedent for how this row gets its "Met" verdict.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@AdamClemens
AdamClemens merged commit 0ec33ab into main Aug 28, 2026
2 checks passed
@AdamClemens
AdamClemens deleted the feat/task-030-periodic-boundary branch August 28, 2026 09:52
AdamClemens added a commit that referenced this pull request Aug 28, 2026
… timeframe claim

README.md's Project Status and Current Phase sections still said PyFlow
"has completed Stage 3... and is about to begin Stage 4" and pointed a
reader at Stage 2's Field Display demo as "the most recent" -- stale
since Stage 4 closed (PR #38), caught while auditing the CLI help text
for the same kind of staleness. Updated both sections to reflect Stage 4
being complete and Stage 5 not yet started, and repointed the "try the
most recent demonstration" command at the Passive Scalar Transport demo.

Added a rule in docs/practices.md: README's Project Status/Current Phase
sections must be updated in the same change a stage opens or closes,
same standing as the existing Quick Start rule, and stale docs found
during unrelated work should be fixed on the spot rather than only
flagged.

Also corrects an inaccurate claim made in this same fix's own prior
commit (src/pyflow/CLAUDE.md): the CLI help text was described as
having gone stale "long after" Stage 4 landed, when in fact Stage 4
landed within about a day and the closing PR merged under an hour
before that claim was written. Reworded to state the actual timeline.
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