FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
Review issues — fhsim_environment

Findings from code review that await an owner decision or an implementation. Each issue is one file in issues/details/, which holds the evidence, the effect, the possible fix, the test that would prove it and the risk. Resolved issues are kept in issues/resolved/ so that their numbers are never reused. Issues that concern a SimObject are also shown on that model's documentation page. Audit notes that are not issues are in issues/notes.md.

How to work an item

  1. Reproduce the Evidence at the file:line given in the detail file, at HEAD.
  2. For a blocked item, get the owner's answer to "Decision needed" first, then set Status to ready.
  3. Write the proving test, apply the fix, check the Risk paragraph.
  4. git mv the file to issues/resolved/, add a **Resolved:** <commit>, <date> paragraph after the table, delete the matching \xrefitem reviewissue "Review issues" "Review issues" \ref fhsim_environment_issue_<ID> lines from the headers, rerun the script and commit it all together.

New issue: --new <slug> "<title>", or add issues/details/<slug>.md with the metadata table but no ID row; the script assigns the next free number, writes the heading and renames the file to <TAG>-<ID>-<slug>.md.

Legend

  • Class
    • BUG code does something other than its documentation or sibling code says
    • KNOWN-LIMITATION behaviour gap by design or omission, document rather than fix silently
    • ARCHITECTURE structure, dependencies, build layout, dead code and stale artefacts
    • DOCUMENTATION missing or wrong documentation or example
    • TEST test coverage or infrastructure
    • API public name (port, state, parameter, registration string) whose change breaks input files
    • SECURITY credentials and supply chain
  • Severity
    • 3 wrong numbers, a crash or a secret exposure reaches a user
    • 2 a documented interface does not work as documented
    • 1 tidiness, readers and tools only
  • Status
    • blocked needs the owner decision named in the file
    • ready fully specified

Open issues (0)

| ID | Class | Severity | Status | |—|—|—|—|

Resolved issues (106)

  • ENV-0001 (TEST) — No test carries the _NEEDS_GUI suffix the ctest filter excludes. Resolved: 7996618, 2026-09-16. File: resolved/ENV-0001-needs-gui-ctest-filter-matches-nothing.md
  • ENV-0002 (DOCUMENTATION) — Waves.Hs documented default is 4, the code default is 1.0. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0002-waves-hs-documented-default-is-4.md
  • ENV-0003 (BUG) — Visual.WorldRadius documented default is 3000, the effective default is 1000. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0003-visual-worldradius-documented-default-is-3000.md
  • ENV-0004 (DOCUMENTATION) — Visual.Sky documented default Clear is not an accepted value. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0004-visual-sky-documented-default-clear.md
  • ENV-0005 (DOCUMENTATION) — Visual.Vertices documented default is 100, 100, the code default is 100, 130. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0005-visual-vertices-documented-default-is-100.md
  • ENV-0006 (DOCUMENTATION) — Waves.Spectrum documents the value Component; the code accepts Components. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0006-waves-spectrum-documents-the-value-component.md
  • ENV-0007 (DOCUMENTATION) — Waves.Theory is documented with a default but read as a mandatory parameter. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0007-waves-theory-is-documented.md
  • ENV-0008 (DOCUMENTATION) — Waves.OmegaNormalizedMax description says "Lower", and the silent 0.5 floor is undocumented. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0008-waves-omeganormalizedmax-description-says-lower.md
  • ENV-0009 (DOCUMENTATION) — Three VisualFlowPlane range defaults do not match the code. Resolved: b6b6d36, 2026-09-15. File: resolved/ENV-0009-three-visualflowplane-range-defaults.md
  • ENV-0010 (DOCUMENTATION) — CNetCDFField documents NetcdfFile but reads the mandatory NetCDFFileName. Resolved: de2ab83, 2026-09-15. File: resolved/ENV-0010-cnetcdffield-documents-netcdffile-but-reads.md
  • ENV-0011 (BUG) — CNetCDFField unconditionally writes a debug text file at construction. Resolved: 498cbd6, 2026-09-16. File: resolved/ENV-0011-netcdffield-writes-debug-file-unconditionally.md
  • ENV-0012 (DOCUMENTATION) — Current.Vector is read but undocumented. Resolved: 8604406, 2026-09-15. File: resolved/ENV-0012-current-vector-is-read-but-undocumented.md
  • ENV-0013 (ARCHITECTURE) — NETCDFCPP_AVAILABLE is defined unconditionally, so the documented condition and the fallback branch are dead. Resolved: f15bebc, 2026-09-16. File: resolved/ENV-0013-netcdfcpp-available-defined-unconditionally.md
  • ENV-0014 (ARCHITECTURE) — TestDynamicWaves prints the whole parameter status map to stdout. Resolved: 154f0a3, 2026-09-15. File: resolved/ENV-0014-testdynamicwaves-prints-the-whole-parameter-status.md
  • ENV-0015 (DOCUMENTATION) — NetCdfSeafloor.SeabedMaterial is read but undocumented. Resolved: a0f188d, 2026-09-15. File: resolved/ENV-0015-netcdfseafloor-seabedmaterial-is-read-but-undocumented.md
  • ENV-0016 (DOCUMENTATION) — Two OpenWiki claims no longer match the source. Resolved: 4151209, 2026-09-15. File: resolved/ENV-0016-two-openwiki-claims-no-longer-match.md
  • ENV-0017 (KNOWN-LIMITATION) — VisualFlowPlane.ComputeFunction silently falls back on an unrecognised value. Resolved: 50c4576, 2026-09-16. File: resolved/ENV-0017-visualflowplane-computefunction-silent-fallback.md
  • ENV-0018 (DOCUMENTATION) — AGENTS.md prescribes backslash Doxygen tags but the code uses @ exclusively. Resolved: 94f5ed3, 2026-09-23. File: resolved/ENV-0018-doxygen-comment-style-contradicts-code.md
  • ENV-0019 (KNOWN-LIMITATION) — Inline JSON parameters lose the closing bracket of a numeric array. Resolved: cdd4165, 2026-09-23. File: resolved/ENV-0019-inline-json-numeric-arrays-mangled.md
  • ENV-0020 (BUG) — RandomSeed defaults to the wall clock, so a simulation is irreproducible unless the user knows to pin it. Resolved: dd199ff, 2026-09-23. File: resolved/ENV-0020-randomseed-defaults-to-wall-clock.md
  • ENV-0021 (BUG) — visual::FlowPlane sets its colour uniforms on the shared material, so two VisualFlowPlane instances corrupt each other. Resolved: 13034de, 2026-09-23. File: resolved/ENV-0021-flowplane-sets-uniforms-on-shared-material.md
  • ENV-0022 (BUG) — visual::FlowPlane's render-queue override is commented out, and it is unclear whether it is wanted. Resolved: 13034de and 18afaab, 2026-09-23. File: resolved/ENV-0022-flowplane-destructor-leaks-entity-node-mesh.md
  • ENV-0023 (BUG) — visual::ScalarPlane, ScalarVolume and FlowPlane call a dangling SceneManager in Release(), so every visualised run segfaults at shutdown. Resolved: 1507a3f and 5bf8d11, 2026-09-23. File: resolved/ENV-0023-visual-release-uses-dangling-scenemanager.md
  • ENV-0024 (BUG) — visual::ScalarPlane and visual::FlowPlane drop their last MeshPtr after HardwareBufferManager is gone, which Ogre reports as a bug in user code. Resolved: 6f55e02, 2026-09-24. File: resolved/ENV-0024-mesh-handle-dropped-after-hardwarebuffermanager.md
  • ENV-0025 (TEST) — CNetCDFField has no automated test; NetCdfSeafloor had none until 2026-09-24. Resolved: 3d35ffa, 2026-09-24. File: resolved/ENV-0025-no-netcdf-field-test-coverage.md
  • ENV-0026 (TEST) — TestBuoy1, TestParticleField, TestDynamicWaves and TestNetcageWake have no automated test. Resolved: 1c1f97d, 2026-09-24. File: resolved/ENV-0026-four-test-simobjects-untested.md
  • ENV-0027 (ARCHITECTURE) — CNCField is dead code behind a stale commented-out registration. Resolved: 3d35ffa, 2026-09-24. File: resolved/ENV-0027-cncfield-dead-registration.md
  • ENV-0028 (KNOWN-LIMITATION) — Field providers expose no gradient/derivative API, so no analytic sensitivity path exists anywhere in this library. Resolved: 555d19f, 2026-09-24. File: resolved/ENV-0028-no-derivative-api-on-fields.md
  • ENV-0029 (BUG) — A registered wake attenuates GetCurrentVelocity but not GetParticleVelocity. Resolved: 53949b6 (marenv 111571c, 1.0.32), 2026-09-24. File: resolved/ENV-0029-wake-does-not-attenuate-particle-velocity.md
  • ENV-0030 (BUG) — The CNetCDFField reader keeps its NetCDF start and count arrays in function statics, so a second file is read with the first file's sizes. Resolved: 3d35ffa, 2026-09-24. File: resolved/ENV-0030-netcdf-handler-static-arrays.md
  • ENV-0031 (BUG) — netcdf_sinmod::Parser::LoadFile dereferences a null NcFile when the file cannot be opened, so a wrong path segfaults. Resolved: 1bcfbd6, 2026-09-24. File: resolved/ENV-0031-netcdf-parser-missing-file-segfault.md
  • ENV-0032 (BUG) — NetCdfSeafloor and the NetCDF current put NED north on the file's xc axis, which NetCDFParser labels east. Resolved: a9e2f4b, 2026-09-24. File: resolved/ENV-0032-netcdf-seafloor-axis-convention.md
  • ENV-0033 (BUG) — Callers of netcdf_sinmod::Parser never delete the exception object it throws by pointer. Resolved: f3c3c15, 2026-09-24. File: resolved/ENV-0033-netcdf-parser-exception-leak.md
  • ENV-0034 (API) — Net hydrodynamics: adapt EnvironmentProvider, NetCageWakeField and the flow plane to the marenv 2.0 wake API. Resolved: 16484f4 (marenv 2.0.0 ffef6e5), 2026-09-26. File: resolved/ENV-0034-net-hydro-environment-wake-adaptation.md
  • ENV-0035 (API) — Net hydrodynamics: PorousDiscWakeSource SimObject for a placed analytic wake. Resolved: 693cf66 (shared-file edits 2673b81), 2026-09-26. File: resolved/ENV-0035-net-hydro-porous-disc-wake-source.md
  • ENV-0036 (DOCUMENTATION) — Net hydrodynamics: user-level wake documentation in fhsim_environment. Resolved: 936438e (shared-file edits a08a2e0), 2026-09-27. File: resolved/ENV-0036-net-hydro-wake-user-documentation.md
  • ENV-0037 (BUG) — TestNetcageWake validates MaxDeficit and DeficitCutoff at setup. Resolved: 3f1819c, 2026-09-27. File: resolved/ENV-0037-testnetcagewake-parameter-validation.md
  • ENV-0038 (API) — Wakes: WakeSchedule, WakeCastingObject and LumpedWakeCaster for any wake-casting SimObject. Resolved: 25b1a0e, a9fe430, dd764d4, 2026-09-27. File: resolved/ENV-0038-phase-f-lumped-wake-caster.md
  • ENV-0039 (BUG) — Freeze re-arms when the ambient current at the source changes. Resolved: 8667294, 2026-09-28. File: resolved/ENV-0039-freeze-rearms-on-ambient-current.md
  • ENV-0040 (BUG) — LumpedWakeCaster builds its wake from a zeroed current when a current field fails, silently. Resolved: pending, 2026-09-30. File: resolved/ENV-0040-lumped-caster-ignores-current-status.md
  • ENV-0041 (BUG) — Relaxation is skipped when the relative flow is below 1 mm/s or the frontal area is invalid, contrary to the documented rule. Resolved: pending, 2026-09-30. File: resolved/ENV-0041-relaxation-skipped-without-relative-flow.md
  • ENV-0042 (BUG) — WakeSchedule settings accept infinite values (WakeFilterTime, WakePeriod, WakeExpansion, WakeRearmTolerance, ...). Resolved: pending, 2026-09-29. File: resolved/ENV-0042-wake-settings-accept-infinity.md
  • ENV-0043 (ARCHITECTURE) — NetCageWakeField evaluates the whole ambient current at the cage on every Sample, even far outside its bounds. Resolved: pending, 2026-09-29. File: resolved/ENV-0043-netcage-wake-field-current-lookup-per-sample.md
  • ENV-0044 (BUG) — LumpedWakeCaster checks only the frontal area from CurrentLoad, so a NaN rear centre or an infinite force is published. Resolved: pending, 2026-09-29. File: resolved/ENV-0044-caster-accepts-non-finite-current-load.md
  • ENV-0045 (TEST) — Wake caster tests miss a failing current, relaxation across a zero-flow rebuild, non-finite CurrentLoad, WakeBlendTime = 0 ordering and a turning followed axis. Resolved: pending, 2026-09-30. File: resolved/ENV-0045-wake-caster-test-gaps.md
  • ENV-0046 (DOCUMENTATION) — With WakeBlendTime = 0 the wake other casters see depends on the PreOdeFcn order; the user docs do not say so. Resolved: pending, 2026-09-29. File: resolved/ENV-0046-zero-blend-time-order-dependence-undocumented.md
  • ENV-0047 (BUG) — TestWakeBody samples GetWakedFlow without excluding its own lumped field, unlike Disk and Sphere. Resolved: pending, 2026-09-30. File: resolved/ENV-0047-testwakebody-does-not-exclude-own-field.md
  • ENV-0048 (ARCHITECTURE) — The other objects' wakes are re-composed at every RK stage and Jacobian evaluation. Resolved: 051c972, 2026-09-28. File: resolved/ENV-0048-external-wakes-per-step.md
  • ENV-0049 (BUG) — A frozen wake keeps the rebuild's source velocity and drifts away from its structure. Resolved: see Resolution, 2026-09-28. File: resolved/ENV-0049-frozen-wake-drifts-from-its-structure.md
  • ENV-0050 (API) — Wire marenv's round-2 wake and wave APIs into the casters and the wave wrapper. Resolved: see Resolution, 2026-09-28. File: resolved/ENV-0050-marenv-round-2-wiring.md
  • ENV-0051 (KNOWN-LIMITATION) — The seabed contact of a sphere is undamped at rest, so BDF of order 3 to 5 can sustain its oscillation. Resolved: 6bb6cb6, 2026-09-28 (R79). File: resolved/ENV-0051-seabed-contact-undamped-at-rest.md
  • ENV-0052 (API) — Wire marenv's R87 (ambient-normalised lumped M) and R88 (linear superposition) into the casters and the external-wake composition. Resolved: 8a689e0, 2026-09-28. File: resolved/ENV-0052-marenv-r87-r88-wiring.md
  • ENV-0053 (API) — ExternalWakes has no waked current without the waves (R62) and no cutoff tier (R47). Resolved: da01468, 2026-09-28. File: resolved/ENV-0053-external-wakes-current-and-cutoff-api.md
  • ENV-0054 (API) — Wire marenv's R95 (momentum-flux composition of wakes) into the casters and the external-wake composition. Resolved: 0141e99, 2026-09-28. File: resolved/ENV-0054-marenv-r95-wiring.md
  • ENV-0055 (BUG) — WaveComponents::Blend aborts a net + wave simulation in the visualization build at integrator init. Resolved: pending, 2026-09-30 — not a library defect. A clean visualization rebuild of fhsim_environment 4.0.0 (fhsim 3.3.1, marenv 2.0.0, with_visualization=True; 235/235 tests pass) and of fhsim_marine_elements against it runs NetHydroTowedPanel.xml and NetStructure.xml to FhSim ended successfully.. The crash came from the stale/inconsistent local build/Release tree. No code change.. File: resolved/ENV-0055-wave-components-blend-bad-alloc-integrator-init.md
  • ENV-0056 (BUG) — PorousDiscWakeSource reads its seabed-image depth once in FinalSetup, so it depends on the XML order relative to NetCdfSeafloor. Resolved: f5ef5c3, 2026-10-01 (interim fix of SYNTHESIS §0, the root fix is R124: the first PreOdeFcn re-reads SeabedImageDepth and re-sets a fixed axis, logged, when it changed; the Set stays in FinalSetup; test PorousDiscWakeSource.FirstPreOdeFcnTakesTheSeabedInstalledAfterFinalSetup_ENV0056 red before (deficit 0.1256 with the 200 m image against 0.2551 with 12 m), green after). File: resolved/ENV-0056-porous-disc-seabed-image-depth-read-once.md
  • ENV-0057 (BUG) — PorousDiscWakeSource accepts non-finite parameters (an infinite SourceVelocity or Area passes setup). Resolved: 7564438, 2026-10-01 (every parameter is checked finite in the constructor: Position, Area/Diameter, MomentumDeficit/ThrustCoefficient, FlowDirection, SourceVelocity, WakeExpansion, WakeXStartFactor; test PorousDiscWakeSource.RejectsAmbiguousOrMissingStrengthAndSize extended with 8 non-finite cases, 16 expectations red before, green after). File: resolved/ENV-0057-porous-disc-accepts-non-finite-parameters.md
  • ENV-0058 (BUG) — TestNetcageWake and NetCageWakeField accept WakeAngleDeg = 0, which gives an infinite full-deficit wake. Resolved: 20a1de9, 2026-10-01 (R127 validation half (the header move to src/testmodels is a later batch): NetCageWakeField throws std::invalid_argument for a wake angle outside (0, pi/2) or bad geometry; TestNetcageWake reports WakeAngleDeg outside (0, 90) degrees, FullWakeDiameter, InitialBoundaryLayer and FullWakeDepth as parameter errors; test TestNetcageWake.RejectsAWakeAngleOutsideZeroToNinetyDegreesAndBadGeometry_ENV0058 red before (21 failures), green after; the pinned pre-4.0 numbers are unchanged). File: resolved/ENV-0058-netcage-wake-angle-not-validated.md
  • ENV-0059 (BUG) — The parametric scalar-field JSON silently drops unknown and misspelt keys (z_refrence becomes the surface). Resolved: 9d168d9, 2026-10-01 (every JSON object is checked against an allow-list of its keys (document incl. version and description, each feature type, each background type, clamp, domain; both centre spellings kept); ReadFixedArray takes the node (F-11); the schema sets additionalProperties false at the document and field level and lists description; test ParametricScalarFieldJson.RejectsUnknownKeysAtEveryLevel_ENV0059 red before (8 of 8 keys accepted), green after; the shipped example documents (env and fishery) pass the allow-lists). File: resolved/ENV-0059-parametric-json-drops-unknown-keys.md
  • ENV-0060 (BUG) — Scalar fields accept NaN depths, values and constants and an inverted domain; the DepthVarying size error omits Current.Depth. Resolved: 035458c, 2026-10-01 (depths and values must be finite and the thickness test is !(thickness > 0) (MakeDepthProfileInverseThickness), ConstantScalarField and the parametric constant background must be finite, the parametric domain box must be finite with min <= max; the DepthVarying size error names Current.Depth; tests DepthLayeredScalarField.RejectsNonFiniteDepthsAndValues_ENV0060, ParametricScalarField.RejectsNonFiniteBackgroundsAndAnInvertedDomain_ENV0060 and EnvironmentDefaults.DepthVaryingSizeErrorNamesTheDepthList_ENV0060 red before (13 failures), green after). File: resolved/ENV-0060-scalar-fields-accept-nan-and-inverted-domain.md
  • ENV-0061 (API) — ParametricScalarField downgrades a bathymetry error to OUT_OF_RANGE_INACCURATE. Resolved: 560021f, 2026-10-01 (a bathymetry status that is not usable (marenv::IsUsable) is returned as it is with the value 0; OUT_OF_RANGE_INACCURATE keeps clamping, the domain box and the masked zero, documented in ScalarField::GetValue and ParametricScalarField; test ParametricScalarFieldSeafloor.PassesABathymetryErrorThrough_ENV0061 red before (OUT_OF_RANGE_INACCURATE, value 4), green after; the fishery echosounder wording (batch B4) is not changed). File: resolved/ENV-0061-parametric-field-downgrades-bathymetry-error.md
  • ENV-0062 (API) — Scalar-field XML errors are reported three ways; a DepthLayered fault escapes the Environment constructor. Resolved: 699433a, 2026-10-01 (ConstructScalarField wraps every field constructor in one try/catch that reports on <prefix>Model; an unknown model is a parameter error, no longer a bare runtime_error; F-S5 traced read-only in fhsim (an exception from a SimObject constructor exits cleanly through the application's catch, without a log-file line); test EnvironmentDefaults.ScalarFieldFaultsAreParameterErrors_ENV0062 red before (std::invalid_argument escaped GetScalarFields), green after). File: resolved/ENV-0062-scalar-field-xml-errors-reported-three-ways.md
  • ENV-0063 (BUG) — EnvironmentProvider::m_timeOfLastSeaStateChange is uninitialised. Resolved: bcd3efb, 2026-10-01 (m_timeOfLastSeaStateChange is initialised to 0, and the doc of TimeOfLastSeaStateChange names the one setter (UpdateSeaState, plus its transition time); test EnvironmentProvider.TimeOfLastSeaStateChangeIsZeroBeforeAnyChange_ENV0063 (default-initialised in 0xFF memory) red before (NaN), green after). File: resolved/ENV-0063-time-of-last-sea-state-change-uninitialised.md
  • ENV-0064 (BUG) — GetWakedCurrent zeroes the whole current when a field fails or is clamped, and LumpedWakeCaster treats a clamped current as failed (R122). Resolved: 05a24e2, 2026-10-01 (owner ruling R122 (i)-(iii): GetWakedCurrent (live and held) keeps the sum of the usable current fields and returns the facade's status, so a net panel gets a clamped or partial current as every other consumer; LumpedWakeCaster takes a usable status (marenv::IsUsable) as a known current and keeps ENV-0040 for an error; tests ExternalWakes.WakedCurrentKeepsAClampedAndAPartialCurrent_ENV0064 and LumpedWakeCaster.ClampedCurrentIsUsableAndAFailingFieldCastsNoWake_ENV0064 red before (zero current, no wake above the first layer), green after; behaviour changes only where a current field is clamped or fails). File: resolved/ENV-0064-waked-current-zeroes-partial-and-clamped-current.md
  • ENV-0065 (ARCHITECTURE) — EnvironmentProvider copies marenv's wake composition (WakeSums) and the wake code uses deprecated marenv calls (R126). Resolved: c8cb563, 2026-10-01 (owner ruling R126: environment::WakeSums, ComposeHeldWakes and the held-sum overloads are removed; ExternalWakes holds one marenv::wake::WakeAccumulator per point from SelectReachingWakeFields and adds the own field live (AddOwn on a copy); the provider applies a given marenv::wake::WakeComposition, GetWakedFlow/GetWakedCurrent(time, pos, const WakeComposition&, out); LumpedWakeCaster publishes with BlendedSourceSetWake(kernel) and Publish(SourceSet, velocity, t0, blendTime, seabedDepth), the seabed depth passed explicitly; the tests use BlendedSourceSetWake for their stand-in fields (t0 = 0, the time the source is at its position; the discs with a source velocity now move, so the ExternalWakes tests sample at the take time); no fhsim_marine_elements, fhsim_base or fhsim_fishery code names the removed API; bit-identity: a probe of 840 held and live flows (cutoff 0, 1e-3, 0.1) and three lumped casters over 40 rebuild steps, hexfloat dump identical before and after; ExternalWakes.AtTheTakenPointAndTimeTheyEqualTheLiveQueryExactly and the caster tests green). File: resolved/ENV-0065-provider-copies-wake-composition-and-uses-deprecated-marenv-api.md
  • ENV-0066 (ARCHITECTURE) — Wake helpers and constants are copied (Require, Norm, Format, kMinRelativeFlow, the lumped kernel) and a rebuild looks up the reference and the ambient current twice. Resolved: 7dbae91, 2026-10-01 (internal src/environment/WakeCommon.h holds Require (templated on the exception type, so ReadWakeSettings keeps std::invalid_argument and the SimObjects std::runtime_error, same messages), Norm, Format and FormatVector; the copies in WakeSchedule, LumpedWakeCaster, PorousDiscWakeSource, TestWakeBody and TestNetcageWake are gone; marenv's kMinRelativeFlow and LumpedKernel replace the local constants and RearFaceKernel; LumpedWakeCaster::Rebuild takes the reference and the ambient current from Update (one lookup each per rebuild); no behaviour change: the E1 hexfloat probe is identical and 249/249 suite tests pass). File: resolved/ENV-0066-wake-helpers-and-constants-duplicated.md
  • ENV-0067 (ARCHITECTURE) — WakeSchedule::Due depends silently on a preceding FilterShare. Resolved: 755e12f, 2026-10-01 (Due(T) throws std::logic_error unless FilterShare was called at the same T (a call that returns share 0 counts); the in-tree callers (LumpedWakeCaster, fhsim_marine_elements NetWakeCaster::FilterNodeVelocities) already call it first; three WakeSchedule tests that called Due alone now call FilterShare first; test WakeSchedule.DueRequiresFilterShareAtTheSameTime_ENV0067 red before, green after; E1 probe identical). File: resolved/ENV-0067-schedule-due-depends-silently-on-filter-share.md
  • ENV-0068 (API) — ExternalWakes readers and SeabedImageDepth need a mutable EnvironmentProvider. Resolved: c72f571, 2026-10-01 (ExternalWakes::WaterVelocity and WakedCurrent take const EnvironmentProvider& and SeabedImageDepth is const (the bathymetry's lookup, as GetSeaDepth); test ExternalWakes.ReadersTakeAConstEnvironment_ENV0068 did not compile before, green after; callers with a mutable provider (fhsim_marine_elements) compile unchanged; E1 probe identical). File: resolved/ENV-0068-wake-readers-need-mutable-provider.md
  • ENV-0069 (API) — LumpedWakeCaster offers no own-field-excluding query; every author builds it by hand. Resolved: c1a9699, 2026-10-01 (LumpedWakeCaster::OwnQuery() returns the WakeQuery with exclude = its registered field (nothing before Register), documented as the query of every own flow lookup; TestWakeBody uses it; test LumpedWakeCaster.OwnQueryExcludesTheRegisteredField_ENV0069 did not compile before, green after; fhsim_marine_elements' BodyFlowInteraction::OwnWakeQuery can use it (not edited here)). File: resolved/ENV-0069-lumped-caster-has-no-own-query.md
  • ENV-0070 (API) — Wake attributes are ignored silently without CastWake, and nets read WakeCutoff twice. Resolved: ead791a, 2026-10-01 (without CastWake, ReadWakeSettings logs every wake parameter given in the input (GetParamSize > 0) as ignored, one LogParameterInfo line each, not an error; WakeSettings::cutoffGiven records whether WakeCutoff was given so fhsim_marine_elements' NetWakeCaster can drop its second read (ME not edited here); the test stub records LogParameterInfo; test ReadWakeSettings.LogsTheWakeParametersIgnoredWithoutCastWake_ENV0070 did not compile before, green after; log lines only). File: resolved/ENV-0070-wake-attributes-ignored-silently-without-castwake.md
  • ENV-0071 (API) — ScalarField::GetValue and EnvironmentProvider::GetScalarValue are not const; GetScalarValue copies a shared_ptr per query. Resolved: beb10e8, 2026-10-01 (ScalarField::GetValue and its three fields are const, EnvironmentProvider::GetScalarValue is const and looks the field up by raw pointer (no shared_ptr copy per query); the test doubles add const; test EnvironmentProvider.ScalarValuesAreReadThroughConstReferences_ENV0071 did not compile before, green after; no in-stack subclass outside this repo; fishery's workaround notes (SensorCtd, SensorSilCam) are batch C4). File: resolved/ENV-0071-scalar-field-getvalue-not-const.md
  • ENV-0072 (DOCUMENTATION) — The wake docs contradict the code: WakeCutoff roles, a stale TestWakeBody line, the legacy NetCageWakeField pattern, LumpedWakeCaster.h, the stand-in recipe. Resolved: 1560384, 2026-10-01 (documentation only: wakes.md gives both WakeCutoff roles (grid; with CastWake the R47 receiver tier, 1e-4 without), drops the stale TestWakeBody line (it excludes its own field since ENV-0047, now through OwnQuery), says no shipped receiver uses cutoff 0, the published velocity after the R50 snap, the clamped current (R122), the ignored-parameter log (ENV-0070), the seabed re-read (ENV-0056) and the stand-in recipe (copy M, area and rear centre, WakeXStartFactor 0); EnvironmentProvider.h teaches the LumpedWakeCaster pattern with OwnQuery; NetCageWakeField is marked legacy in its header and in wakes.md; LumpedWakeCaster.h names OwnQuery and the published velocity). File: resolved/ENV-0072-wake-docs-contradict-the-code.md
  • ENV-0073 (DOCUMENTATION) — DepthVarying, scalar-field and farm docs: end behaviour, direction, GetScalarValue parameters, bathymetry at setup, WakeIterations for rows. Resolved: 122cbd1, 2026-10-01 (documentation only: Environment.h DepthVarying gives the direction convention (flows towards, from North towards East), strictly increasing depths and the R122 end behaviour (nearest layer, OUT_OF_RANGE_INACCURATE, summed by every consumer); GetScalarValue lists its parameters in signature order; the schema and ParametricScalarField.h say the field uses the Environment's bathymetry at setup (a later NetCdfSeafloor is not seen, W-06/R124); wakes.md and WakeSchedule.h state R121: an N-row farm needs WakeIterations >= N and a net converges on max(max|dR|, |dM|/M), written as true once the fhsim_marine_elements batch lands). File: resolved/ENV-0073-depth-profile-scalar-and-farm-docs.md
  • ENV-0074 (BUG) — A non-finite reference velocity poisons LumpedWakeCaster's source-velocity filter for good, and every later rebuild throws in marenv. Resolved: 6c630bd, 2026-10-01 (architect decision in batch E2, after the ENV-0044/ENV-0040 precedent: a step with a non-finite Reference() is skipped and logged once per run of such steps; it does not enter u_s, and a due rebuild builds, publishes and counts nothing, so it runs at the next finite step; test LumpedWakeCaster.NonFiniteReferenceIsSkippedAndTheCasterRecovers_ENV0074 red before (BlendedSourceSetWake::Publish: the source velocity must be finite, u_s NaN), green after). File: resolved/ENV-0074-nan-reference-velocity-poisons-source-velocity-filter.md
  • ENV-0075 (API) — PorousDiscWakeSource caps C_T at 0.96 silently, stays at Position while dragging the water at SourceVelocity, and uses its own field type. Resolved: b61fba1, 2026-10-01 (owner ruling R125, OD-5: the area is widened to M / 0.96 above C_T = 0.96 and logged once at setup; the source is at Position at the setup time and translates with SourceVelocity; the field is a BlendedSourceSetWake published with blend time 0, a followed axis published again at each step's time and position; a clamped ambient current is usable for the followed axis (R122). Tests PorousDiscWakeSource.ThrustCoefficientAbove096WidensTheAreaAndLogsOnce_R125 (red: deficit 0.3601 against 0.3849 at x = 10 m, no log line), SourceTranslatesWithSourceVelocity_R125 (red: 0.1538 against 0.2621; the towed followed source 0 against 0.2632) and FollowedAxisAcceptsAClampedCurrent_R122 (red: no wake) green after. Characterisation: for C_T ≤ 0.96 and SourceVelocity = 0, 75 600 probe samples (fixed axis, C_T = 0.96 exactly with overridden kernel, followed axis turning and stopping, 12 m seabed; deficit, source velocity, status, waked current at t = 0 and 10 s) are bit-identical before and after; no existing test changed). File: resolved/ENV-0075-porous-disc-caps-ct-fixed-position-own-field-type.md
  • ENV-0076 (BUG) — A NetCdfSeafloor bathymetry reaches only the facade: SeafloorForces and seafloor-referenced scalar fields keep the Environment's setup seabed. Resolved: 4baaada, 2026-10-01 (owner ruling R124, OD-4: Bathymetry.Model = "NetCDF" with Bathymetry.NetCDFFile makes the NetCDF depth grid the Environment's one bathymetry, fixed at construction, handed to the facade, SeafloorForces and the scalar fields; the NetCdfSeafloor SimObject is deprecated, logs it at setup (a parameter info line on NetcdfFile pointing to Bathymetry.Model = "NetCDF") and is removed in the next major version. Tests EnvironmentBathymetryNetCDF.ReachesTheFacadeSeafloorForcesAndScalarFields_R124 (F-01's sketch: a 30 m file, a seafloor-referenced depth profile 1 → 0 over 10 m, 0.5 at z = 25 m, and SeafloorForces::GetSubmergence = −5 m; red before: Unknown bathymetry model: NetCDF), EnvironmentBathymetryNetCDF.RequiresAReadableFile_R124 and the deprecation check in NetCdfSeafloor.RegistersItsBathymetryOnTheEnvironment (red before: no line) green after). File: resolved/ENV-0076-netcdf-seafloor-reaches-only-the-facade.md
  • ENV-0077 (API) — NetCageWakeField, a legacy test-only wake, is installed as public API and drops a clamped ambient current. Resolved: c3519c3, 2026-10-01 (owner ruling R127, OD-7, the move half; the validation half was ENV-0058: NetCageWakeField.h and .cpp move from include/fhsim_environment/ and src/environment/ to src/testmodels/ and the header is no longer installed; the field takes a clamped ambient current (OUT_OF_RANGE_INACCURATE) as usable, as every other consumer (R122 (iii); E1 review P2-5, decided in E2); test_package checks a ConstantScalarField on an EnvironmentProvider instead. Test NetCageWakeField.AClampedCurrentIsUsable_R122 red before (status 1 and deficit 0 instead of OK and 0.19611640360388949), green after). File: resolved/ENV-0077-netcage-wake-field-public-and-drops-clamped-current.md
  • ENV-0078 (API) — CNCField/CNetCDFField is a second NetCDF current API that nothing consumes. Resolved: 78a0190, 2026-10-01 (owner ruling R127, OD-7: removed now. Deleted: the public header include/fhsim_environment/CNCField.h (environment::CNCField), src/environment/CNCField.cpp, the NetCDFField SimObject (CNetCDFField, src/environment/NetCDFField.h/.cpp, its registration and its NCField shared resource), its reader src/environment/util/netcdf_handler.h/.cpp (NetcdfHandler, no other user) and tests/NetCDFField_Test.cpp (9 cases). A NetCDF current stays available as Current.Model = "NetCDF", which moves the water. Pure removal: no red test; the build, a repo-wide grep and the full suite (252 tests, from 261) are the evidence). File: resolved/ENV-0078-cncfield-second-netcdf-current-api.md
  • ENV-0079 (ARCHITECTURE) — The scalar fields interpolate depth profiles with their own code, not marenv's one DepthProfile. Resolved: 6ff27cc, 2026-10-01 (W-30, after R122 and marenv MENV-0053: DepthLayeredScalarField and the depth_profile background of ParametricScalarField hold a marenv::calc::DepthProfile, built by environment::field::MakeDepthProfile (marenv's validation, the message prefixed by the field); the public MakeDepthProfileInverseThickness and EvaluateDepthProfile are deleted. Characterisation probe (temporary test, not committed; log /tmp/nethydro-build/e2-dp-probe.log): 54 profiles (the test profiles and 50 random ones with 2 to 10 layers), 1 080 357 depths over each profile ±20 m plus every layer depth: statuses identical, values at the layers and outside bit-identical, 145 824 interior values differ in the last bits (division against multiplication by the inverse thickness), max |Δ| = 2.27e-13, max relative 1.47e-11. No existing test needed loosening. One behaviour change: a NaN depth now gives ERROR_NOT_SET and the value 0 (before: NaN with status OK), passed through by ParametricScalarField as a bathymetry error is (ENV-0061); test DepthLayeredScalarField.NaNDepthIsAnErrorWithValueZero_W30 red before (status OK, value NaN), green after). File: resolved/ENV-0079-scalar-fields-own-depth-profile-interpolator.md
  • ENV-0080 (BUG) — A parametric document with a top-level "fields" object silently drops its other top-level keys. Resolved: 579e09f, 2026-10-01 (SelectFieldConfig rejects any top-level key beside fields other than version and description, naming it, as a parameter error on ScalarField.<Name>.Model (ENV-0062); the schema's wrapper branch of oneOf lists only those three keys with additionalProperties: false, the single-field branch is $defs/field. Test EnvironmentDefaults.ScalarFieldWrapperRejectsKeysBesideFields red before (the field was built, no error), green after. The shipped wrapper documents (examples/input/auv_ocean_fields.json, scalar_field_demo.json, fishery's auv_ocean_fields.json) have only version, description and fields). File: resolved/ENV-0080-parametric-wrapper-drops-top-level-keys.md
  • ENV-0081 (BUG) — The scalar bake draws an error status with the value 0 as data when MaskInaccurate is off. Resolved: 5100627, 2026-10-01 (util::BakeScalarField and util::ProbeScalarFieldRange share IsDrawn: a non-finite value or a status marenv::IsUsable rejects is masked and left out of the probed range whatever maskInaccurate (ShowExtrapolated) says; maskInaccurate still decides only for OUT_OF_RANGE_INACCURATE. Test ScalarFieldBake.AnErrorStatusIsMaskedEvenWithoutMaskInaccurate red before (mask 255, code 1, range valid), green after). File: resolved/ENV-0081-scalar-bake-draws-error-status.md
  • ENV-0082 (BUG) — LumpedWakeCaster counts a rebuild whose current lookup failed, so Freeze can freeze at M = 0 and never rebuild after the lookup recovers. Resolved: 63066bf, 2026-10-01 (architect decision under owner ruling R122 (ii), the semantics of fhsim_marine_elements MARE-0336 and ENV-0074; supervisor ruling (A) for the recovery: a dropped wake makes a rebuild due in every mode. Tests LumpedWakeCaster.FailedLookupsDoNotFreezeAndTheCasterRecovers_ENV0082 red before (2 rebuilds, frozen at M = 0), FailedLookupDropsTheWakeAfterTheBlendAndRearmsFreeze_ENV0082 red before (no drop or episode line), FailingCurrentCastsNoWakeAndSaysSo and ClampedCurrentIsUsableAndAFailingFieldCastsNoWake_ENV0064 updated to the new semantics; WakeSchedule.RebuildDueAt*_ENV0082 for the new schedule method; all green after). File: resolved/ENV-0082-lumped-caster-counts-failed-lookup-rebuild.md
  • ENV-0083 (ARCHITECTURE) — LumpedWakeCaster keeps its own copy of the lumped relaxation and of the |dM|/M measure, and names a removed marenv type. Resolved: 4d79c0f, 2026-10-02 (marenv MENV-0061 adds RelaxLumpedSource, pinned there bit for bit against a verbatim copy of LumpedWakeCaster::Relax; test WakeSchedule.MomentumChangeIsTheRelativeChangeOfM_ENV0083 did not link before (no MomentumChange), green after; a hexfloat dump of LumpedWakeCaster (Off, Freeze and Periodic with WakeRelaxation 1 and 0.3, a moving body with a varying drag coefficient and a near-zero relative flow: every lumped source, |dM|/M, u_s and 4,000 field samples, 35,290 lines) is byte-identical before and after (/tmp/nethydro-build/c1b/probe-env-{before,after}.txt); the type is renamed to marenv's SourceSetWake (MENV-0060) in the same commit; 262/262 tests pass). File: resolved/ENV-0083-lumped-relaxation-and-momentum-change-copied.md
  • ENV-0084 (ARCHITECTURE) — The failed-lookup episode is written twice, in LumpedWakeCaster and in fhsim_marine_elements' NetWakeCaster, with two wordings. Resolved: 040630d, 2026-10-02 (WakeSchedule::BeginLookupFailure, MayDropWake, RecordWakeDrop and EndLookupFailure; tests WakeSchedule.LookupFailureEpisodeDropsOnceAfterTheBlendAndRebuildsAtTheRecovery_ENV0084 and WakeSchedule.LookupFailureWithoutACountedDropMakesNothingDue_ENV0084 did not compile before (no such members), green after; a hexfloat dump of LumpedWakeCaster with failed lookups (Off, Freeze and Periodic, WakeRelaxation 1 and 0.3, WakeBuildTime 0 and 2 s, five failure episodes including one before the first build and one during a blend: every lumped source, |dM|/M, u_s, rebuild count, Freeze state and 108,864 field samples, 109,356 lines) is byte-identical before and after with the log lines left out, which keep their number and order but take the one wording (/tmp/nethydro-build/f1/probe-env-{before,after}.txt); 264/264 tests pass). File: resolved/ENV-0084-failed-lookup-episode-copied.md
  • ENV-0085 (API) — LumpedWakeCaster::Update before Register silently does nothing. Resolved: c628b0e, 2026-10-02 (test LumpedWakeCaster.UpdateBeforeRegisterIsLoggedOnce_ENV0085 red before (no line), green after; 265/265 tests pass). File: resolved/ENV-0085-update-before-register-silent.md
  • ENV-0086 (API) — The deprecated NetCdfSeafloor SimObject is still registered. Resolved: b0f1afa, 2026-10-02 (owner ruling R129: the SimObject, its registration, rendering and three tests deleted; NetCdfSeafloor.{h,cpp} renamed NetCdfSeafloorBathymetry.{h,cpp} with the bathymetry class only; test SimObject.NetCdfSeafloorIsRemoved_R129 red before (the input loaded and ran, result.ok true), green after; SimObject.EnvironmentBathymetryNetCDF added, green before and after; 264/264 tests pass; no input, example or consumer in the stack names it, only fhsim_insights' models.md and reports/simobject-test-coverage.md). File: resolved/ENV-0086-remove-netcdfseafloor-simobject.md
  • ENV-0087 (API) — The default WakeIterations 2 leaves a farm of three or more rows unconverged. Resolved: d852f72, 2026-10-02 (owner ruling R130; test ReadWakeSettings.DefaultsAreTheLeadApprovedChoices red before (2), green after; WakeSchedule.FreezeStopsAfterTheLastIteration, which runs on the default, moves from 3 to 5 rebuilds and is updated in the next commit, "Baselines for R130"). File: resolved/ENV-0087-wake-iterations-default-two.md
  • ENV-0088 (ARCHITECTURE) — A net with no other wake field in the registry still computes its sample points and takes an empty composition at every step. Resolved: 800d4c6, 2026-10-02 (ExternalWakes::NeedsTake; tests NeedsTakeIsFalseWithOnlyTheOwnLumpedField_ENV0088, NeedsTakeIsFalseWithNoRegisteredField_ENV0088, NeedsTakeIsTrueWithAnotherField_ENV0088, NeedsTakeIsFalseForEvaluation_ENV0088 and WithoutAnyOtherFieldTheLiveQueryEqualsTheTake_ENV0088 did not compile before (no NeedsTake), pass after; the characterisation dumps C1 to C9 are identical before and after). File: resolved/ENV-0088-external-wakes-take-without-other-field.md
  • ENV-0089 (ARCHITECTURE) — ReceiverCutoff (the R47 cutoff tier of a receiver) lives in fhsim_marine_elements, above the wake settings it reads. Resolved: b05d054, 2026-10-02 (batch B2, R1: environment::wake::ReceiverCutoff and kNonCastingCutoff in ExternalWakes.h; tests ReceiverCutoff.* did not compile before (no such name), pass after; fhsim_marine_elements keeps a forwarding header). File: resolved/ENV-0089-receiver-cutoff-in-fhsim-marine-elements.md
  • ENV-0090 (ARCHITECTURE) — The wet fractions and the gated surface queries of a body live in fhsim_marine_elements, so an environment-only model cannot use them. Resolved: f36f009, 2026-10-02 (batch B2, R2: BodySubmergence.h, environment::body_submergence, the wet fractions moved verbatim and the gated Submergence, WaveAcceleration, MeanWaveAcceleration, WavesWithElevation and CylinderWetFraction(environment, …) of cable_surface with them; new overloads WaveAcceleration(environment, T, p, a) and SphereWetFraction(environment, T, centre, r). The 7 BodySubmergence tests move from fhsim_marine_elements and compile against the new namespace; the gate tests Submergence/WaveAcceleration/SphereWetFraction …_ENV0090 did not compile before, pass after). File: resolved/ENV-0090-body-submergence-and-surface-queries-in-marine-elements.md
  • ENV-0091 (API) — A sphere's drag, added mass and Froude-Krylov factor exist only inside fhsim_marine_elements' Net/Sphere. Resolved: 21a4ef9, 2026-10-02 (batch B2, R2: SphereHydro.h, environment::sphere_hydro: Sphere, kAddedMassCoefficient, DragForce, DragJacobian, CurrentLoad, AddedMass, DisplacedMass, ExcitationFactor, MomentumDeficit; tests SphereHydro.* did not compile before, pass after. BodyLoad waits for SourceLoad (batch B4/B7)). File: resolved/ENV-0091-sphere-hydro-helper-in-marine-elements.md
  • ENV-0092 (ARCHITECTURE) — ExternalWakes samples a casting object's own private field live in every evaluation, instead of holding it per step with the other objects' wakes. Resolved: eb9d77d, 2026-10-02 (batch B3, owner ruling R135: ExternalWakes::Take holds a WakeComposition per point with the own private field sampled at the take; NeedsTake true with query.own. Tests StepHoldsTheOwnPrivateFieldOfTheTakenPoint_R135 and NeedsTakeIsTrueWithTheOwnPrivateField_R135 failed before (B3-env-red.log), pass after; StepHoldsTheOtherWakesOfTheTakenPoint and WithoutAnyOtherFieldTheLiveQueryEqualsTheTake_ENV0088 move in "Baselines for R135"). File: resolved/ENV-0092-external-wakes-hold-own-private-field.md
  • ENV-0093 (ARCHITECTURE) — The marching private and lumped wake build of a source set lives only in fhsim_marine_elements' NetWakeCaster. Resolved: f92d415 and 88ff071 (WakeCommon.h installed), 2026-10-02 (batch B4, design R5: WakeSourceSet.h with SourceLoad, WakeCastState and WakeCastingObject; WakeCaster.h with WakeCaster, SourceSetWakeSettings, ReadSourceSetWakeSettings, WakeEvaluation, moved verbatim from fhsim_marine_elements' NetWakeCaster; the ENV-0074 non-finite skip is new for source sets. The six tests WakeCaster.* did not link before (no WakeCaster, B4-env-red.log), pass after; fhsim_marine_elements MARE wraps it). File: resolved/ENV-0093-wake-caster-for-source-sets.md
  • ENV-0094 (ARCHITECTURE) — LumpedWakeCaster keeps its own copy of the lumped build, schedule episode and logging that WakeCaster has. Resolved: 94874d7, 2026-10-02 (batch B5, design §3.3: WakeEvaluation::None, the lumped field only; LumpedWakeCaster is WakeCaster with one source over a single-body adapter, LumpedWakeCaster.cpp 217 → 174 lines with the adapter. No new test: the gate is the unchanged LumpedWakeCaster_Test (29) and TestWakeBody_Test (8), which pass, and the characterisation dumps C5 and C8, identical to /tmp/char/B5-base). File: resolved/ENV-0094-lumped-wake-caster-duplicates-wake-caster.md
  • ENV-0095 (API) — The facade of a SimObject that casts and receives wakes lives only in fhsim_marine_elements. Resolved: 661cfae, 2026-10-02 (batch B6, design R3 §3.4: BodyWake.h with BodyWake, BodyWakeSettings, BodyWakeKind and ReadBodyWakeSettings(creator, kind); WakeSourceSet gains NumSamplePoints, SamplePointCarriers and CarrierMeanPosition. Owner decision on the API gap: the constructor takes the logger, Register(environment, rho) does not. The six tests BodyWake.* did not compile before (no BodyWake.h, B6-env-red.log), pass after; env ctest 306 tests, 0 failures; characterisation dumps C8 and C9 identical to /tmp/char/B6-base). File: resolved/ENV-0095-body-wake-facade-in-marine-elements.md
  • ENV-0096 (BUG) — WakeCaster trusts the carrier count and carrier numbers a WakeSourceSet returns. Resolved: 1fa9225, 2026-10-02 (batch B7, B4 review P2: WakeCaster::Update skips a step in which a source names fewer than 1 or more than 3 carriers, or a carrier outside the set, logged once per run as ENV-0074; CarrierMeanPosition returns not-a-number for such a list. Tests WakeCaster.SourceWithoutCarriersSkipsTheStep_ENV0096 (threw "SourceSetWake::Publish: the source velocity must be finite") and WakeCaster.SourceWithTooManyOrUnknownCarriersSkipsTheStep_ENV0096 (stack smashing) failed before (B7-env-red.log), pass after with CarrierMeanPositionOfAMalformedListIsNotANumber_ENV0096). File: resolved/ENV-0096-wake-caster-trusts-source-carrier-count.md
  • ENV-0097 (DOCUMENTATION) — The generic wake caster's messages and comments still speak of a net's panels and of NetWakeCaster. Resolved: abbeabd, 2026-10-02 (batch B7, B4 review P2: the WakeLength and WakeGrid setup errors of ReadSourceSetWakeSettings say "source"; WakeSchedule.h names WakeCaster; doc/user/wakes.md says where a source set's four parameters are read and what its change measure is; the ENV-0093 record lists 88ff071. Text only, no test). File: resolved/ENV-0097-generic-wake-caster-keeps-net-wording.md
  • ENV-0098 (API) — A SimObject of several rigid bodies has no wake-casting interface and no aggregate mode. Resolved: 60e595a, 2026-10-02 (batch B7, design R4 §3.1 and §6 B7: IndexedWakeCastingObject and CastState in WakeSourceSet.h; WakeEvaluation="None" read by ReadSourceSetWakeSettings; sphere_hydro::BodyLoad from the existing MomentumDeficit; test model TestWakeCluster; doc/user/wakes.md "Multi-body objects". The tests TestWakeCluster.* and SphereHydro.BodyLoad* did not compile before (B7-env-red2-build.log); with the new code but without the None reader, TestWakeCluster.WithoutAPrivateField* threw "WakeEvaluation is \"None\"" (B7-env-red3.log); all pass after). File: resolved/ENV-0098-no-multi-body-wake-casting-object.md
  • ENV-0099 (BUG) — ExternalWakes holds the wakes with the blend weight of the step start, so the held flow is a staircase in time during a rebuild blend. Resolved: 81c8e5f, 2026-10-02 (owner ruling R136, batch B8, with marenv MENV-0066: ExternalWakes::Take holds per point the WakeSampleParts of every selected field and of the own private field while one of them blends, and WaterVelocity/WakedCurrent compose them at the evaluation time (HeldComposition); outside a blend the finished composition as before. Tests ExternalWakes.InsideABlendTheHeldSamplesComposeWithTheLiveBlendWeight_R136 and ATakeAtAPublishInstantHoldsTheFieldThatFadesIn_R136 red before (the held flow kept the weight of the take, 0.6250 against the live 0.7032 at t = 2.5 s; B8-env-red.log), green after; full suite 318 tests passed; characterisation C8 and C9 identical). File: resolved/ENV-0099-held-wake-blend-weight-live.md
  • ENV-0100 (ARCHITECTURE) — A source set's wake reads every carrier once per source or sample point per step, and BodyWake::WakedCurrent costs a call per evaluation. Resolved: 7fad82f, 2026-10-03 (batch C-perf: CarrierPositions(set, X, positions) reads each carrier once and CarrierMeanPosition(positions, carriers, n, mean) takes the mean from them, bit for bit that of CarrierMeanPosition(set, X, ...); BodyWake::Update and WakeCaster::Update (SkipNonFiniteCarrier, SourcePosition, CurrentLookupFails) read the carrier positions once per step; CarrierMeanPosition(set, ...) and SkipMalformedSource ask the set for its size once; BodyWake::WaterVelocity and WakedCurrent are inline; ExternalWakes::WakedCurrent passes the held composition outside a blend without a copy. Test WakeCaster.CarrierMeanPositionFromHeldPositionsIsTheSetsMean_ENV0100 did not compile before (no CarrierPositions), passes after; characterisation C8 and C9 identical to /tmp/char/B9-base). File: resolved/ENV-0100-source-set-wake-reads-carriers-per-point.md
  • ENV-0101 (ARCHITECTURE) — The shape and panel load laws live in fhsim_marine_elements and fhsim_base, so a body below ME cannot use them. Resolved: 9008207, 2026-10-04 (feature fluid-body-interaction batch B1, ADR 0002: hydrodynamics/ with SphereHydro.h, BodySubmergence.h (+ CylinderWetFractionGradient, MediumDensity, SetSurface, SetWaveAcceleration), DiskHydro.h, CylinderHydro.h, the panel load laws and NetSolidity.h; tests 319 → 462, all pass. ME and fhsim_base delete their copies in B3, B4). File: resolved/ENV-0101-shape-and-panel-laws-outside-the-environment.md
  • ENV-0102 (API) — A SimObject can cast a wake through three public paths, and each has footguns. Resolved: 7394531, 2026-10-04 (feature fluid-body-interaction batch B2: BodyWake the one public path, casters in environment::wake::detail; SphereCaster, DiskCaster; PanelSourceSet.h and BodyFlowInteraction.h moved from fhsim_marine_elements; density at construction, WaterVelocity before Register throws, one log, one helper, one accessor set; doc/user/wake-parameters.md; tests 462 → 481 (and 13 disabled), all pass. ME switches in B3). File: resolved/ENV-0102-casting-api-has-several-public-paths.md
  • ENV-0103 (BUG) — The face-on drag area of a disc on a cable is π/4 D (D − d/π), not the annulus outside the cable. Resolved: 7ee7fce, 2026-10-04 (owner delegation, feature fluid-body-interaction: the annulus π/4 (D² − d²) in DragForceNormal and face on in FrontalArea; DiskHydro_Test red on the old area (7 cases), all 481 tests pass. fhsim_marine_elements' net-cable discs call DragForceNormal instead of their inline annulus). File: resolved/ENV-0103-disc-face-area-not-the-annulus.md
  • ENV-0104 (BUG) — The cable element's Reynolds number |v|² D / (ν |v_n|) grows without bound in nearly axial flow, so Cd drops to the drag crisis or takes the lift branch. Resolved: 35f097d, 2026-10-04 (owner ruling 2026-10-04, feature fluid-body-interaction: Cd on the cross-flow Reynolds number |v_n| D / ν, Ct on |v| D / ν, the lift branch removed; CylinderHydro_Test red on the old derivatives (2 tests) and the old 4-argument API, all 482 tests pass). File: resolved/ENV-0104-cylinder-reynolds-number-blows-up-near-axial-flow.md
  • ENV-0105 (API) — The cylinder drag force has no shared home and no choice of formulation. Resolved: 4664729, 2026-10-04 (owner decision b 2026-10-04, feature fluid-body-interaction: cylinder_hydro::DragForce, DragForceJacobian, DragFormulation { Independence, Eames }, kWaterKinematicViscosity; seven CylinderDrag tests, red (not compiling) before the functions existed, all 489 tests pass). File: resolved/ENV-0105-cylinder-drag-force-has-no-shared-home.md
  • ENV-0106 (BUG) — The cylinder normal-drag coefficient steps by 0.75 at Re = 14 and has no source below it. Resolved: 3a2ca11, 2026-10-04 (owner delegation 2026-10-04, feature fluid-body-interaction, fhsim_marine_elements MARE-0331: below the branch edge Cd is White's 1 + 10 Re^(−2/3), the edge moved to its crossing with the middle branch, kLowReynolds = 20.582841580981793, Re clamped to 1 below 1 (Cd = 11, slope 0); CylinderHydro_Test red on 5 tests before the change, all 492 tests pass after). Corrected by 2f4335f, 2026-10-04: the clamp at Re = 1 underestimated Stokes-range drag about 3× (digitised White/Wiley curve 33.3 at Re = 0.2, 16.4 at 0.5); White's correlation now applies down to the floor kMinimumReynolds = 1e-6 (Cd = 1 + 1e5, slope 0), which only keeps Cd finite in axial flow (30.2 at Re = 0.2, 16.9 at 0.5, 11 at 1). CylinderHydro_Test red on 3 tests before (Cd(0.2) = 11 against 33.3), all pass after; new TinyNormalSpeedsGiveFiniteForceAndJacobian_MARE0331 (force and Jacobian finite for v_n down to 0 and 1e-20 m/s). File: resolved/ENV-0106-cylinder-normal-drag-steps-at-reynolds-14.md