diff --git a/AGENT_HANDOFF.md b/AGENT_HANDOFF.md index 0c6580167..9146e1fcb 100644 --- a/AGENT_HANDOFF.md +++ b/AGENT_HANDOFF.md @@ -1,5 +1,43 @@ # AGENT_HANDOFF — Tools +## 2026-08-11 PR #4342 current-parent propagation candidate + +This no-publish candidate keeps PR `#4342` on +`feat/4274-regional-plan-io` with base `feat/4274-regional-surface-ui`. +Exact current child `c1f47f2ef68b3db102da5416aaac17a40f675207` is the first +parent and exact reviewed local #4339 candidate +`db335937afc4b587d235eb705e315f577519c5e6` is the second parent of a +normal no-ff merge. Child-owned canonical request import/export, bounded UTF-8, +native atomic save, browser-qualified download, tests, and limitations remain +intact while inheriting current editor, wire, regional-physics, and complete +ground-model ancestry. + +The merge also resolves one cross-runtime compatibility edge without weakening +the ground contract. The default shared canonical encoder still rejects floats +or integers outside JavaScript's safe range. A separately named extended +finite-float policy reuses the same recursive encoder only through the +capability-observation facade; integers remain safe-range bounded and integral +finite doubles such as `1e20` and `1e21` emit exact exponent-free tokens that +match the TypeScript capability serializer. Non-finite values still fail +closed. + +Local qualification is green: all `909` Rate-of-Closure Python tests, all +`110` React files / `686` tests, and the complete Cargo workspace pass. The +focused compatibility/regional-I/O slices pass `47` Python and `12` React +tests. Pinned Ruff 0.14.10 check/format passes `17` changed Python files; pinned +MyPy 1.13 and Bandit pass `12` changed production files. TypeScript, +zero-warning ESLint, the 199-module Vite build, Rust format and warning-denied +clippy, both 400- and 500-LOC changed-file gates, manifest/docs/blocking-gate/ +assertion/minimum-test governance, marker scans, and diff checks pass. An +untouched manual-delivery UI test timed out once during the first concurrent +full run, then passed alone and in the single complete rerun. + +No branch has been rebased, retargeted, rewritten, force-pushed, or published. +Execution and playback, result interchange, measured calibration, model-input +persistence, changing geometry or velocity, TypeScript/compiled regional +physics, downstream parity, protected exact-head evidence, approval, +dependency integration, and release remain open. + ## 2026-08-11 PR #4339 current-parent propagation candidate This no-publish candidate keeps PR `#4339` on @@ -32,188 +70,16 @@ model-input persistence, changing geometry or surface velocity, TypeScript/compiled regional physics, downstream parity, protected exact-head evidence, approval, dependency integration, and release remain open. -## 2026-08-11 PR #4339 structural helper repair candidate - -This local follow-up descends exact independently reviewed reconciliation -candidate `eedad6d23b517eb4c99d4ba9000ff6555101099f`. Independent review found -one publication blocker: the regional PyQt number-input helper accepted six -parameters, above the campaign's mandatory four-parameter limit. RED-first -tests now bind the helper's signature and all observable widget settings. A -frozen `NumberInputSpec` validates finite positive step and finite ordered -bounds before widget construction; the three-parameter helper preserves field -names, values, units, ranges, increments, tooltips, and presentation order. - -Eight focused Python/PyQt tests and 25 focused React tests pass; the complete -React suite passes all 108 files / 672 tests. Pinned Ruff check/format, MyPy on -all six affected production modules, Bandit medium/high screening, TypeScript, -zero-warning ESLint, documentation/manifest governance, changed-production, -test-assertion, minimum-test, 500-LOC, and diff gates pass. Mandatory maxima -are 400 module lines, 42 function lines, and three parameters. A broader -Rate-of-Closure Python run reached the ten-minute workstation lifecycle bound -without yielding an assertion failure; it is not counted as passing evidence. -The monorepo-wide lane separately exposed unrelated baseline failures and -xdist worker termination. No schema, digest, regional physics, UI behavior, -PR base, protected evidence, or release boundary changes. - -## 2026-08-11 PR #4339 current-parent ancestry candidate - -The clean `feat/4274-regional-surface-ui` worktree normally merges exact -published child `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` with exact newly -published #4335 parent `9e01ccc3e891cc45907293751a192624195a77a5`, -while preserving #4339's `feat/4271-regional-wire-contract` base. Production -UI, contract, resolver, regional physics, and ground ancestry merge without -conflict. Only SPEC, manifest, and handoffs are reconciled. Independent review, -ordinary fast-forward publication, fresh protected CI/approval, dependency -integration, and release remain required. - -## 2026-08-10 PR #4339 stale-validation invalidation follow-up - -Rendered exact-head browser QA found that a validated one-overlay readback -remained visible after adding a second overlay. The broad PyQt6 suite also -found missing hover hints on the new controls. PyQt6 and React now clear both -canonical readback and prior validation state whenever any identity, interval, -material, or overlay-row draft value changes; PyQt6 exposes the explicit -"Changes not validated" pending state, and every PyQt6 interactive has a -specific engineering-context tooltip. RED-first regression tests cover the -dynamic-row path on both surfaces. Final local evidence is 870 Python/PyQt -tests and 672 React tests passing; Ruff, format, MyPy, TypeScript, zero-warning -ESLint, the 198-module production build, manifest/docs/file-size governance, -and diff checks are clean. The known polynomial-generator empty-legend warning -is unrelated. This changes no wire schema, provenance digest, physics, or -persistence boundary; fresh protected CI is still required before merge. - -## 2026-08-11 Current regional-surface parent reconciled into PR #4335 - -Open draft PR `#4335` retains branch `feat/4271-regional-wire-contract` and -base `feat/4271-regional-surface-transitions`. Exact remote regional-wire child -`9e01ccc3e891cc45907293751a192624195a77a5` is merged first and exact current -regional-surface parent `5ac3c1f233de30dd42eeac57073cbdb149bde652` -second by an ordinary no-ff merge. The child's Python/TypeScript wire schemas, -canonical JSON/SHA-256 fixture, fail-closed parsing, Python resolver binding, -tests, contracts, and limitations remain intact with both append-only handoff -and specification histories. - -Focused local qualification is green: all `132` Python ground/regional-wire -tests, `9` focused React regional/ground-contract tests, and all `137` -`tools-core` Rust tests pass. TypeScript, zero-warning ESLint, the 190-module -Vite build, Rust workspace format and warning-denied clippy, pinned Ruff 0.14.10 -across the six-file Python PR delta, pinned MyPy 1.13 and Bandit medium/high -across four production files, the 500-LOC changed-file gate, manifest parsing -plus all eight contracts, documentation governance, exact wire-tree -preservation, history/marker, and diff checks pass. - -This candidate is unpublished and `not_released`. Changing geometry or -velocity, internal transition-ledger export, regional UI, compiled or -TypeScript regional physics, UpstreamDrift parity, protected exact-head CI, -review, approval, dependency integration, and release remain open. - -## 2026-08-11 Current skid/roll parent reconciled into PR #4332 - -Open draft PR `#4332` retains branch -`feat/4271-regional-surface-transitions` and base -`feat/4271-ground-skid-roll`. Exact remote regional-surface child -`04ccf08dd990de1cd056a3420e67772773a4be2e` is merged first and exact current -skid/roll parent `3f861c1faaa7455faee92eaa7f813174667208e0` second by an ordinary no-ff -merge. The child's bounded coplanar overlays, exact transition splitting and -evidence, regional production, tests, fixtures, contracts, and limitations -remain intact with both append-only handoff and specification histories. - -Focused local qualification is green: all `121` Python ground/regional tests, -`20` focused React ground-contract/transfer tests, and all `137` `tools-core` -Rust tests pass. TypeScript, zero-warning ESLint, the 189-module Vite build, -Rust workspace format and warning-denied clippy, pinned Ruff 0.14.10 across the -14-file Python PR delta, pinned MyPy 1.13 and Bandit medium/high across 12 -production files, the 500-LOC changed-file gate, manifest parsing plus all -eight contracts, documentation governance, exact regional-tree preservation, -history/marker, and diff checks pass. - -This candidate is unpublished and `not_released`. Changing normals, -discontinuous geometry or surface velocity, regional UI, compiled regional -physics, UpstreamDrift parity, protected exact-head CI, review, approval, -dependency integration, and release remain open. - -## 2026-08-11 Current impact/bounce parent reconciled into PR #4304 - -Open draft PR `#4304` retains branch `feat/4271-ground-skid-roll` and base -`feat/4270-ground-impact-bounce`. Exact remote skid/roll child -`0ea6740965068542e9d8c7449e06ec07d88969e0` is merged first and exact current -impact/bounce parent `62beb3e1aa951645fd556a53f9cbae4bb46c47e5` -second by an ordinary no-ff merge. The child's arbitrary-plane skid, pure roll, -rolling resistance, rest, edge localization, strict result composition, -passive ledgers, fixtures, tests, and limitations remain intact with both -append-only histories. - -Local verification is green: `154` focused ground/flight physics and contract -tests plus all eight campaign-manifest tests pass, as do all `137` `tools-core` -Rust tests. Pinned Ruff 0.14.10 check/format covers all 18 PR-delta Python files; -pinned MyPy 1.13 and Bandit medium/high cover all 12 production files. Rust -format and warning-denied clippy, manifest parsing/validation, documentation -governance, exact skid/roll-tree preservation, marker/history, and diff checks -pass. - -This local candidate is not published or released. Regional/changing-normal -surfaces, deformation, torsional damping, roll-to-skid transitions, UI, -compiled physics, protected exact-head CI, review, approval, downstream -integration, and release remain open. - -## PR #4302 corrected-flight-transfer propagation - -Draft PR #4302 remains on `feat/4270-ground-impact-bounce` with unchanged base -`feat/4269-flight-ground-transfer`. Exact corrected #4288 parent -`247215422a6d4b677552955b4923bc609a553259` is incorporated by the normal merge -containing this handoff. The child preserves its passive restitution/Coulomb -sphere-plane impulse, deterministic repeated ballistic hops, exact physical -contact, capture-to-skid handoff, cancellation/failure semantics, and airborne -segment evidence while inheriting the corrected transfer ancestry, deterministic -workspace timestamps, and canonical `swing_sim` import identity. No branch was -rebased, retargeted, rewritten, or force-pushed. - -The slice remains partial and `not_released`: issue #4271 retains skid, roll, -rest, total distance, and final `GroundSimulationResult`; terrain deformation, -UI execution, TypeScript bounce physics, compiled Rust/PyO3/WASM bounce parity, -and UpstreamDrift adapters remain excluded. Protected CI, independent review, -and dependency-ordered collapse remain separate release gates. - -Merged-tree validation is `987` Python tests, `106` React files / `661` tests, -and the complete `tools-core` Rust suite at `137` tests (`111` unit, `20` -transfer, `6` wire). The affected cross-version suite is also `146` tests on -real CPython 3.10.20. The 189-module Vite production build, TypeScript, -zero-warning ESLint, Ruff check/format across 90 files, pinned mypy 1.13 across -all 17 ground and nine transfer production modules, Rust workspace format plus -warning-denied `tools-core` clippy, campaign-manifest validator plus eight -contracts, documentation governance, 11-file 500-LOC budget, marker scan, and -diff checks are clean. Hosted checks and review apply to the new exact merge -head only. - - -## PR #4288 corrected-ground propagation - -Draft PR #4288 remains on `feat/4269-flight-ground-transfer` with unchanged -base `feat/4268-ground-contract`. Exact corrected #4285 parent -`788aa547651a3685a363ea401824a5d81477bafb` is incorporated by the normal merge -containing this handoff. The child preserves its signed terminal state, -physical sphere/terrain contact brackets, strict provenance, and qualified -Python/TypeScript/Rust/PyO3/WASM transfer while inheriting deterministic -workspace timestamps and canonical `swing_sim` import identity. No branch was -rebased, retargeted, rewritten, or force-pushed. - -This propagation adds no bounce, skid, roll, terrain response, total distance, -or UI execution. Protected CI, independent review, and dependency-ordered -collapse remain separate release gates. - -Merged-tree validation is `951` Python tests, `106` React files / `661` tests, -and `26` focused Rust transfer/wire tests. The affected cross-version suite is -also `110` tests on real CPython 3.10.20. The 189-module Vite production build, -TypeScript, zero-warning ESLint, Ruff check/format across 82 files, pinned mypy -1.13 across the six-file transfer and 13-file parent production namespaces, -Rust workspace format plus warning-denied `tools-core` clippy, campaign-manifest -validator plus eight contracts, documentation governance, 13-file 500-LOC -budget, marker scan, and diff checks are clean. Hosted checks and review apply -to the new exact merge head only. +## 2026-08-11 PR #4342 append-only preservation repair -> Update this file in every implementation commit and every push to `main`. -> Last updated: 2026-08-11. +Independent audit of local merge `e7fedfb18de1550eed3484ed2fc99d0baaecdca1` +found that three older parent ancestry sections had been summarized instead of +retained verbatim. This docs-only follow-up restores the full parent text below +without changing production code, tests, schemas, manifest state, PR base, or +release claims. The exact parent sections and SPEC rows are now governed by +byte-for-byte comparison against +`d21741e312b849a63f73cabf351a15d9de80fb94`. ## 2026-08-11 PR #4335 current-parent ancestry candidate @@ -287,67 +153,6 @@ now records open PR #4332 at its still-published child head and open PR #4304 at its exact newly published parent head; neither record claims protected or main-release evidence. -## 2026-08-11 Current flight-transfer parent reconciled into PR #4302 - -Open draft PR `#4302` retains branch `feat/4270-ground-impact-bounce` and base -`feat/4269-flight-ground-transfer`. Exact remote bounce child -`cf6e72bad98e5f36f782254942e6895b8b71e670` is merged first and exact current -flight-transfer parent `c39297d37a17d5d8d3520ed62c5563cdcc609cab` second by an -ordinary no-ff merge. Passive impact/restitution/friction, deterministic -repeated bounce, exact contact, capture-to-skid handoff, bounded failure and -cancellation, and all transfer production, tests, fixtures, and limitations -remain intact. Both append-only histories are retained. - -The exact PR delta also receives the three AST-equivalent layouts required by -the repository-pinned Ruff 0.14.10 formatter; no analysis, persistence, or -contract assertion behavior changes. - -Local verification is green: `1129` Rate/ground/flight Python tests, `25` -focused React transfer tests, and all `137` `tools-core` Rust tests pass. -TypeScript, zero-warning ESLint, the 189-module Vite build, Rust format and -warning-denied clippy, pinned Ruff 0.14.10 check/format across the 14-file PR -delta, pinned MyPy 1.13 across eight production files, Bandit medium/high, -campaign-manifest parsing, documentation preservation, and diff checks pass. - -This local candidate is not published or released. Skid, roll, rest, total -distance, final ground results, UI, TypeScript bounce physics, and compiled -bounce runtimes remain open, as do protected exact-head CI, independent review, -approval, dependency integration, and release. - -## PR #4285 workspace timestamp propagation - -Draft PR #4285 remains on `feat/4268-ground-contract` with unchanged base -`feat/4197-capability-observer`. Exact corrected #4282 carrier -`5f77af4add23547a21cc3fabce98ae9ad4260427` is incorporated through the normal -merge containing this handoff. No branch was rebased, retargeted, rewritten, -or force-pushed. - -The child retains its strict, UI-neutral flight-to-ground schemas, canonical -fixture, migrations, legacy-result adapter, explicit dependency, and pinned -typing repairs while inheriting the deterministic Python 3.10-3.12 UTC parser -and the corrected variation, scalar, wind, capability, and campaign-release -ancestry. This merge does not claim bounce, skid, roll, terrain profiles, -total distance, UI execution, or Rust/WASM delivery. Protected CI, review, and -normal descendant propagation remain separate release gates. - -Exact-head CI on the preceding child head exposed an actionable collection -defect after installing the package: embedded `src.shared.python.swing_sim` -tests and canonical `shared.python.swing_sim` imports could load distinct -package trees, making the ground and impact subpackages unavailable by import -order. The shared alias registry now coalesces `swing_sim`; an isolated RED/GREEN -identity contract and both affected public-API suites pin the correction. The -separate file-size job was cancelled during checkout and did not execute its -budget check, so it remains infrastructure evidence rather than a source -failure. - -Merged-tree evidence is `915` Rate/ground/impact Python tests, the `12`-test -shared-alias architecture suite, `28` focused ground/impact/alias tests on -CPython 3.12, `28` direct compatibility tests on real CPython 3.10.20, and -`104` React files / `642` tests. The 188-module Vite build, TypeScript, -zero-warning ESLint, Ruff, format, pinned mypy 1.13, campaign-manifest -validation plus eight contracts, documentation governance, the 44-file -500-LOC budget, conflict-marker scan, and diff checks are clean. - ## 2026-08-11 PR #4304 current-parent ancestry candidate The clean dedicated `feat/4271-ground-skid-roll` worktree first fast-forwarded @@ -370,6 +175,180 @@ the official changed-file 500-LOC budget, and mandatory production limits of local merge is a PUBLISH candidate for independent review only; protected exact-head CI, approval, normal child propagation, and publication remain open. + +## 2026-08-11 PR #4342 current-parent reconciliation candidate + +The clean `feat/4274-regional-plan-io` worktree normally merges exact +published PR #4342 child `8e1c7ccd99a7c4886c5fb9ccc7e4d94a6d7e3833` +with exact newly published PR #4339 parent +`d21741e312b849a63f73cabf351a15d9de80fb94` as its second parent. PR #4342 +continues to target `feat/4274-regional-surface-ui`; neither branch is rebased, +retargeted, rewritten, force-pushed, or published by this reconciliation. +The merge preserves strict regional request import/export together with the +parent's frozen engineering-number specification and bounded helper. + +The child widget module now delegates its canonical-precision controls to that +shared three-parameter helper while retaining the inclusive cross-runtime safe +number bounds and eleven-decimal presentation required by its I/O contract. +Merged-tree qualification is 53 focused Python/PyQt/shared-ground tests and 14 +focused React tests passing. Pinned Ruff 0.14.10 check/format, MyPy 1.13 over +all ten affected production modules, Bandit medium/high screening, TypeScript, +zero-warning ESLint, and the 199-module production build pass. Campaign +manifest validation and all eight manifest tests, documentation and tool +manifest governance, changed-Python, minimum-test, exact-diff assertion, +500-LOC, parent/child diff, and whitespace gates pass. Mandatory structural +maxima are 396 module lines, 40 function lines, and three parameters. +The local merge is not protected or release evidence. Independent review, +ordinary fast-forward publication, fresh protected CI/approval, dependency +integration, and release remain required. + +## 2026-08-11 PR #4339 structural helper repair candidate + +This parent follow-up descends exact independently reviewed reconciliation +candidate `eedad6d23b517eb4c99d4ba9000ff6555101099f`. Independent review found +one publication blocker: the regional PyQt number-input helper accepted six +parameters, above the campaign's mandatory four-parameter limit. RED-first +tests bind the helper's signature and all observable widget settings. A frozen +`NumberInputSpec` validates finite positive step and finite ordered bounds +before widget construction; the three-parameter helper preserves field names, +values, units, ranges, increments, tooltips, and presentation order. + +Eight focused Python/PyQt tests and 25 focused React tests pass; the complete +React suite passes all 108 files / 672 tests. Pinned Ruff check/format, MyPy, +Bandit medium/high screening, TypeScript, zero-warning ESLint, +documentation/manifest governance, changed-production, test-assertion, +minimum-test, 500-LOC, and diff gates pass. Mandatory maxima are 400 module +lines, 42 function lines, and three parameters. No schema, digest, regional +physics, UI behavior, PR base, protected evidence, or release boundary changes. + +## 2026-08-11 PR #4339 current-parent ancestry candidate + +The clean `feat/4274-regional-surface-ui` worktree normally merged exact +published child `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` with exact published +#4335 parent `9e01ccc3e891cc45907293751a192624195a77a5`, while preserving +#4339's `feat/4271-regional-wire-contract` base. Production UI, contract, +resolver, regional physics, and ground ancestry merged without conflict; only +SPEC, manifest, and handoffs were reconciled. Independent review, ordinary +publication, protected exact-head CI/approval, dependency integration, and +release remained open. + +## 2026-08-11 PR #4342 delta-MyPy follow-up + +Protected CI on exact PR #4342 head +`cffe349ac0a8054f1d168cb36684fd00bc5f8a49` identified one redundant `bool` +cast in the regional atomic-write adapter under the Linux delta-MyPy gate. The +cast is removed; the typed helper's direct Boolean return is preserved. This +changes no wire bytes, validation, file semantics, UI behavior, or physics. +Focused persistence tests and the CI-equivalent pinned MyPy command pass +locally; fresh protected CI/review and dependency ordering remain required. + +## 2026-08-11 regional request I/O protected publication + +Branch `feat/4274-regional-plan-io` is published normally as draft PR +[#4342](https://github.com/D-sorganization/Tools/pull/4342), targeting exact +PR #4339 branch `feat/4274-regional-surface-ui` at parent head +`cbb9c0a6bdc6a50f59f7a661139b9d53e1892980`. Its reviewed implementation +head is `d748e7a5ef3da5e6ce7737ff6829e0f14665fe97`; publication commits change +no runtime behavior. Protected CI, independent review, issue #4274, parent +ordering, integration, and release remain open. + +## 2026-08-11 bounded regional request read follow-up + +Independent review of local safe-number commit +`10c394f6b1fd2927e7f3b1f96cc097cae6bfd380` found that native request import +checked file size with `stat()` and then performed a separate unbounded text +read. A concurrently grown or replaced file could therefore allocate beyond +the 1 MiB wire cap before the strict parser rejected it. + +Native import now opens one binary handle, reads at most the wire cap plus one +sentinel byte, rejects overflow, strictly decodes UTF-8, and only then delegates +to the unchanged canonical v1 parser. Tests simulate content growth after the +metadata check and reject invalid UTF-8 explicitly. The complete regional and +atomic persistence set is 28 tests passing. This changes no schema, digest, +physics, browser behavior, or write semantics. Static and governance evidence +is recorded in this commit: Ruff, Ruff format, Black, focused MyPy, manifest, +module-size, documentation-governance, and diff checks pass. The child remains +local and unprotected. + +## 2026-08-11 regional request I/O safe-number follow-up + +Independent review of local commit `e39edf4b50b1fb9811b0032bec4758c7a08c9b74` +found two cross-runtime representation gaps. The PyQt6 precedence spin box +silently narrowed otherwise valid v1 integers above 1,000,000, and Python +accepted integer-valued wire numbers above JavaScript's exact safe range. + +The native editor now uses an exact decimal integer entry for precedence and +preserves every v1 value from zero through 9,007,199,254,740,991 without a +floating-point conversion. Shared Python canonical-number and ground-record +validation now reject magnitudes outside that same range, matching React while +retaining all finite fractional values inside it. PyQt6 floating-point editors +publish the same bounds. Regression coverage pins exact maximum-precedence +open/save round-trip and matched native/browser refusal of unsafe material +numbers. This changes no schema version, provenance algorithm, physics, or +browser filesystem limitation. Final local evidence is 132 shared ground tests, +21 regional editor/I/O tests, five atomic-workspace tests, 23 focused React +tests, the whole-shell tooltip sweep, and eight manifest tests passing. Ruff, +Ruff format, Black, focused MyPy, TypeScript, zero-warning ESLint, the 199-module +production build, module and changed-file size budgets, documentation +governance, and diff checks pass. The child remains local and unprotected. + +## 2026-08-10 PR #4339 stale-validation invalidation follow-up + +Rendered exact-head browser QA found that a validated one-overlay readback +remained visible after adding a second overlay. The broad PyQt6 suite also +found missing hover hints on the new controls. PyQt6 and React now clear both +canonical readback and prior validation state whenever any identity, interval, +material, or overlay-row draft value changes; PyQt6 exposes the explicit +"Changes not validated" pending state, and every PyQt6 interactive has a +specific engineering-context tooltip. RED-first regression tests cover the +dynamic-row path on both surfaces. Final local evidence is 870 Python/PyQt +tests and 672 React tests passing; Ruff, format, MyPy, TypeScript, zero-warning +ESLint, the 198-module production build, manifest/docs/file-size governance, +and diff checks are clean. The known polynomial-generator empty-legend warning +is unrelated. This changes no wire schema, provenance digest, physics, or +persistence boundary; fresh protected CI is still required before merge. + +> Update this file in every implementation commit and every push to `main`. +> Last updated: 2026-08-11. + +## 2026-08-10 issue #4274 canonical regional request I/O local child + +Local branch `feat/4274-regional-plan-io` started directly from published PR +#4339 head `a9ace5052bcd54b78f79b62d5d9ac26debedb4b1`, then fast-forwarded +normally to corrected exact parent `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980`. +The parent's stale-validation invalidation and tooltip follow-up are preserved. +This child has not been pushed, opened as a PR, reviewed, merged, or released. + +The matched Ground Surfaces editors now import and export the canonical +`ground-regional-material-plan-request/v1` document. PyQt6 uses native Open +and Save As dialogs plus a shared flush/fsync/atomic-replace UTF-8 writer; +cancel is a no-op, failed reads and writes preserve the last-known-good editor +or file, and the recent path advances only after success. React validates a +bounded browser File before committing state and downloads exact canonical +bytes while revoking its object URL. Browser filesystem limitations are +explicit, and workspace persistence remains separate. + +Import accepts only editor producer/provider v1 evidence, the fixed target +frame origin/downrange axis, and one to eight rows. It never relabels external +evidence. An unchanged import round-trips the exact request and provenance; +after any edit, validation binds a fresh draft digest. No measured calibration +is synthesized and neither path executes physics. + +RED-first coverage now includes exact-byte round-trip, native cancel and +atomic rollback, corruption, duplicate keys, oversize input, unsupported +producer/axis qualification, stale-provenance rebinding, transactional PyQt6 +population, browser rollback, URL cleanup, and pre-allocation size rejection. +Focused evidence is 25 Python/PyQt tests and 12 React tests passing. With +adjacent wire and manifest coverage, 44 Python and 16 React tests pass. +Focused MyPy, Ruff, TypeScript, zero-warning ESLint, the 199-module production +build, release-manifest validation, and module budgets are clean. + +Issue #4274 remains open. Measured calibration, workspace model-input +persistence, execution/playback, result interchange, visualization, changing +geometry, compiled regional physics, downstream parity, protected CI/review, +integration of this child into the protected stack, and release remain explicit +gaps. + ## 2026-08-10 issue #4274 matched regional surface editor local child Local branch `feat/4274-regional-surface-ui` started from published PR #4335 @@ -544,751 +523,6 @@ All `115` ground tests, Ruff, formatting, a finding-free local scan of the affected file, documentation governance, the `370`-line source-size check, and diff gates pass before an ordinary guarded fast-forward publication. Fresh protected CI and review remain required. -## 2026-08-11 Current ground parent propagated into PR #4288 - -Open draft PR `#4288` retains branch `feat/4269-flight-ground-transfer` and base -`feat/4268-ground-contract`. Exact remote transfer child -`df716ac740beb9d47dced66f867dc3dde1fa5367` is merged first and exact current -ground-contract parent `584e4e53a7990053a346938c4e45538786887ec7` -second by an ordinary no-ff merge. Flight-to-ground production, tests, fixtures, -cross-runtime contracts, Rust/PyO3/WASM integration, and explicit limitations -remain intact. Only append-only handoff/SPEC aggregation conflicts require -resolution; every dated record from both histories is retained. Focused gates -pass 85 Python contract/transfer tests, 25 React tests, and 137 Rust library and -transfer/wire tests. Pinned Ruff 0.14.10 covers all 13 PR-delta Python files, -pinned MyPy 1.13 covers nine production files, and Bandit reports no medium/high -findings. TypeScript, exact-delta ESLint, the 189-module web build, Rust format, -docs, strict manifest, diff, exact transfer-tree, and both-parent preservation -checks pass. Publication, protected exact-head CI, review, approval, and release -remain open. - -## 2026-08-11 PR #4288 append-only history preservation repair - -This documentation-only follow-up to exact local candidate -`1eb4188ff1a87a3d8e9a55aeca68194ca04e0bb4` restores the parent handoff -sections and specification rows omitted during conflict resolution. It also -repairs the interleaved rate-of-closure handoff paragraph without changing -production code, tests, schemas, the campaign manifest, merge topology, or PR -#4288's `feat/4268-ground-contract` base. Publication, protected exact-head CI, -approval, dependency integration, and release remain open. - -## 2026-08-11 PR #4288 current-ground-parent ancestry candidate - -The clean `feat/4269-flight-ground-transfer` reconciliation starts from exact -published child `afb1bdcfc6701caaf1f7bc3497a6a37dd9698c14` and normally merges -exact newly published #4285 parent -`e09ab96280cab363b36bd0e7db4a3cd064dc2527` second, while preserving #4288's -`feat/4268-ground-contract` base. The child's bounded TypeScript integrator, -signed terminal angular state, physical sphere/terrain contact, and cross-runtime -transfer remain authoritative; the parent's split kinetics, plotting catalog, -strict ground contract, and current wind/capability ancestry are retained. -Seven surviving child-owned Python files are normalized with pinned Ruff -0.14.10; this mechanical repair changes no AST. The TypeScript flight facade -also preserves the exact child program with repository-standard line endings. -Independent review, ordinary fast-forward publication, fresh protected CI, -approval, dependency integration, and release remain open. - -> Update this append-only handoff in every implementation commit and every push -> to `main`. -> Last updated: 2026-08-11 - -## 2026-08-11 Current capability carrier propagated into PR #4285 - -- Open draft PR `#4285` retains branch `feat/4268-ground-contract` and base - `feat/4197-capability-observer`. Exact remote child - `e09ab96280cab363b36bd0e7db4a3cd064dc2527` is the first parent and exact - published capability-observer carrier - `d0b827667e61f0583e1dad0b3cbbca6819624d3c` is merged second by an ordinary - no-ff merge. No branch is rebased, retargeted, force-pushed, or rewritten. -- Ground-contract production, tests, schemas, fixtures, dependencies, and - fail-closed limitations remain child-owned and intact. Only the four durable - handoff/SPEC files conflict; their dated records from both parents are - retained while the parent contributes the current wind/capability and release - ancestry. -- Focused verification is green: 214 strict-ground, impact, PyQt layout/GUI, - kinetics, capability, wind, and manifest tests pass. Pinned Ruff 0.14.10 - checks/formats all 27 PR-delta Python files, pinned MyPy 1.13 accepts all 20 - production files, and Bandit reports no medium/high findings. Docs governance, - strict campaign-manifest validation, diff hygiene, exact child ground-tree - preservation, and both-parent handoff/SPEC preservation pass. -- This is a bounded local audit. Publication, protected exact-head CI, review, - approval, and normal downstream propagation into #4288 remain open. - -## 2026-08-11 Current #4282 ancestry reconciled into PR #4285 - -- Draft PR `#4285` retains branch `feat/4268-ground-contract` and base - `feat/4197-capability-observer`. Exact remote child - `7a38b9838d743e051a6900620c4d6e754582aa89` is the first parent; exact - published workflow/base head `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` - is merged second. The latter contains merged #4283 head - `9bbb98e16e435a0d4c74153b909f2ebfefbbce7a`, so dependency order is - preserved without rebase, retarget, force-push, or parent rewrite. -- The strict flight-to-ground schemas, migrations, fixture, legacy adapter, - dependency declarations, and Python 3.10 compatibility remain intact. The - inherited parent adds its current wind/capability stack, Ground/Tee parity, - split kinetics facade, and pinned formatting repairs. -- The only source conflict was the child's formatting-only pre-split kinetics - hunk; it resolves wholly to the validated parent facade. Four append-only - handoff/SPEC histories are retained and the campaign manifest records the - exact published heads that this unpublished candidate composes. -- The child-owned scalar extractor's required `float` narrowing made the - 459-line plotting registry part of the effective delta. Ordered catalog data - now lives in small private scalar/series collaborators; the public catalog is - 61 lines and every changed production module/function/signature satisfies - the strict 400-line/50-line/four-parameter limits without changing keys, - order, extractors, units, or public objects. -- Local verification passes the complete 1,539-test Rate/shared-swing Python - matrix with one explicit optional Rust-wheel skip, all 648 React tests across - 106 files, TypeScript, zero-warning ESLint, the 188-module Vite production - build, and 12 `swing-core` Rust tests. Focused ground/parity/kinetics/wind/ - manifest and catalog/plot suites pass 146 and 57 tests respectively. -- This is a local publication candidate only. Independent review, ordinary - publication, fresh exact-head protected CI, required approval, and normal - downstream #4288 propagation remain mandatory. - -## 2026-08-11 merged #4283 carrier receives current #4282 - -- PR `#4283` is already merged, but its preserved head branch - `feat/4197-capability-observer` remains the live base of open draft PR `#4285`. - Exact remote/local carrier child - `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is merged first with exact newly - published #4282 head `3faf9e9493c9ba37168d9f65ab10cafeedc2a72f` - second by a normal no-ff merge. No PR is reopened, retargeted, or merged, and - no branch history is rewritten. -- Because the carrier child is already the first parent of #4282, the source - merge is conflict-free and reproduces the exact #4282 implementation while - preserving the complete capability-observer history. This carrier record is - the only intentional tree delta from #4282. -- Focused validation is green: 86 Python/PyQt capability, wind, and campaign- - manifest tests pass, as do all 86 tests in 12 focused React capability/wind - suites. React type-check, zero-warning lint, and the production build pass. - Docs governance, strict campaign-manifest validation, and exact-parent diff - hygiene pass. The exact tree delta from #4282 contains documentation only, so - changed-Python Ruff/MyPy/Bandit gates are not applicable. -- Publication is explicitly outside this bounded audit; - protected current-head checks and ordinary dependency propagation into #4285 - remain separate future actions. - -## 2026-08-11 current scalar-adapter propagation into wind workflow PR #4282 - -- PR `#4282` remains on `feat/4199-wind-workflow`, based on - `feat/4199-wind-scalar-adapter`. Exact published child - `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is merged first with exact newly - published parent `9321c1d2e091b8c7e5a4a83aa9ad726290e7fb5a` second by a - normal merge; no rebase, retarget, force-push, or parent rewrite is used. -- All implementation and test paths merge automatically. The child responsive - PyQt6/React wind workflow, execution/progress/cancellation, persistence, - export, consolidated capability stack, and strict campaign manifest remain - authoritative while inheriting the parent's current wind scalar-adapter, - variation, workspace, launch-monitor/D-plane, split-kinetics, and Qt repairs. - Only append-only handoffs and SPEC conflict textually; both histories remain. -- Focused pre-commit regression is green: all 94 focused Python/PyQt wind, - responsive-layout, navigation, playback, and manifest tests pass, and all 44 - tests in eight focused React wind/responsive suites pass. Docs governance and - strict campaign-manifest generation/validation also pass. -- Exact post-commit PR-delta gates are also green: pinned Ruff 0.14.10 checks - and formats all 57 changed Python files, pinned MyPy 1.13.0 accepts all 38 - changed production files, and pinned Bandit 1.7.7 finds no medium/high issues - in 37 scanned source files. The 500-LOC budget, changed-Python policy, - minimum-test contract, changed-test assertions, diff hygiene, React - type-check, React lint, and production web build all pass. -- This candidate remains local pending independent review, ordinary publication, - protected exact-head CI, unresolved-thread checks, and dependency order. - -## 2026-08-11 Exact #4281 parent propagation into PR #4282 - -- Draft PR `#4282` remains on `feat/4199-wind-workflow`, based on - `feat/4199-wind-scalar-adapter`. Exact remote child - `29e15d6ff631f7f30afcc745be783f2e716d7dcf` normally merges exact published - parent `a7dce5f89b483303938f518b74b4028a1c68ba81` in child-first order without - rebase, reset, retarget, force-push, or parent rewrite. -- The responsive PyQt6/React wind workflow and consolidated capability stack - remain intact while inheriting the parent's split kinetics facade, Ground/Tee - parity, scalar-adapter module/parameter repair, and complete prior stack. -- The sole source conflict is the child's obsolete formatting-only edit to the - pre-split kinetics monolith; the validated parent facade is authoritative. - Four documentation conflicts retain both append-only histories. Seven - child-owned files require the pinned Ruff formatter before publication. -- The exact skipped-import MyPy profile makes the facade cache suppression - redundant; an explicit `KineticsSeries | None` cast preserves the runtime - object while satisfying the static boundary without an ignore. -- Local evidence is 74 focused Python/PyQt wind, kinetics, and Ground/Tee - tests; 29 focused React tests; and 8 campaign-manifest tests. TypeScript, - focused zero-warning ESLint, Ruff check/format, pinned MyPy 1.13, Bandit's - medium/high threshold, strict wind module/signature/function budgets, - manifest, documentation, policy, SPEC, and diff gates pass. -- This is a local reconciliation candidate. Independent review, fresh - exact-head protected CI, unresolved-thread checks, dependency order, and - ordinary publication remain required. -## 2026-08-11 current variation propagation into wind PR #4281 - -- PR `#4281` remains on `feat/4199-wind-scalar-adapter`, based on - `feat/4144-variation-export-continuation`. Exact published child - `a7dce5f89b483303938f518b74b4028a1c68ba81` is merged first with exact newly - published parent `e6c7460a01082631565fb9ed48aa32538bd7772c` second by a - normal merge; no rebase, retarget, force-push, or parent rewrite is used. -- All implementation and test paths merge automatically. The child - Python/TypeScript scalar-ensemble, deterministic-scenario, wind-strategy - adapter, and strict module-budget behavior remain authoritative while - inheriting the parent's current variation, workspace, launch-monitor/D-plane, - split-kinetics, and Qt typing repairs. Only append-only handoffs and SPEC - conflict textually; both histories remain below. -- Focused pre-commit regression is green: all 77 focused wind/variation Python - tests pass, and all 20 tests in the five focused React wind/variation suites - pass. -- Exact post-commit PR-delta gates are also green: pinned Ruff 0.14.10 checks - and formats all five changed Python files, pinned MyPy 1.13.0 accepts all - three changed production files, and pinned Bandit 1.7.7 finds no issues in - those three files. Both 500- and strict 400-LOC budgets, docs governance, - changed-Python policy, minimum-test contract, changed-test assertions, diff - hygiene, React type-check, React lint, and the production web build all pass. - The manifest artifact/checker/test do not exist on either side of this - pre-manifest stack, so that later release gate is structurally not applicable. -- This candidate remains local pending independent review, ordinary - publication, protected - exact-head CI, unresolved-thread checks, and dependency order. -## 2026-08-11 PR #4281 wind adapter module-budget repair - -- The 403-line `wind_strategy_plot_adapter.py` blocker is repaired by moving - request/analysis validation into the private - `_wind_strategy_plot_validation.py` collaborator. The public adapter is now - 252 lines and the validator is 213 lines; both are below the mandatory - 400-line ceiling. -- The scenario validator accepts the scenario plus one frozen, slotted - expectation object. No production function exceeds four parameters or 50 - lines. -- `build_wind_strategy_plot_dataset`, `WIND_STRATEGY_*` exports, validation - messages, variable/stage/category/cohort order, row identity, scalar values, - availability, attributes, and the no-flight-rerun boundary are unchanged. -- This is a local candidate only. Independent review, fresh exact-head - protected CI, unresolved-thread checks, dependency order, and ordinary - publication remain required before merge or release. - -## 2026-08-11 reviewed variation parent propagation into wind PR #4281 - -- Exact remote wind child `247046d55afcad3e6cd4f8029f854856c427f59c` - normally merges exact reviewed variation parent - `3337945699966b63cb5cd8e52d7c3b194315e911` in child-first order. PR base, - stack topology, and both histories remain intact; no rebase, reset, retarget, - force-push, or parent rewrite is used. -- Python/TypeScript scalar-ensemble and wind-strategy plot-adapter behavior is - unchanged while inheriting the parent's variation/export UI, kinetics split, - Ground/Tee parity, workspace/toolstrip, and Ruff-normalized repairs. The sole - feature-code conflict was obsolete monolithic kinetics and is resolved to the - validated parent `pendulum.sample(...)` facade. -- This reconciliation is local only. Independent review, fresh exact-head CI, - unresolved-thread checks, dependency order, and ordinary publication remain - required before merge or release. -## 2026-08-11 current workspace propagation into variation PR #4280 - -- PR `#4280` remains on `feat/4144-variation-export-continuation`, based on - `feat/4218-toolstrip-workspace`. Exact published child - `3337945699966b63cb5cd8e52d7c3b194315e911` is merged first with exact newly - published parent `efbca84095b617b4018732f7802c2da3f0525387` second by a - normal merge; no rebase, retarget, force-push, or parent rewrite is used. -- All implementation and test paths merge automatically. The child variation - export, typed unavailable outcomes, bounded tables, linked selection, and - all-trial arc behavior remain authoritative while inheriting the parent's - current workspace, launch-monitor/D-plane ancestry, split kinetics, and Qt - typing repairs. Only append-only handoffs and SPEC conflict textually; both - histories remain below. -- Focused pre-commit regression is green: all 56 focused Python variation tests - pass, and all 10 tests in the three focused React variation suites pass. -- Exact post-commit PR-delta gates against the new parent are also green: - pinned Ruff 0.14.10 checks and formats all five changed Python files, pinned - MyPy 1.13.0 accepts all four changed production files, and pinned Bandit - 1.7.7 finds no issues in those four files. Docs governance, 500-LOC budget, - changed-Python policy, minimum-test contract, changed-test assertions, diff - hygiene, React type-check, React lint, and the production web build all pass. - The manifest artifact/checker/test do not exist on either side of this - pre-manifest stack, so that later release gate is structurally not applicable. -- This candidate remains local pending independent review, ordinary - publication, protected - exact-head CI, unresolved-thread checks, and dependency order. -## 2026-08-11 reviewed workspace parent propagation into variation PR #4280 - -- Exact remote variation child - `668ba96746f79f7a12e8092161bd610054197f58` normally merges exact reviewed - workspace/toolstrip parent `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` - in child-first order. PR base, stack order, and both histories remain intact; - no rebase, reset, retarget, force-push, or parent rewrite is used. -- The variation/export feature remains unchanged while inheriting the current - kinetics split, Ground/Tee parity contracts, protected Ruff normalization, - and complete workspace/toolstrip behavior. The sole feature-code conflict - was obsolete monolithic kinetics source and is resolved to the validated - parent façade. Seven duplicate child automation edits fail protected Ruff - 0.14.10 formatting and are normalized to the exact reviewed parent blobs; - the automation commit remains reachable in the child-first history. -- This reconciliation is local only. Independent review, fresh exact-head - protected CI, unresolved-thread checks, dependency order, and ordinary - publication remain required before merge or release. -## 2026-08-11 current #4203 propagation into workspace PR #4279 - -- Draft PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base - `feat/4181-launch-monitor-registry`. Exact published child - `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` is merged first with exact - newly published parent `7abce9ad767fe8311da66a1e5998b892ea3ca9de` - second by a normal merge; no rebase, retarget, force-push, or parent rewrite - is used. -- All implementation paths merge automatically. The child workspace, - toolstrip, visibility, navigation, playback, and independent-plot behavior - remain authoritative while inheriting the parent's split kinetics and four - behavior-preserving Qt primitive-return boundaries. Only append-only - handoffs and SPEC require textual reconciliation, and both histories remain - below. -- Focused pre-commit regression is green: all 142 exact PR-delta Python tests - pass, and all 32 tests in the eight changed React suites pass. Exact - post-commit PR-delta gates against the new parent are also green: pinned Ruff - 0.14.10 checks and formats all 27 changed Python files, pinned MyPy 1.13.0 - accepts all 18 changed production files, and pinned Bandit 1.7.7 finds no - medium/high issues in those 18 files. Docs governance, 500-LOC budget, - changed-Python policy, minimum-test contract, changed-test assertions, diff - hygiene, React type-check, React lint, and the production web build all pass. - The manifest artifact/checker/test do not exist on either side of this - pre-manifest stack, so that later release gate is structurally not applicable - to this propagation. -- This candidate remains local pending independent review, ordinary - publication, protected - exact-head CI, unresolved-thread checks, and dependency order. -## 2026-08-11 remote automation reconciliation for workspace PR #4279 - -- Exact local workspace head `0b22c401a26c31441a599d8d9b39de123706e7ea` - ordinarily merges exact remote head - `61fe2d556a5413e525d958612ccfd57e65b8d5a2`, preserving both histories and - the existing PR base `feat/4181-launch-monitor-registry` without rebase, - reset, retarget, force-push, or parent rewrite. -- The remote commit is a broad formatting-only automation sweep. Fifteen of - its 23 paths, including six pre-existing `.codex-worktrees` gitlinks, were - already byte-identical in the current parent. Its seven unique formatting - edits did not match protected Ruff 0.14.10 output and are normalized back to - the pinned form. Its sole content conflict was obsolete pre-split kinetics - code; the current `pendulum.sample(...)` façade implementation remains - authoritative, preserving the parent split and runtime behavior. -- Workspace/toolstrip, module visibility, navigation, playback, independent - plots, physics, frames, units, schemas, and public contracts remain intact. - This history-preserving local reconciliation still requires independent - review, exact-head protected CI, unresolved-thread checks, and dependency - gates before publication or merge. - -## 2026-08-11 hosted MyPy repair propagation into workspace PR #4279 - -- Exact workspace child `7806a16f58e1c6999d32f0127a187fbb21f839a1` - normally merges exact published parent - `3796b49e40b677fbac4e05739f8be49f905df2cb`; PR base, stack order, and - both histories remain unchanged. -- The inherited production delta is limited to four static - `numpy.ndarray` casts in the kinetics façade, series, and dynamics modules. - Workspace/toolstrip behavior and runtime arrays, physics, units, frames, - public identity, and UI behavior are unchanged. -- This merge is local only. Fresh exact-head protected CI, required review, - unresolved-thread checks, and dependency gates remain release blockers. - -## 2026-08-11 latest #4203 propagation into workspace PR #4279 - -- Exact parent `0216a547aa79727091a2939b96e779e8ddbd7304` is normally merged into - child `61b7f48b5aeb7d57246b4963da3df086e79cbe15` without changing PR base, - stack order, or either history. -- No feature-code conflict exists. The workspace/toolstrip, visibility, - navigation, playback, and plot controls remain intact while the child - inherits the parent's pinned formatting and identity-preserving kinetics - size-budget repair. -- This merge is local only. Fresh exact-head protected CI, review, unresolved - threads, and dependency gates remain required before publication or merge. - -## 2026-08-11 #4203 append-only SPEC preservation repair - -The first independent audit of local reconciliation candidate `e20b4f630...` -found four exact D-plane parent rows omitted from the append-only SPEC history: -2026-08-10 versions 1.13.11, 1.13.9, 1.13.7, and 1.13.6. They are restored -verbatim in the current documentation-only follow-up. Production code, tests, -merge parents, PR base, and local quality evidence are unchanged. Independent -re-review, ordinary publication, protected CI, and downstream propagation -remain open. - -## 2026-08-11 #4203 current D-plane parent reconciliation - -- Draft PR #4203 now requires a normal merge of exact current base - `f3363aa88868f6a5c7e9ccfc682a9eca014e86c1` after exact published child - `217e36dc93d30f79826847f958fbcd10805e58ed`; its base remains - `feat/4189-dplane` and no history is rewritten. -- The parent changes nine files. Its sole textual conflict is an inherited - kinetics formatting edit. The already reviewed split kinetics facade stays - authoritative and uses the typed `DoublePendulumSwing` object directly; - the parent's explanatory geometry comment is retained. -- Exact CI-pinned MyPy 1.13 validation then exposed four remaining Qt stub - boundaries in the child delta. Responsive-event handling, legend visibility, - ball-setup event filtering, and status text now narrow their unchanged Qt - return values to the declared primitive contracts. -- Focused regression, full PR-delta quality gates, independent review, normal - fast-forward publication, and fresh protected exact-head CI remain required. - -## 2026-08-11 #4203 exact-head format completion - -- Protected CI on exact published head - `7d69a545ae555679f0318940e67c1786626d6794` failed only Ruff formatting. - Reproducing the exact pinned 0.14.10 check found eleven noncompliant changed - Python files: four inherited files plus seven altered by the automated - pre-commit repair. -- The pending repair applies pinned Ruff formatting to exactly those eleven - files. AST equivalence and focused tests must pass before independent review - and ordinary fast-forward publication; no simulation, contract, or UI - behavior is intentionally changed. - -## 2026-08-11 #4203 hosted MyPy kinetics repair - -- Exact head `0216a547aa79727091a2939b96e779e8ddbd7304` failed CI Standard run - `31477542889`, job `93734652129`, at runtime merge ref `aede309`: NumPy's - typed API exposed four `no-any-return` findings in the newly extracted - kinetics modules. -- The repair narrows only the results of `numpy.linalg.norm`, - `numpy.concatenate`, and the app-frame matrix projection to the already - declared `numpy.ndarray` return contract. Explicit casts do not allocate, - convert, or change any array, physics, units, frames, public identity, or UI. -- RED evidence is the exact four hosted diagnostics at - `_kinetics_series.py:121/131`, `_kinetics_dynamics.py:194`, and - `kinetics.py:61`. GREEN evidence requires the complete PR-base changed-source - MyPy profile, not a three-file-only run, plus focused/full Rate regression and - normal protected CI after publication. -- Local GREEN evidence is 102/102 complete-delta MyPy source files, 141/141 - Ruff/format files, 101 Bandit source files with no medium/high finding, 28/28 - focused tests, and 701/701 full Rate tests. Size, documentation, minimum-test, - and diff gates also pass. -- This commit is local only. PR base, stack order, protected review, and the - paused #4279 parent propagation remain unchanged. - -## 2026-08-11 #4203 kinetics size-budget repair - -- Exact head `572bf525dd1ded26cbc3fbb4f228d1f6ca16e118` passes the PR-base - changed-file scan because `kinetics.py` is byte-identical to the inherited - parent, but the stricter `HEAD~1` scan selects the Ruff-formatted file and - fails it at 646 LOC against the ungrandfathered 500-LOC limit. -- The behavior-preserving LoD/DRY split leaves - `simulation/kinetics.py` as the stable 222-LOC public façade, moves pure - dynamics to `_kinetics_dynamics.py` (205 LOC), and moves the immutable - series/DbC contract to `_kinetics_series.py` (131 LOC). Public constants, - class/function objects, and the private `_reaction_forces` compatibility - seam are identity-pinned by a RED-first contract test. -- Physics, units, frames, numerical parity fixture, PyQt presentation, and - release-stack order are unchanged. This implementation is committed locally - only; no push, PR mutation, or release claim is authorized by this handoff. -- Verification includes 28 focused kinetics/presentation/PyQt tests and the - complete 701-test Rate-of-Closure Python suite, all passing locally. - -## 2026-08-11 #4203 pinned-Ruff formatting repair - -- No material handoff change: this commit only applies the repository-pinned - Ruff 0.14.10 formatter to the eight Python files named by current-head CI - Standard run `31468208320`, job `93705508050`. -- Physics, application behavior, public contracts, schemas, UI layout, stack - bases, and dependency order are unchanged. Fresh protected CI and review at - the resulting head remain required; queued runner jobs are not green - evidence. - -## 2026-08-10 #4143 child receives repaired #4203 parent - -- Ready PR `#4325` retains branch `feat/4143-tee-parity-fixture` and base - `feat/4181-launch-monitor-registry`; repaired parent head - `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` is incorporated through a - normal merge commit without rebasing, retargeting, or rewriting history. -- The merge tree has no production/test-code conflict. Both branches' - append-only handoff/SPEC evidence is retained, including the shared parity - fixture and deterministic web/PyQt visual evidence. -- Fresh exact-head protected CI and review remain required. #4143 stays open - until the dependency line lands on `main`. - -## 2026-08-10 #4143 Python/React Golden Ball-Setup Parity - -- Branch `feat/4143-tee-parity-fixture` starts from exact draft PR #4203 head - `31cbc007d4c85b5479b7cd0fb0969124eab2af67`; it does not rewrite or retarget - the release stack. -- `ball_setup_golden_v1.json` is the single Python/React source of truth for - schema `rate_of_closure.ball_setup_golden` version 1, SI metre units, and - reference `ground_plane_to_ball_bottom`. It pins Driver/Tee and iron/Ground - defaults, explicit overrides, Ground's zero effective tee height, derived - center geometry, serialization, negative and non-finite rejection, and - legacy-run migration to Ground. -- New consumer tests plus the existing tee suites pass: 18 Python tests and 24 - React tests. Web TypeScript, ESLint, and production Vite build gates pass; - scoped Ruff check and format pass. This is test/fixture-only and does not - change production physics or UI behavior. -- Deterministic 1600 x 1200 Playwright captures cover the default Driver/Tee - and rerun explicit-Ground React states with checked/disabled controls, - present/absent tee geometry, and zero console/page errors. A hidden 1400 x - 900 PyQt harness records the same states with canonical center and tee-artist - assertions; a headless regression keeps its temporary PNGs nonblank and - structurally distinct without pixel-perfect baselines. Artifact manifests - and SHA-256 digests are under - `C:\Users\diete\AppData\Local\Temp\rate-4143-visual-evidence-8050eeba`. -- Issue #4143 remains open for exact-head protected CI/review and release to - `main`. The strict campaign release manifest is not present on #4203's exact - history (it was introduced later on a divergent campaign branch), so this - bounded child records that limitation instead of reconstructing it. -## 2026-08-10 Repaired wind-scalar parent propagation - -## 2026-08-10 PR #4282 exact-head mypy repair - -Protected quality-gate run `31395741841`, job `93478091420`, checked merge ref -`ae75c4b006072b20a713e45b177defcc16a380fe` for exact head -`aa6eeffb0395f7ed7954f2315b1c625cada552d8`. Checkout, dependency install, -Ruff, and formatting passed; pinned mypy 1.13 then failed only -`scripts/rate_campaign_manifest.py:335:5 [no-any-return]`. Under the exact CI -`--follow-imports=skip` profile, Pydantic's `model_validate_json` return is -`Any`. The validated local now carries an explicit `CampaignManifest` type, -preserving runtime behavior without a redundant cast or suppression. Do not -retry or cite the obsolete failed head as passing. - -## 2026-08-10 Exact workspace-parent propagation into PR #4280 - -Draft PR `#4280` remains on `feat/4144-variation-export-continuation` with -base `feat/4218-toolstrip-workspace`. The normal merge starts from original -child head `f90836e342efc8be624739802375af2876d11e5f` and incorporates exact -published parent head `6717e9e09d507dbc24bedb36177f1cdf0b4fd90b` as -the second parent. No rebase, retarget, force-push, parent rewrite, or draft- -state change is permitted. - -The source merge is conflict-free: the child's selected-scatter CSV export, -typed unavailable values, accessible raw tables, linked selection, and focused -PyQt/React visualization modules remain intact alongside the parent's complete -workspace/toolstrip, playback, plot, navigation, Python 3.10, and module-budget -repairs. SPEC 1.14.12 records this combined child release above the unique -parent 1.14.11 entry. Staged review found and the continuation corrected one -release-blocking rerun defect: replacing a study after selecting a later trial -now clears linked selection atomically. Every PyQt public setter validates -against the current trial count, while React clears on result identity change -and shares only bounded selections, so a smaller rerun cannot crash or leave -all new points dimmed. - -Verification is green: 37 focused variation GUI/export tests and the complete -Rate/shared-swing/golf-club matrix passes 1,528 tests with two explicit -optional build123d skips; all -546 React tests pass across 90 files, as do TypeScript, ESLint, and the Vite -production build. Exact-parent Ruff, Ruff-format, Black, pinned MyPy 1.13 for -all four changed Python production modules, Bandit, the four-file 500-line gate, -docs, minimum-test, changed-test assertions, detect-secrets fingerprints, and -diff checks pass. CPython 3.10.20 compiles all changed Python files, and 30 -compatibility/date-boundary regressions pass. There is no Rust delta from the -exact parent, whose 12-test `swing-core` evidence remains applicable. -Independent staged re-review found no actionable findings after verifying the -atomic result-identity boundary and validated-value widget updates. Protected -exact-head CI and required repository review remain release gates after -guarded publication. - -## 2026-08-10 Second workspace-parent propagation into PR #4280 - -## 2026-08-10 Exact wind-adapter propagation into PR #4282 - -Draft PR `#4282` remains on `feat/4199-wind-workflow` with base -`feat/4199-wind-scalar-adapter`. The normal merge starts from original child -`5f77af4add23547a21cc3fabce98ae9ad4260427` and incorporates exact published -parent `4a793c4c3f19aad43a3c215800b266be487ace49` second. Do not rebase, -retarget, force-push, rewrite either parent, change draft state, or merge the PR. - -The consolidated responsive wind/capability workflow and campaign release -authority remain additive with the parent's variation visualizations, -result-local selection, workspace/toolstrip, Python 3.10 compatibility, and -matching `scalar-ensemble/v1` wind adapter. The canonical navigation-state -module now owns the child capability-tab ID, preserving the parent's safe -legacy visibility migration without duplicating navigation constants. The -parent's strict deterministic wind boundary also remains intact: exact -per-trial provenance, zero shear/turbulence, seed zero, and no gusts. -Static review replaces child-owned optimized-away runtime assertions with -explicit invariant failures and identifies the fixed-argument executable -builder subprocess boundary with Bandit's native annotations. The exact-head -CI repair above handles the separate skipped-import Pydantic return boundary. - -SPEC 1.14.14 is the unique combined child entry above parent 1.14.13. -Verification is green across 73 focused Python navigation/wind/compatibility -tests, the complete Rate/shared-swing/golf-club matrix (`1,657 passed`, two -explicit optional build123d skips), and all 643 React tests across 105 files. -TypeScript, zero-warning ESLint, Vite production build, 12 Rust tests, 31 real -CPython 3.10 compatibility tests, and 43 post-review invariant/GUI/manifest -tests pass. Ruff/format, pinned MyPy 1.13 across 37 changed production files, -Bandit, the exact-parent 500-line budget, campaign-manifest contracts, -docs/minimum-test/assertion governance, CI-policy secrets scan, compilation, -and diff gates pass. Independent re-review found no actionable findings after -94 Python workflow/navigation tests, 20 manifest/GUI tests, and 61 React -workflow tests plus independent static checks. Protected current-head CI, -unresolved threads, and required repository review remain release gates. - -## Active Rate of Closure campaign - -The active checkout is -`C:\Users\diete\Repositories\Tools-worktrees\toolstrip-workspace` on the -existing PR #4282 carrier `feat/4199-wind-workflow`. The local continuation -starts from original published head -`5f77af4add23547a21cc3fabce98ae9ad4260427` and normally incorporates exact -published #4281 parent `4a793c4c3f19aad43a3c215800b266be487ace49` -without changing the branch base `feat/4199-wind-scalar-adapter`. It composes -four reviewed slices: -strict capability parsing and signed decimal entry; complete capability -diagnostics/result exports and quantitative React scatter scales; package-safe -static-web release entrypoints; and the strict `rate-of-closure-campaign/v1` -release-evidence authority. The normal merge also carries the parent's -Python 3.10 compatibility, variation-export, and scalar-ensemble corrections. -No branch was rebased, retargeted, rewritten, or force-pushed. Protected CI -and review remain due after normal publication. - -Canonical files: - -- `docs/release/rate_of_closure_campaign.v1.json` — normalized campaign state; -- `scripts/rate_campaign_manifest.py` — schema and contradiction validator; -- `docs/release/RATE_OF_CLOSURE_CAMPAIGN_MANIFEST.md` — maintenance procedure; -- `src/rate_of_closure/AGENT_HANDOFF.md` — current Rate-specific handoff; -- `docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md` — historical detail. - -The manifest deliberately reports the campaign as **not released**. It -distinguishes specified scope, feature-stack implementation, protected parent -merge, and exact `main` release. A local pass, a feature-branch merge, and a -default-branch release are never interchangeable. - -## Current carrier and release state - -Capability PRs #4294, #4289, and #4283 were merged top-down into -`feat/4199-wind-workflow`; their feature parents were not protected. PR #4282 -is the current open carrier on base `feat/4199-wind-scalar-adapter`. Exact -published parent `4a793c4c3f19aad43a3c215800b266be487ace49` is incorporated -through the normal local merge containing this handoff. - -The previous exact #4282 head `3186a265b1` built and loaded `swing_core`, but -its Python 3.11 parity job failed before collection because a cached -`pytest-qt` plugin loaded without PyQt6. Commit `18fe89201` disables third-party -pytest plugin auto-loading only in that Rust parity step. Its focused workflow -contract test passes; a fresh hosted parity run is still required. - -Combined local evidence on the composed continuation is 1,657 Python tests -with two explicit optional skips and 105 React files / 643 tests, plus the -TypeScript, zero-warning ESLint, 188-module Vite build, Rust, Python 3.10, -manifest, Ruff, pinned mypy, Bandit, governance, secrets, compilation, and -diff evidence recorded above. - -Hosted quality-gate run `31340032608` reached mypy 1.13 and exposed -CI-context-only `no-any-return` findings in the Pydantic manifest loader and -Qt elapsed-timer adapter because the delta lane uses `--follow-imports=skip`. -Both boundaries now narrow their return values explicitly. The exact Python -3.12/mypy 1.13 delta is clean across 54 files; Ruff passes and 62 focused -regression tests plus eight campaign-manifest tests pass (only pre-existing -optional-plugin config warnings). - -Corrected-parent propagation evidence is 62 focused wind/scalar/variation and -compatibility tests on both Python 3.11 and real CPython 3.10.20, plus 8 React -files / 35 tests, TypeScript, and focused zero-warning ESLint. The Python 3.10 -run exposed one child-owned direct `enum.StrEnum` import in capability -observations; it now uses the shared runtime compatibility contract and is -included in the source-level regression. Ruff check/format passes 15 focused -files, pinned mypy 1.13 passes 10 production modules, and all nine campaign -manifest/parity contracts pass. - -The direct web launcher dynamically loads the root bootstrap through -`importlib` instead of mutating `sys.path` in the changed entrypoint. Its real -child-process delegation test and the changed-Python policy guard cover that -release path. - -Only `main` is the release boundary. It requires `quality-gate` and -`tests (3.11)`. Outer PR #4119 remains the main-targeting platform carrier and -requires current-main reconciliation. Impact-interval PR #4133 merged after -its parent stack had already propagated and is not proven in #4119. - -## Critical open programs - -- #4142/#4144: variation graphics are substantial, but global sensitivity, - bounded performance, downstream pinning, and release remain. -- #4146: club-builder core exists; manufacturing export, image fitting, full - client workflow, and downstream qualification remain. -- #4158: wedge kinematics, clearance, turf, visualization, and forgiveness are - feature-stack implementations without a protected release. -- #4191/#4201: wind, inverse flight, playback, and capability work exist on the - stack; scientific, installed-package, and cross-surface release gates remain. -- #4218/#4234: toolstrip and selected layout fixes exist; camera issue #4284, - complete persistence, high-DPI, keyboard, and visual baselines remain. -- #4260/#4267: four-surface parity is specified; ground contracts/transfer are - partial and bounce, skid, roll, total distance, UI, and parity remain open. - -## Required validation - -```powershell -python scripts/rate_campaign_manifest.py -python -m pytest tests/rate_of_closure/test_campaign_release_manifest.py -q -python -m pytest tests/ops/test_maturin_swing_core_workflow.py -q -python -m ruff check scripts/rate_campaign_manifest.py ` - tests/rate_of_closure/test_campaign_release_manifest.py -python -m ruff format --check scripts/rate_campaign_manifest.py ` - tests/rate_of_closure/test_campaign_release_manifest.py -python -m mypy --ignore-missing-imports scripts/rate_campaign_manifest.py -``` - -For a feature change, also run the complete affected Rate Python/PyQt/shared -swing and React suites recorded in the per-tool handoff. - -## Do not - -- Do not mark a program released without a 40-character `main` merge SHA. -- Do not convert queued, cancelled, skipped, or failed checks into passing - evidence. -- Do not retarget or rewrite the protected stack, force-push, or admin-merge. -- Do not duplicate carrier or test metadata in individual program records. -- Do not treat an UpstreamDrift launcher tile as four-surface parity. - -Fleet handoff policy is tracked by Repository_Management #1393/#1397. Any -`src/**` handoff change also requires the same-commit `SPEC.md` update. - -## 2026-08-10 Final repaired #4282 propagation into PR #4285 - -Draft PR `#4285` retains branch `feat/4268-ground-contract` and base -`feat/4197-capability-observer`. Original child head -`e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` now normally incorporates exact -quality-green workflow head `1e82f15026786ea0b08f78f4c001590ddce9ff39` -second. No ground-contract production or test code conflicted, and no rebase, -retarget, force-push, parent rewrite, or draft-state change was used. Fresh -protected CI/review is required before downstream #4288 propagation. - -## 2026-08-10 Final repaired ground-contract propagation into PR #4288 - -Draft PR `#4288` retains branch `feat/4269-flight-ground-transfer` and base -`feat/4268-ground-contract`. Original child head -`108a841b1378c992defd3c7b7ee263d41a6c8b24` normally incorporates exact -quality-green parent `a93edb4bfd6a8dc9334122cd2ae660983d5bf424` -second. No transfer production or test code conflicted. No rebase, retarget, -force-push, parent rewrite, or draft-state change was used; fresh protected CI -and review remain required. - -## PR #4288 exact repaired-ground propagation - -Draft PR #4288 remains on `feat/4269-flight-ground-transfer` with unchanged -base `feat/4268-ground-contract`. Original child -`247215422a6d4b677552955b4923bc609a553259` normally incorporates exact repaired -#4285 parent `e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` second in the -merge containing this handoff. The child preserves its signed terminal state, -physical sphere/terrain contact brackets, strict provenance, and qualified -Python/TypeScript/Rust/PyO3/WASM transfer while inheriting deterministic -workspace timestamps, canonical `swing_sim` import identity, the hosted-mypy -manifest repair, and the complete variation, wind, capability, and campaign -ancestry. No branch was rebased, retargeted, rewritten, or force-pushed. - -This propagation adds no bounce, skid, roll, terrain response, total distance, -or UI execution. Protected CI, independent review, and dependency-ordered -collapse remain separate release gates. - -Exact composed-tree verification is 1,080 Python tests passed with six explicit -optional installed-`tools_core` wheel skips, 107 React files / 662 tests, -26 direct Rust transfer/wire tests, TypeScript, zero-warning ESLint, and the -189-module production build. Ruff check/format passes all 28 changed Python -files; pinned mypy 1.13 passes all 21 changed production files. Campaign -manifest validation, documentation governance, and diff checks are clean. The -missing local wheel is not accelerated installed-package evidence and remains -an explicit release boundary; the direct Rust suites executed rather than -being relabeled as wheel parity. - -## 2026-08-10 Exact repaired #4282 propagation into PR #4285 - -Draft PR #4285 remains on `feat/4268-ground-contract` with unchanged base -`feat/4197-capability-observer`. The normal merge containing this handoff keeps -original child `788aa547651a3685a363ea401824a5d81477bafb` first and incorporates -exact repaired #4282 carrier `686016196a2f895058b8a566dff103a0fd32cd10` -second. That carrier contains merged capability PR #4283 commit -`c1827bbdc50a6e11cc475db2636b4e47a4c15416`, exact observer head -`9bbb98e16e435a0d4c74153b909f2ebfefbbce7a`, and the hosted-mypy manifest -repair following predecessor `aa6eeffb0395f7ed7954f2315b1c625cada552d8`. -No branch was rebased, retargeted, rewritten, or force-pushed. ## 2026-08-09 PR #4304 corrected implementation evidence @@ -1391,54 +625,6 @@ UI, TypeScript/Rust/PyO3/WASM physics, and downstream parity remain open. Protected CI, independent review, exact-head publication, parent integration, and consumer delivery are still required. -## 2026-08-10 Exact repaired #4282 propagation into PR #4285 (continued) - -The inherited ground descendant passes 1,703 Python tests with two explicit optional -`build123d` skips, 643 React tests across 105 files plus type-check, -zero-warning lint and production build, 12 Rust tests, and 77 ground plus -compatibility tests on real CPython 3.10. Ruff/format cover 78 changed Python -files; pinned mypy and Bandit cover 52 changed production files. Campaign -manifest, documentation, minimum-test, changed-assertion, 500-LOC, changed-file -secrets, Python 3.10 compilation, and diff gates are clean. Protected -current-head CI and required review remain separate release gates. Its exact -repaired head is now incorporated into #4288; normal propagation of the -reviewed #4288 head into #4298 is the next ancestry gate. - -The composed pinned-mypy profile additionally exposed integration-only `Any` -returns at the Pydantic manifest and scalar plotting boundaries. The repaired -#4282 parent owns the manifest annotation; scalar extraction normalizes the -already-validated value with `float`. Bandit also replaced an optimized-away -command-state assertion with an explicit invariant error. The alias finder -retains its intentional optional-probe catch-and-continue boundary under a -narrow explanatory `B112` annotation. - -## 2026-08-09 Ground parent reconciled with corrected wind carrier - -Draft PR #4285 remains on `feat/4268-ground-contract` with unchanged base -`feat/4197-capability-observer`. Exact corrected wind carrier -`bb101cedd555d07d493aae998b46050c68660cdd` is incorporated by the normal -local merge containing this handoff; no branch was rebased, retargeted, -force-pushed, or published. The result is the carrier-reconciled ground parent: -it retains the strict flight-to-ground schemas, canonical fixtures, migrations, -legacy-result adapter, dependency declaration, and pinned-mypy repairs while -carrying the complete corrected wind/scalar/variation/Python-3.10 and -consolidated capability ancestry. - -No qualified bounce, skid, roll, terrain-profile, total-distance, UI, or -Rust/WASM ground physics is added by this propagation. PR #4288 must normally -merge the resulting exact #4285 head before its flight-to-ground transfer can -be evaluated as a descendant of the corrected carrier. Because #4285 still -targets the observer branch while the corrected carrier now contains that -observer through wind workflow #4282, this merge is the explicit -observer-to-wind ancestry reconciliation; the GitHub base remains unchanged. - -Focused evidence is 89 ground-contract, compatibility, scalar-adapter, and -responsive-wind tests on Python 3.11 and the same 89 on real CPython 3.10.20. -Ruff check/format passes 34 focused Python files; pinned mypy 1.13 passes 23 -production modules. Ground production modules remain below 400 lines and -functions below 50 lines, with no placeholder markers. The inherited campaign -manifest validates and its nine manifest/parity contracts pass. - ## 2026-08-09 PR #4302 pinned-MyPy current-head correction Hosted quality-gate run `31350134551` exposed four deterministic MyPy 1.13 @@ -1740,6 +926,7 @@ npm run type-check npm run lint npm run build ``` + ## 2026-08-09 PR #4302 deterministic-digest scanner repair Protected CI correctly remained blocking at head @@ -1753,567 +940,3 @@ Commit this narrow repair with all three canonical handoffs and push normally to `feat/4270-ground-impact-bounce`. Do not retry the unchanged failed run, amend history, or force-push. Descendant PRs #4304 and #4305 inherit this file and must later receive the parent by ordinary merge commits. -## 2026-08-11 parent handoff sections preserved during #4282 reconciliation - -## 2026-08-10 Second variation-parent propagation into PR #4281 - -- Draft PR `#4281` retains branch `feat/4199-wind-scalar-adapter` and base - `feat/4144-variation-export-continuation`. Exact repaired parent head - `b90e5021a59e2081415b51ef29fbed06377bc201` is incorporated through a - normal merge commit without rebase, retarget, force-push, or history rewrite. -- There is no scalar-adapter production/test conflict. Both append-only - handoff/SPEC histories are retained and the adapter contract is unchanged. -- Parent quality success is not child release evidence. Fresh exact-head CI, - review, and all earlier dependencies remain open. -- Reconciled-child evidence is 25 focused D-plane/impact tests plus docs - governance, changed-file size budget, and whitespace checks. - -## 2026-08-10 Parent Repair Propagation (#4202 → #4203) - -- Draft child PR `#4203` remains on `feat/4181-launch-monitor-registry`, based - on `feat/4189-dplane`; neither branch nor PR base is rewritten. -- Original child head `08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` is - normally merged with exact parent head - `b443fdbed7064c5db0320106013c8413e3e24356`, in that parent order. -- The semantic reconciliation preserves #4203's responsive - `SimulationViewControlsMixin` architecture while delegating persisted - D-plane checkbox state to the parent's focused `ImpactLayerControls` - helper. The existing `_impact_layer_checks` automation seam aliases the - helper's single checkbox mapping, so no duplicate UI state is introduced. -- The inherited Python 3.10 compatibility repairs, frame-explicit D-plane - geometry, launch-monitor registry, responsive layout, and exports remain - additive. `simulation_view.py` and its controls mixin both remain below the - protected 500-line limit. -- The exact original child also carried three ungrandfathered module-budget - blockers before this propagation: `simulation/sources.py` (540 LOC), - `plotting/catalog.py` (533 LOC), and `ui/pyqt6/main_window.py` (528 LOC). - Behavior-preserving extractions now isolate triple-pendulum dynamics, - plotting metadata, and versioned primary-navigation persistence. The legacy - source, catalog, and main-window imports are identity-preserving re-exports; - the split modules are 282/282, 459/98, and 494/85 lines respectively. -- Focused reconciliation and extraction evidence is green: 36 PyQt - simulation/layout tests, 38 plotting/navigation tests, and 21 simulation - source/export tests. Final combined-stack evidence is 1,249 passing Python - tests with six explicit optional-dependency/Rust-wheel skips; 521 passing - React tests plus TypeScript, ESLint, and Vite production gates; 12 - `swing-core` tests; real CPython 3.10 compilation/import checks; scoped - Ruff/Black/pinned MyPy; docs, minimum-test, assertion, changed-file size, - detect-secrets, and diff gates. A full-tree audit separately retains two - untouched non-candidate size findings (`kinetics.py`, 646 LOC; - `torque_profile_panel.py`, 612 LOC). Independent staged review found no - actionable findings after 95 additional focused tests. Exact-head protected - CI and required repository review remain release gates. - -## 2026-08-09 PR #4203 Python 3.10 string-enum compatibility - -Current-head child CI exposed a collection boundary that was already present -in PR #4203's parent surface: seven Rate/shared swing modules imported -`enum.StrEnum`, which does not exist on Python 3.10. Runtime imports now use -the repository's existing `shared.python.compatibility.StrEnum`; type checking -retains the native stdlib symbol behind `TYPE_CHECKING` so pinned mypy 1.13 -keeps enum-member types rather than weakening them to strings. No enum values, -serialized contracts, physics, or UI behavior changed. - -This repair is published at exact #4203 head -`ab7de5a47977417e02926c3fbc7476002e82b690`. Evidence: -64 focused convention, D-plane, manual-delivery, flight-result, inverse, -impact-family, capability, and compatibility tests pass; Ruff and format pass; -pinned mypy 1.13 passes all eight changed Python files; and a real CPython -3.10.20 probe verifies the shared fallback and all seven runtime import paths. -Propagate the new parent normally through #4279, #4280, #4281, and #4282. - -The subsequent full Rate scan also found one parent-owned direct -`datetime.UTC` import in the torque-profile controller. It now uses the same -shared Python 3.10 compatibility module. The focused torque-profile UI suite -and the real-3.10 source/runtime probe are required before publishing this -follow-up; serialized timestamps remain UTC and the workspace schema is -unchanged. - -## 2026-08-09 PR #4203 Linux collection repair - -Draft PR #4203 remains on `feat/4181-launch-monitor-registry`, based on -`feat/4189-dplane`; no branch was rebased, retargeted, force-pushed, or merged -on GitHub. Exact-head CI run `31199764932` passed the quality gate but all -three Python lanes failed while collecting the in-package flight and solver -facade contract tests. Pytest loaded those tests through its `src.shared...` -package namespace, while their absolute dotted aliases requested the editable -`shared...` namespace; Python then reported that `flight`/`solver` could not be -imported from `src.shared.python.swing_sim` before any assertion ran. - -The bounded repair uses package-relative facade imports in those two tests, so -collection and the public API assertions stay in one namespace. It does not -change production code or widen either facade. Verify both contract modules -with `--import-mode=importlib`, Ruff/format, and pinned mypy before a normal -push. The run's Rust `-lpython3.11` link error is missing runner toolchain -state, not simulation evidence; do not modify the model to hide it. After the -new #4203 head passes, propagate it through #4279, #4280, #4281, and #4282 in -normal stack order. - -Local evidence is now `12 passed` on Windows and `12 passed` under WSL Python -3.11 with importlib collection. Ruff check/format and pinned mypy 1.13 pass -for both changed test modules. The frozen-dataclass assertion casts only its -introspection target to `Any`, matching the later carrier boundary while -retaining the runtime assertion. The minimal WSL environment reports only -unknown-option warnings for intentionally omitted optional pytest plugins. - -## 2026-08-10 PR #4202 D-plane ndarray typing repair - -- Draft PR `#4202` remains on `feat/4189-dplane`, based on - `feat/4162-wedge-impact-visualization`; the verified published repair base is - `b443fdbed7064c5db0320106013c8413e3e24356`. -- CI Standard run `31384810375`, job `93442745760`, exposed two exact pinned - MyPy 1.13 `no-any-return` findings in the private D-plane ndarray helpers. - Explicit local ndarray result boundaries now preserve those helpers' return - contracts without changing validation, arithmetic, frames, schemas, or any - public API. -- TDD evidence: the exact two-error MyPy failure was reproduced before the - repair; the same command is green afterward. Twenty-four focused D-plane, - impact-contract, impact-kinematics, and impact-scene tests pass, together - with seven metadata/pre-push contract tests, scoped Ruff, Ruff format, Black, - docs governance, minimum-test, module-size, changed-file-size, and diff - checks. An exploratory CI-workflow contract slice retains three unrelated - failures for later toolcache/environment steps absent from this older branch; - no workflow file is changed by this repair. -- This is a bounded quality-gate repair, not completion of D-plane issue - `#4189`. Protected current-head CI, dependency order, and required review - remain release gates; no push, retarget, or draft-state change is included. - -## 2026-08-10 Parent Repair Propagation (#4179 → #4202) - -- Child PR `#4202` remains on `feat/4189-dplane`, based on - `feat/4162-wedge-impact-visualization`; neither branch nor PR base is - rewritten. -- Original child head `b4abec03bccfbdd87ddf91427159c5c2332c21dd` is - normally merged with exact parent head - `6704a3e541a3e74c28b4a284530d1a21269dd340`, in that parent order. -- The Python 3.10 UTC repair and source-wide AST guard remain additive to the - frame-explicit 3D D-plane geometry, desktop/web overlays, and export - contracts. -- The persisted D-plane layer controls are extracted into a focused helper, - restoring `simulation_view.py` to the protected 500-line module budget - without changing its compatibility seam or behavior. -- Combined-stack verification is green: 93 focused and 825 scoped Python tests - with two optional `build123d` skips; 360 React tests plus TypeScript, ESLint, - and Vite production gates; real CPython 3.10.20 compilation/UTC; Ruff/Black; - focused pinned MyPy 1.13; docs, minimum-test, file-size, detect-secrets, and - diff checks. The exact parent's 12 unchanged `swing-core` tests remain - applicable because this child has no Rust delta. The inherited broad MyPy - baseline remains 17 Qt/NumPy typing findings in 11 untouched files. - Protected CI and required review remain release gates. - -## 2026-08-10 Parent Repair Propagation (#4178 → #4179) - -- Child PR `#4179` remains on `feat/4162-wedge-impact-visualization`, based on - `feat/4166-wedge-turf-physics`; neither branch nor PR base is rewritten. -- Original child head `0eb804e70887c788421332369e42792411aff55a` is - normally merged with exact parent head - `bfa83aedc88ead380babc73a699377d98b971006`, in that parent order. -- The Python 3.10 UTC repair and source-wide AST guard remain additive to the - exact-event, locked-scale wedge impact visualization contracts. -- Combined-stack verification is green: 58 focused and 739 scoped Python tests - with two optional `build123d` skips; 347 React tests plus TypeScript, ESLint, - and Vite production gates; real CPython 3.10.20 compilation/UTC; Ruff/Black; - focused pinned MyPy 1.13; docs, minimum-test, file-size, detect-secrets, and - diff checks. The exact parent's 12 unchanged `swing-core` tests remain - applicable because this child has no Rust delta. The inherited broad MyPy - baseline remains 17 Qt/NumPy typing findings in 11 untouched files. - Protected CI and required review remain release gates. - -## 2026-08-10 Parent Repair Propagation (#4174 → #4178) - -- Child PR `#4178` remains on `feat/4166-wedge-turf-physics`, based on - `feat/4161-wedge-ground-clearance`; neither branch nor PR base is rewritten. -- Original child head `aaae3f73e17dbfaad5cca1dc6f49559b3aebe9d5` is - normally merged with exact parent head - `9ea93e92563280ec34bca682ad44d7409edd7a02`, in that parent order. -- The Python 3.10 UTC repair and AST guard remain additive to the validated - turf-contact contracts and their explicit scientific/calibration boundary. -- Combined-stack verification is green: 56 focused and 732 scoped Python tests - with two optional `build123d` skips; real CPython 3.10.20 compilation/UTC; - Ruff/Black; focused pinned MyPy 1.13; docs, minimum-test, file-size, - detect-secrets, and diff checks. With no TypeScript or Rust delta, the exact - parent evidence of 345 React tests/all web gates and 12 `swing-core` tests is - unchanged. The inherited broad MyPy baseline remains 17 Qt/NumPy typing - findings in 11 untouched files. Protected CI and review remain release gates. - -## 2026-08-10 Parent Repair Propagation (#4173 → #4174) - -- Child PR `#4174` remains on `feat/4161-wedge-ground-clearance`, based on - `feat/4163-impact-inspector`; neither branch nor PR base is rewritten. -- Original child head `880a6465fc872cf3d6650283db154ddc41793a31` is - normally merged with exact parent head - `9ddaff3b6bca542fd7a2befc7d7b0ae53910a60a`, in that parent order. -- The inherited Python 3.10 UTC repair and source-wide AST guard remain - additive to the swept wedge ground-clearance contracts. -- Combined-stack verification is green: 56 focused Python tests; 703 scoped - Python tests with two optional `build123d` skips; 345 React tests plus - TypeScript, ESLint, and Vite production gates; 12 `swing-core` tests; real - CPython 3.10.20 compilation and UTC checks; Ruff/Black; focused pinned MyPy - 1.13; docs, minimum-test, file-size, detect-secrets, and diff checks. The - inherited broad MyPy baseline is 17 Qt/NumPy typing findings in 11 untouched - files and remains outside this propagation scope. Protected CI and review - remain release gates. - -## 2026-08-10 Parent Repair Propagation (#4167 → #4173) - -- Child PR `#4173` remains on `feat/4163-impact-inspector`, based on - `feat/4144-variation-visualizations`; neither branch nor PR base is rewritten. -- The original child head `3c43955aaeb3964ff8c3ef2748d626baae518b76` - is being merged normally with exact parent head - `22b66b560652b78de84141344c4ddd9a92a83b26`, in that parent order. -- The inherited repair replaces Python 3.11-only `datetime.UTC` use in Rate - torque-profile persistence with `shared.python.compatibility.UTC` and adds a - Rate-source AST regression guard for direct, aliased, and module-attribute - access. -- Combined local verification is green: 63 focused Python tests, all 562 Rate - tests, all 334 React tests, TypeScript type-check, ESLint, Vite production - build, 12 `swing-core` Rust tests, real CPython 3.10.20 compile/UTC checks, - Ruff check/format, Black, focused pinned MyPy 1.13, docs governance, - minimum-test, file-size, detect-secrets, and diff checks. A broader MyPy - sweep still reports 17 pre-existing Qt/NumPy typing errors in 11 untouched - files. Protected CI and required review remain release gates; queued, - cancelled, missing-toolcache, and dependency-download jobs are not green - evidence. -- Every implementation commit must update this file, the Rate handoff, the - campaign handoff, and `SPEC.md`, or explicitly record why there is no - material handoff change. - -## Where This Repo Is Headed - -Tools is the D-sorganization fleet's shared engineering-tools monorepo (45+ -tools: PyQt6 GUIs, FastAPI/React web mirrors, Rust kernels). The current -center of gravity is `src/rate_of_closure`, being grown from a single -closure-rate calculator into a full swing → impact → ball-flight simulation -platform under **Repository_Management#1390** (this handoff rollout) and a -stack of golf-simulation epics: - -| Epic | Status (one line) | -| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| #4103 — Swing–Impact–Ball-Flight Simulation Platform | Phases 0-6 implemented on branch `feat/impact-simulation-platform`, consolidated into PR **#4119** (open, auto-merge armed, awaiting review). Phase 7 (WASM web parity swap, Pages CI) still open. | -| #4120 — Investigation & Variation Suite (plotting/viewers/Monte Carlo/help) | V1-V4 implemented, stacked on #4119, consolidated into PR **#4124** (open, draft-for-review, no auto-merge yet — targets `feat/investigation-suite`, itself stacked on #4119). | -| #4125 — Realistic Clubs/Kinetics/Putting/Public Release Mgmt/Showcase Styling | H1-H7 implemented, stacked on #4124, consolidated into PR **#4129** (open, draft-for-review, targets `feat/course-showcase`, stacked on #4124). H5 (public release-management repo) is cross-repo, not yet started. | -| #4130 — Impact-Interval Club Dynamics (contact-interval rigid-body model) | Foundation epic only (F1 formulation doc not yet started); no PR yet. Next major physics wave after #4125 lands. | - -The separate shared Club Builder epic #4146 is active. Its first dependency -slice, #4147, lives on `feat/4147-club-builder-core` and establishes the -UI-independent assembly mass/CG/inertia, frame, length-datum, and persistence -contracts that the later shaft, CAD, export, fitting, and UI issues consume. - -Active infrastructure repair: #4155 hardens the Rust/PyO3 job against -incomplete setup-python cache entries whose interpreter works but whose -declared link library is missing. The repair is isolated on -`fix/4155-rust-libpython-cache` and does not change simulation code. - -See `src/rate_of_closure/AGENT_HANDOFF.md` for the detailed stack breakdown -and architecture pointers for this tool specifically. - -## Must-Read Architecture Pointers - -1. `CLAUDE.md` — repo-wide conventions, CI gate list, cross-repo dependency - rules (Tools is a leaf dependency; UpstreamDrift and Gasification_Model - consume it). -2. `docs/architecture/CANONICAL_TOPOLOGY.md` — canonical repo topology policy. -3. `SPEC.md` — living specification; §12 Change Log requires a dated row for - every PR touching `src/` (enforced by `spec-check.yml`, see gates below). -4. `src/rate_of_closure/AGENT_HANDOFF.md`, `src/pendulum_simulator/AGENT_HANDOFF.md`, - `src/rotation_converter/AGENT_HANDOFF.md` — per-tool handoff docs. -5. `docs/AGENT_HANDOFF_TEMPLATE.md` — template for adding a handoff doc to a - new tool. - -## In-Flight Branches (what stacks on what) - -``` -main - └─ feat/impact-simulation-platform (PR #4119, epic #4103, auto-merge armed) - └─ feat/investigation-suite (PR #4124, epic #4120, stacked on #4119) - └─ feat/course-showcase (PR #4129, epic #4125, stacked on #4124) -docs/agent-handoff-1390 (this branch, off origin/main, Repository_Management#1390) -``` - -Other active non-golf branches worth knowing about: `fix/file-size-budget-bounded-checkout` -(#4096, CI checkout-scope fix), `agent/scada-phase-a-foundation` (#4091, SCADA -epic #4085), several `scada/pr*` branches (SCADA epics #4085-#4089), and a -handful of Bolt/Palette/Sentinel micro-PRs (#4070-#4102) unrelated to the -golf-sim stack. - -## Gate Commands (repo-wide) - -```bash -python3 -m ruff check . # lint -python3 -m ruff format --check . # format check -python3 -m pytest -n auto --timeout=60 # full test suite -python3 -m pytest -m contract # API contract tests (downstream-facing) -python3 -m pytest -m integration --timeout=60 # cross-repo integration -``` - -SPEC freshness (CI job `spec-freshness` in `.github/workflows/spec-check.yml`): -any PR touching `src/**`, `tests/**`, `config/**`, `pyproject.toml`, -`Cargo.toml`, `package.json`, or `requirements.txt` must also modify -`SPEC.md` in the same PR, or carry the `spec-exempt` label. Runs on the -`d-sorg-fleet` self-hosted runner. - -## Do-Not List - -- Do not modify public function signatures in `src/shared/python/**` without - opening coordinated migration issues in UpstreamDrift and Gasification_Model - (see `CLAUDE.md` Cross-Repo Dependencies). -- Do not import across package boundaries (e.g. `signal_processing_studio` - importing from `sidekick.process_calculators`) — LoD is enforced. -- Do not exceed the 500-LOC file budget on new/modified files in the golf-sim - packages (`rate_of_closure`, `swing_sim`, `swing-core`) — sub-package, - don't grow monoliths. -- Do not use `git commit --no-verify` / `--push --no-verify` to bypass hooks; - see `CLAUDE.md` Hook bypass policy. -- Do not regenerate the sidekick API baseline (`tests/sidekick_api_baseline.json`) - without coordinating a breaking-change migration. -- Do not merge #4124 or #4129 ahead of their base (#4119, #4124 respectively) - — they are stacked and will conflict/duplicate SPEC.md sections if merged - out of order. -- Do not hand-roll a GitHub Pages deploy workflow for `rate_of_closure/web` - yet — Phase 7 of #4103 owns this; today Pages hosting elsewhere in the repo - (e.g. `unit_converter`) is done via manual branch-folder publish, not CI. - -## Short-Term Roadmap (ordered) - -1. Land PR #4119 (base platform) — currently the long pole; everything else - stacks on it. -2. Get #4124 out of draft-for-review and merge into `feat/investigation-suite` - → cascades onto #4119. -3. Get #4129 out of draft-for-review and merge into `feat/course-showcase` - → cascades onto #4124. -4. Start #4130 Phase F1 (formulation document) once #4125's stack is in. -5. Phase 7 of #4103: WASM swap for the web mirror + real Pages CI deploy for - `rate_of_closure/web`. -6. #4125 H5: stand up the public release-management repo (cross-repo, not - started). - -## 2026-08-11 additional parent sections preserved during #4282 reconciliation - -## 2026-08-10 Exact variation-parent propagation into PR #4281 - -Draft PR `#4281` remains on `feat/4199-wind-scalar-adapter` with base -`feat/4144-variation-export-continuation`. The normal merge starts from -original child `cf52529b1e68479321bb93b1be3d59c77f782008` and incorporates exact -published parent `8bcc49fc4e16e5e43be0b7f0f03c3017d5b79d0c` as its second parent. Do -not rebase, retarget, force-push, rewrite either parent, or change draft state. - -The child's matching Python/TypeScript `scalar-ensemble/v1` contract and wind -strategy plot adapter remain additive with the parent's selected-scatter -exports, accessible raw tables, result-local linked selection, complete -workspace/toolstrip, playback, navigation, compatibility, and module-budget -repairs. Both adapters now enforce the same deterministic wind-scenario -boundary: exact per-trial provenance, zero shear and turbulence, seed zero, and -no gusts. SPEC 1.14.13 is the unique combined child entry above parent 1.14.12. - -Verification is green across 27 focused Python contract/adapter/selection -tests, the complete Rate/shared-swing/golf-club matrix (`1,549 passed`, two -explicit optional build123d skips), and all 556 React tests across 92 files. -TypeScript, zero-warning ESLint, Vite production build, Ruff, Ruff-format, -pinned MyPy 1.13, Bandit, the exact-parent two-file 500-line budget, docs, -minimum-test, assertions, detect-secrets, diff, and CPython 3.10 compilation -pass. Independent re-review found no actionable findings after checking the -exact provenance derivation and all five deterministic-scenario regressions; -protected current-head CI, unresolved threads, and required repository review -remain release gates. - -## 2026-08-10 PR #4280 workspace timestamp propagation - -Draft PR #4280 remains on `feat/4144-variation-export-continuation` with base -`feat/4218-toolstrip-workspace`. Exact corrected parent -`05383d333b6fd87eaf5e37305476f50b505c2c2e` is incorporated through the normal -merge containing this handoff, without rebasing, retargeting, force-pushing, -or rewriting either branch. The child retains its selected-scatter CSV export, -typed unavailable values, accessible raw tables, and focused visualization -modules while inheriting the deterministic Python 3.10-3.12 UTC parser. - -The monotonic specification assigns the parent repair version 1.14.10 and the -variation child version 1.14.11. The reconciled tree passes all `778` Rate -tests, the real-CPython-3.10.20 compatibility suite (`27 passed`), the focused -React variation suite (`1 file / 8 tests`), TypeScript, zero-warning focused -ESLint, Ruff, format, and pinned mypy 1.13. Documentation, size, and diff gates -must remain clean in the merge commit. Protected CI, review, and propagation -to #4281 and later descendants remain separate release gates. - -## 2026-08-10 Second parent propagation into PR #4279 - -- Draft PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base - `feat/4181-launch-monitor-registry`; exact repaired parent head - `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` is incorporated through a - normal merge commit with no rebase, retarget, or history rewrite. -- The trees have no feature-code conflict. Reconciliation retains both - branches' append-only handoff/SPEC evidence, while the inherited D-plane - ndarray typing repair remains numerically and behaviorally neutral. -- Parent quality-gate success does not authorize this child. Fresh exact-head - protected CI, review, and all dependency gates remain open. -- Reconciled-child evidence is 25 focused D-plane/impact tests plus docs - governance, changed-file size budget, and whitespace checks. - -## 2026-08-10 Exact parent propagation into PR #4279 - -Draft PR `#4279` remains on `feat/4218-toolstrip-workspace` with base -`feat/4181-launch-monitor-registry`. This merge starts from original child -head `05383d333b6fd87eaf5e37305476f50b505c2c2e` and incorporates exact -published parent head `31cbc007d4c85b5479b7cd0fb0969124eab2af67` through a -normal two-parent merge; no rebase, retarget, force-push, or draft-state change -is permitted. - -The semantic reconciliation preserves the child's File/View/Tools workspace, -module visibility, granular playback, trail, plot, and launcher integration. -It also keeps the parent's focused `ImpactLayerControls`, plotting catalog, -triple-pendulum, and primary-navigation modules. Workspace navigation now -aliases the parent's canonical stable-ID/settings constants, while retaining -the child's visibility and required-module state. Impact-layer automation and -the rendered controls share the parent's single checkbox mapping. - -Combined verification is green: 1,339 Python tests pass with six explicit -optional build123d/Rust-wheel skips; 545 React tests pass across 89 files, and -TypeScript, ESLint, and the Vite production build pass. The post-format semantic -rerun is 40 passing navigation/simulation GUI tests. Ruff, Ruff-format, Black, -pinned MyPy 1.13 across all 18 changed production modules, Bandit, the exact -18-file 500-line gate, docs, minimum-test, changed-test assertions, -detect-secrets fingerprints, and staged/unstaged diff checks pass. CPython -3.10.20 compiles every changed Python file and its dependency-free navigation -state round-trip passes; 30 compatibility/date-boundary regressions also pass. -There is no Rust delta from the exact parent, whose 12-test `swing-core` -evidence remains applicable. Independent staged review found no actionable -findings after 76 additional focused PyQt/navigation/workspace tests; protected -exact-head CI and required repository review remain release gates after an -ordinary guarded push. - -## 2026-08-10 PR #4279 fractional-timestamp Python 3.10 repair - -Exact-head CI on descendant PR #4281 exposed one remaining workspace parser -difference: CPython 3.10 accepts only three or six fractional-second digits in -`datetime.fromisoformat`, while newer supported interpreters accept the -one-digit value already used by the workspace ordering contract. The earliest -owner is PR #4279. Its shared workspace validator now enforces one anchored UTC -grammar and parses zero through six fractional digits consistently, rejecting -greater precision instead of silently truncating it on newer Python versions. -UTC-only validation, serialized values, schema fields, and chronological -comparison are unchanged. - -Evidence is `778 passed` for the full Rate suite and `45 passed` for the -compatibility plus complete workspace document suites on the local supported -interpreter, plus `27 passed` for the source-level compatibility suite on real -CPython 3.10.20. The latter has only expected warnings for plugins absent from -that intentionally minimal runtime. Ruff, formatting, pinned mypy 1.13, -documentation governance, and the 400-line budget pass. Exact remote-head -identity and normal publication/descendant propagation remain release gates. - -## 2026-08-09 PR #4281 scalar-ensemble parent propagation - -Draft PR #4281 remains on `feat/4199-wind-scalar-adapter` with unchanged base -`feat/4144-variation-export-continuation`. Exact corrected #4280 parent -`38ed58cab96842a3007e76a855db83ee2452b8fd` is incorporated by the normal -merge containing this handoff; no branch was rebased, retargeted, force-pushed, -or published by this continuation. The result preserves the complete parent -workspace, Python 3.10 compatibility, and variation-export history together -with #4281's independently owned scalar-ensemble and wind-strategy adapters. - -The child supplies matching UI-neutral Python/TypeScript -`scalar-ensemble/v1` contracts with stable RFC3986 composite row identity, -immutable nullable rows, and overall/per-cohort availability. Its wind adapter -retains every actual and perfect-information status and exposes true/estimated -wind, launch/aim, target, landing, miss, cost, and information delta. Impact -variables remain explicitly unavailable because the analysis starts at -prescribed launch. SPEC 1.14.12 records this child source delta separately -from parent versions 1.14.11 and earlier. - -Current focused evidence is `49 passed` on Python 3.11 and `49 passed` on real -CPython 3.10.20 with PyQt6/scientific dependencies present. React passes `2 -files / 10 tests`, TypeScript, and focused zero-warning ESLint. Ruff -check/format passes the four child Python files; pinned mypy 1.13 passes both -production modules and the corrected wind-adapter test. Documentation -governance, ancestry/SPEC assertions, and final diff checks are required in -this same local merge. Protected CI, review, publication, and descendant -propagation remain separate release gates. The background runner, progress and -cancellation, PyQt6/React strategy/scatter workflow, persistence, and export -wiring remain incomplete and must not be represented as delivered. - -## 2026-08-09 PR #4280 parent propagation and SPEC restoration - -Draft PR #4280 remains on `feat/4144-variation-export-continuation` with base -`feat/4218-toolstrip-workspace`. Exact corrected parent -`3f67ed466fefc8991db9c4409f921f25e1c37142` is incorporated by the normal -merge containing this handoff; no branch was rebased, retargeted, force-pushed, -or published by this continuation. The result retains the complete workspace -and Python 3.10 compatibility history together with #4280's independently -owned variation scatter/export changes. - -The child exports every selected scatter axis to CSV with stable trial index, -typed outcome, and explicit unavailable values in both PyQt6 and React. PyQt6 -also exposes the selected raw rows in bounded accessible tables, with shared -table population and focused scatter/matrix modules. SPEC 1.14.11 now records -this child source delta separately from parent versions 1.14.10 and earlier. - -Current evidence is `46 passed` on Python 3.11 and `19 passed` on real CPython -3.10.20 with PyQt6 present. React passes `1 file / 8 tests`, TypeScript, and -focused zero-warning ESLint. Ruff check/format passes five child Python files; -pinned mypy 1.13 passes the four child production modules. Documentation -governance, ancestry/SPEC assertions, and final diff checks pass locally. -Protected CI, review, publication, and descendant propagation remain separate -release gates. - -## 2026-08-09 PR #4279 Python 3.10 compatibility completion - -Draft PR #4279 remains on `feat/4218-toolstrip-workspace` with unchanged base -`feat/4181-launch-monitor-registry`. Exact corrected parent -`08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` was incorporated by the normal -local merge `a340fabefa443d47325c5538f342683b38c01ade`; no branch was rebased, -retargeted, force-pushed, or published by this continuation. - -The child-owned command registry and view-workspace enums now obtain -`StrEnum` from `shared.python.compatibility` at runtime while retaining the -native type behind `TYPE_CHECKING`. Workspace timestamp validation likewise -uses the shared `UTC` value. This removes all three Python 3.11-only imports -introduced by #4279 without changing command IDs, enum values, timestamp -serialization, workspace schemas, or UI behavior. The merged regression -guards nine string-enum modules and both UTC modules by inspecting the actual -runtime import branch, then executes the three child workspace modules. - -Evidence is `126 passed` on Python 3.11, plus `14 passed` and a successful -10-module dotted-import probe on real CPython 3.10.20. Ruff check/format passes -the 11 production modules and compatibility test; pinned mypy 1.13 passes all -11 production modules with the changed-file CI settings. Documentation -governance and final diff checks must pass in this same local commit. Protected -CI, review, publication, and descendant propagation remain separate gates. - -## 2026-08-09 PR #4279 launch-registry propagation - -Draft PR #4279 remains on `feat/4218-toolstrip-workspace` with unchanged base -`feat/4181-launch-monitor-registry`. Exact parent head -`08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` is incorporated through the normal -merge commit containing this handoff; neither branch was rebased, retargeted, -force-pushed, or pushed by this continuation. Source changes applied cleanly; -the overlapping handoff and specification histories were reconciled -monotonically. The result preserves the parent's package-relative facade and -Python 3.10 enum repairs plus the child's workspace, toolstrip, playback, plot, -and module-navigation implementation. - -Focused validation is `126 passed` across both facade contract modules and all -Python/PyQt test files changed by #4279. React workspace validation is `8 files -/ 32 tests passed`. Ruff check and format pass for all 28 relevant Python -files. CI-pinned mypy 1.13 passes the 18 changed production files plus the two -facade contract tests. The type gate exposed one real child-boundary defect: -`legend_visible()` returned an untyped Qt value; it now converts that value at -the widget boundary with `bool(...)`. The affected simulation GUI rerun is `29 -passed`; documentation governance and staged/unstaged diff checks also pass. - -## 2026-08-10 Second Parent Repair Propagation (#4202 -> #4203) - -- Draft child PR `#4203` retains base `feat/4189-dplane` and receives exact - repaired parent head `7d8d2f06dc797021d01939691e58f8425b652b33` - through a normal merge commit; no base, parent history, or draft state is - rewritten. -- The propagated parent repair adds explicit NumPy ndarray result boundaries - to the two D-plane helpers that failed the hosted pinned MyPy gate. Numerical - behavior, frames, schemas, and UI behavior remain unchanged. -- The exact parent quality gate is green. Protected child checks, review, and - all earlier dependency gates remain open; this propagation does not - authorize a merge or close #4189. -- Child-tree verification after conflict reconciliation is 25 focused D-plane, - impact-contract, impact-kinematics, and impact-scene tests; docs governance, - changed-file size budget, and whitespace checks also pass. The Windows - unpinned MyPy 1.15 environment cannot parse the installed Python-3.12-only - NumPy stub syntax under this branch's Python 3.11 target, and WSL currently - fails to start with `E_FAIL`; neither attempt is reported as a passing gate. diff --git a/SPEC.md b/SPEC.md index 071cdeb96..4c64c7e88 100644 --- a/SPEC.md +++ b/SPEC.md @@ -26,162 +26,14 @@ | **Owner** | D-sorganization | | **Primary Language(s)** | Python 3.11+, Rust, JavaScript, TypeScript | | **License** | MIT | -| **Current Version** | 1.14.31 | -| **Spec Version** | 1.14.31 | +| **Current Version** | 1.14.35 | +| **Spec Version** | 1.14.35 | | **Last Spec Update** | 2026-08-11 | ## 2. Purpose & Mission Comprehensive monorepo housing 45+ utility tools for data processing, scientific computing, process engineering, and automation. This is the central tooling hub for the D-sorganization fleet, providing modular engineering calculation tools with PyQt6 GUIs, FastAPI web services, Rust numerical kernels, and a unified launcher with plugin architecture for extensibility. -### 2026-08-11 PR #4288 append-only history preservation repair - -The documentation-only follow-up to exact local candidate -`1eb4188ff1a87a3d8e9a55aeca68194ca04e0bb4` restores parent handoff sections -and change-log rows omitted during reconciliation and repairs one interleaved -handoff paragraph. Production code, tests, schemas, the campaign manifest, -child-first merge topology, and PR #4288's `feat/4268-ground-contract` base are -unchanged. Publication and protected exact-head release evidence remain open. - -### 2026-08-11 Ground contract receives current workflow/base ancestry - -- Exact remote ground-contract child - `7a38b9838d743e051a6900620c4d6e754582aa89` is the first parent and exact - published workflow/base head - `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is merged second, preserving - PR #4285's `feat/4197-capability-observer` base and child-first topology. -- The strict `flight-to-ground/v1` contract remains behaviorally unchanged - while inheriting the current wind/capability stack, Ground/Tee parity, split - kinetics facade, and pinned formatting repairs. The ground-side kinetics - conflict was an obsolete formatting-only edit and contributes no behavior. -- The retained scalar extractor narrowing is housed behind a 61-line public - plotting catalog facade. Ordered scalar and series entries are separated in - private collaborators, keeping every changed production module/function/ - signature within 400 lines, 50 lines, and four non-receiver parameters while - preserving catalog keys, order, categories, units, and extractor behavior. -- Verification passes the complete 1,539-test Rate/shared-swing Python matrix - with one optional Rust-wheel skip, all 648 React tests in 106 files, - TypeScript, zero-warning ESLint, the 188-module production build, 12 Rust - tests, 146 focused contract/parity tests, and 57 catalog/plot regressions. -- This merge creates a local publication candidate only. Bounce, skid, roll, - terrain profiles, total distance, ground UI, Rust/WASM ground parity, - protected CI, approval, release, and downstream #4288 propagation remain - explicitly open. - -### 2026-08-11 Wind workflow receives current scalar-adapter parent - -- The responsive PyQt6/React wind-strategy workflow and consolidated - capability stack inherit exact scalar-adapter parent - `a7dce5f89b483303938f518b74b4028a1c68ba81` through a normal child-first - merge, preserving branch topology and both histories. -- The validated split kinetics facade replaces one obsolete child formatting - hunk. Seven remaining child-owned paths receive pinned Ruff formatting only; - physics, public APIs, schemas, frames, units, and UI behavior are unchanged. -- The exact skipped-import MyPy profile replaces one unused cache-return ignore - with an explicit `KineticsSeries | None` cast. The cached object and runtime - behavior are unchanged. - -### 2026-08-11 Wind strategy plot-adapter module-budget repair - -- `rate_of_closure.variation.wind_strategy_plot_adapter` remains the public - plot-data facade. Its request/analysis validation is delegated to the private - `_wind_strategy_plot_validation` collaborator so both production modules are - below the mandatory 400-line ceiling. -- The public API, `scalar-ensemble/v1` wire shape and ordering, row identity, - values, typed availability, attributes, validation messages, and contract - prohibiting a flight-physics rerun are unchanged. -- Private wind-scenario validation receives a scenario and one frozen, slotted - expectation object, keeping every production function at or below four - parameters and 50 lines without weakening any precondition. - -### 2026-08-11 Kinetics module-budget repair - -- The established `rate_of_closure.simulation.kinetics` module remains the - public façade for swing kinetics. Immutable result validation now lives in - `_kinetics_series.py`, and pure double-pendulum inverse/forward dynamics and - reaction-force helpers live in `_kinetics_dynamics.py`. -- Public constants, classes, and functions retain identity-preserving imports; - the historical private `_reaction_forces` test/consumer seam remains an - alias to the extracted implementation. Physics, SI units, frames, numerical - fixtures, UI behavior, and serialization contracts are unchanged. -- This extraction repairs the proactively reproduced changed-file failure: - exact head `572bf525d` versus `HEAD~1` selected the Ruff-formatted - `kinetics.py` at 646 LOC, above the ungrandfathered 500-LOC ceiling. The - façade and its focused implementation modules are now 222, 205, and 131 LOC. - -### 2026-08-09 Capability workflow contract hardening - -- Python and TypeScript capability workflow readers reject JSON primitive type - mismatches throughout the nested v1 document instead of coercing numeric - strings, booleans, or numeric text fields. -- A shared golden parser fixture pins identical acceptance and rejection, - including portable acceptance of mathematically integral JSON numbers for - integer fields. -- React Shot Optimizer numeric controls retain decimal draft text, allowing - ordinary leading-minus keyboard entry before validated numeric commit. - -### 2026-08-09 Capability result diagnostics - -- PyQt6 and React ranked-alternative views expose the full v1 optimization - diagnostics, explicit parameter units, evidence-envelope state, and Pareto - state rather than a reduced carry/dispersion summary. -- Ranked results export through spreadsheet-safe CSV and a deterministic - `capability-result-export/v1` JSON envelope. Lossless raw observation exports - remain separate so aggregate recommendations cannot obscure failed or - no-impact trials. -- React scalar-ensemble scatter plots render numeric grid/tick scales, visible - axis ranges, and cohort legends with paired-finite counts. - -### 2026-08-09 Rate campaign release-evidence authority - -- `docs/release/rate_of_closure_campaign.v1.json` is the normalized authority - for primary campaign issues, specifications, carriers, four-surface support, - commit-bound tests, limitations, dependencies, and release status. -- `scripts/rate_campaign_manifest.py` validates the strict version-1 contract - and emits its deterministic JSON Schema. Feature-stack implementation, - protected parent integration, and exact `main` release are mutually - exclusive states with fail-closed cross-field requirements. -- The current manifest truthfully records no complete campaign release SHA; - local tests and unprotected feature-parent merges cannot satisfy that claim. -- Composed local implementation evidence is commit-bound in the manifest; - maintainers must still refresh live mutable PR heads before any write, - merge, release, or issue-closure decision. -- The manifest loader explicitly narrows Pydantic's validated value for the - CI mypy 1.13 `--follow-imports=skip` context without weakening runtime - validation or the generated schema. -- The PyQt playback adapter similarly converts Qt's elapsed-time result to a - concrete `float`, preserving the typed seconds contract when Qt imports are - deliberately skipped by the changed-file CI lane. - -### 2026-08-09 Swing-core parity CI isolation - -- The dedicated `swing_core` Rust-to-Python parity lane disables third-party - pytest plugin auto-loading so cached GUI plugins on self-hosted runners cannot - introduce undeclared PyQt dependencies into the Rust-only qualification job. -- The lane continues to install the built wheel and run the same non-skippable - parity suite; numerical behavior and production dependencies are unchanged. - -### 2026-08-09 Rate web-release stability - -- The documented direct Rate web launcher imports its registration through the - package-qualified path and dynamically loads the repository bootstrap without - direct `sys.path` mutation, so `python src/rate_of_closure/launch_web.py` - works outside package-module execution and satisfies changed-file policy. -- Rate supports a static Vite web release and a PyQt6/PyInstaller desktop - release. It does not claim Tauri support without a `src-tauri` project or an - artifact qualification lane. -- The Flight Explorer parent-panel test explicitly settles its lazy wind-panel - import inside React `act`, removing suite-load timing from the assertion. - -### 2026-08-10 D-plane ndarray typing boundary repair - -- The private D-plane vector conversion and horizontal-projection helpers bind - NumPy expression results to explicit ndarray locals before returning them. -- This preserves the existing numerical calculations and DbC validation while - satisfying the changed-file MyPy `no-any-return` contract on Python 3.12. -- No public API, reference frame, serialized schema, physics assumption, or UI - behavior changes in this repair. - ### 2026-08-06 GUI module-budget repair - Movement Optimizer motion palette and chain-length helpers live in a small @@ -194,7 +46,7 @@ unchanged. Publication and protected exact-head release evidence remain open. ## 3. Goals & Non-Goals -### 2026-08-10 Regional Surface-Plan Editor First Slice +### 2026-08-10 Regional Surface-Plan Canonical Request I/O - The standalone PyQt6 and React shells expose matched `Ground Surfaces` modules for editing one SI base domain and one to eight coplanar static @@ -208,9 +60,28 @@ unchanged. Publication and protected exact-head release evidence remain open. errors preserve the draft and provide accessible error state; successful validation exposes schema, SI-unit, provenance, and canonical request readback. -- This first slice is session-only. Ground execution/playback, result import, - export, measured calibration workflows, model-input persistence, compiled - regional physics, and UpstreamDrift consumers remain explicit non-goals. +- Native PyQt6 Open/Save As commands use strict complete-read validation and + atomic UTF-8 replacement. Browser import/download uses the same bounded + canonical request and discloses that browser downloads cannot guarantee a + path, atomic replacement, or recent-file access. Workspace persistence is a + separate contract. +- Imports accept only editor-v1 provenance, providers, geometry/axis + qualification, and row capacity. Unchanged imports preserve the exact + request and provenance; edits create a fresh draft digest. External or + differently qualified requests are rejected without coercion. +- Both runtimes accept wire numbers only inside JavaScript's exact safe range. + Native precedence entry remains integer-exact through the inclusive v1 + maximum of 9,007,199,254,740,991 and cannot silently narrow imported data. +- Native request import reads a single binary-handle snapshot bounded to the + 1 MiB wire limit plus one sentinel byte, then performs strict UTF-8 decoding. + Concurrent file growth cannot trigger an unbounded allocation. +- PyQt6 canonical-precision inputs share one frozen `NumberInputSpec` and + three-parameter construction helper. The regional I/O editor retains its + eleven-decimal presentation and inclusive cross-runtime safe bounds without + restoring the superseded six-parameter helper. +- Ground execution/playback, result interchange, measured calibration + workflows, model-input workspace persistence, compiled regional physics, + and UpstreamDrift consumers remain explicit non-goals. ### 2026-08-06 Impact-to-Flight Solution-Family Foundation @@ -457,15 +328,6 @@ unchanged. Publication and protected exact-head release evidence remain open. overrides survive club changes, legacy runs migrate to Ground, and the derived ball center drives contact, alignment, impact records, flight origin, and both standalone renderers. -- Python and React consume the same version-1 golden ball-setup fixture. Its - strict metadata fixes SI metre units and the - `ground_plane_to_ball_bottom` reference; its cases pin club defaults, - explicit overrides, Ground's zero effective tee height, derived geometry, - serialization, invalid-height rejection, and legacy migration. -- Visual verification uses semantic state and structural image contracts, not - pixel-perfect baselines: Playwright records default Tee and rerun Ground web - states with zero browser errors, while the hidden-window PyQt harness pins - canonical center/artist state and nonblank, distinct Ground/Tee captures. - Variation plans retain their complete v2 schema and can be saved, loaded, duplicated, and deleted from a versioned local library. Users can select simultaneous, one-at-a-time, or combined analyses, while paired common- @@ -3073,32 +2935,24 @@ Active development with stable core, continuous tool expansion, and web API in p | Date | Version | Changes | | ---- | ------- | ------- | +| 2026-08-11 | 1.14.35 | fix(rate-of-closure, #4342): retain the default canonical JSON encoder's JavaScript-safe numeric boundary for ground contracts while adding an explicit capability-observation-only extended finite-float policy that reuses the same recursive encoder; keep integers safe-range bounded, emit integral finite doubles such as `1e20` and `1e21` as exact exponent-free decimal tokens matching the TypeScript capability serializer, and preserve fail-closed non-finite handling with Python, TypeScript, ground-boundary, full-suite, static-analysis, build, and governance evidence. | +| 2026-08-11 | 1.14.34 | merge(rate-of-closure, #4274 #4339 #4342): normally merge exact current regional request-I/O child `c1f47f2ef68b3db102da5416aaac17a40f675207` first with exact reviewed local regional-editor parent candidate `db335937afc4b587d235eb705e315f577519c5e6` second while preserving PR #4342's `feat/4274-regional-surface-ui` base, child-owned canonical request import/export, bounded UTF-8 and safe-number validation, native atomic save, browser-qualified download, tests, limitations, and all append-only handoff/SPEC history; inherit current editor, wire, regional-physics, and complete ground ancestry without rebase, retarget, rewrite, force-push, or publication, while keeping execution/playback, result interchange, measured calibration, model-input persistence, changing geometry or velocity, TypeScript/compiled regional physics, downstream parity, protected exact-head evidence, review, approval, dependency integration, and release open. | | 2026-08-11 | 1.14.31 | merge(rate-of-closure, #4274 #4335 #4339): normally merge exact current regional-editor child `d21741e312b849a63f73cabf351a15d9de80fb94` first with exact published regional-wire parent `8f933ed8dcb29e55ece4ec6bb1e60813f6794d57` second while preserving PR #4339's `feat/4271-regional-wire-contract` base, matched PyQt6/React editors, strict validation invalidation and readback, parent wire/resolver/regional-physics/ground ancestry, and both append-only handoff/SPEC histories; retain the extracted navigation-state contract with `regional_surfaces` in default and legacy migration order, without rebase, retarget, rewrite, force-push, or publication, while keeping execution/playback, result interchange, measured calibration, model-input persistence, changing geometry or velocity, TypeScript/compiled regional physics, downstream parity, protected exact-head evidence, review, approval, dependency integration, and release open. | +| 2026-08-11 | 1.14.33 | docs(rate-of-closure, #4342): restore verbatim the omitted PR #4335, #4332, and #4304 current-parent ancestry sections in all three canonical handoffs and the parent's exact parallel-branch SPEC 1.14.29 and 1.14.28 reconciliation rows; record the historical version collision without rewriting either branch's append-only record; change no production code, tests, schemas, manifest state, PR base, protected evidence, or release status. | +| 2026-08-11 | 1.14.32 | chore(rate-of-closure, #4274 #4342): normally reconcile exact published regional request-I/O child `8e1c7ccd99a7c4886c5fb9ccc7e4d94a6d7e3833` with exact newly published regional-editor parent `d21741e312b849a63f73cabf351a15d9de80fb94` without changing PR #4342's base; preserve native atomic and browser-qualified canonical request I/O, safe-number and bounded UTF-8 behavior, and the parent's frozen validated engineering-number specification by delegating child controls to its three-parameter helper while retaining eleven-decimal presentation; keep protected CI, approval, integration, execution, calibration, downstream parity, and release open. | +| 2026-08-11 | 1.14.31 | fix(rate-of-closure, #4274 #4342): remove one redundant Boolean cast rejected by protected delta-MyPy without changing wire bytes, validation, file semantics, UI behavior, or physics. | | 2026-08-11 | 1.14.30 | fix(rate-of-closure, #4274 #4339): replace the six-parameter PyQt engineering-number helper with a three-parameter helper and frozen validated specification while preserving names, values, units, ranges, increments, tooltips, and field order; add RED-first helper/configuration and structural-bound tests, retain byte-stable wire/digest/physics behavior, and keep protected CI, approval, integration, and release open. | | 2026-08-11 | 1.14.29 | chore(rate-of-closure, #4274 #4339): normally reconcile exact published regional-surface editor child `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` with exact newly published regional-plan wire parent `9e01ccc3e891cc45907293751a192624195a77a5` without changing the PR base or rewriting either branch; retain matched PyQt6/React request editors, invalidation and engineering hints together with the strict Python/TypeScript plan contract, resolver binding, bounded coplanar regional physics, and complete ground ancestry, while preserving execution/playback, result interchange, measured calibration, workspace persistence, changing geometry, compiled-runtime physics, downstream parity, protected evidence, and release as open work. | -| 2026-08-11 | 1.14.29 | merge(ground-regional-wire, #4332 #4335): normally merge exact remote regional-wire child `9e01ccc3e891cc45907293751a192624195a77a5` first with exact current regional-surface parent `5ac3c1f233de30dd42eeac57073cbdb149bde652` second while preserving PR #4335's `feat/4271-regional-surface-transitions` base, strict Python/TypeScript regional-plan request/result schemas, canonical JSON/SHA-256 fixture evidence, fail-closed parsing, Python resolver binding, tests, limitations, and both append-only handoff/SPEC histories; inherit current regional, skid/roll, impact/bounce, and flight-transfer ancestry without rebase, retarget, force-push, parent rewrite, or remote publication, while keeping changing geometry or velocity, internal transition-ledger export, regional UI, compiled or TypeScript regional physics, downstream parity, protected exact-head CI, review, approval, and release open. | | 2026-08-11 | 1.14.28 | chore(ground-regions, #4271 #4335): normally reconcile exact live regional-wire child `74a053d2d544da9f44a88007660ad28c0127f285` with exact newly published regional-surface parent `04ccf08dd990de1cd056a3420e67772773a4be2e` without changing the PR base or rewriting either branch; preserve the strict Python/TypeScript plan wire boundary and Python resolver binding together with the parent's reconciled coplanar regional physics and complete skid/roll ancestry, while retaining protected CI/review, UI, compiled or TypeScript regional physics, changing geometry/velocity, internal transition-ledger export, downstream parity, and release as open work. | +| 2026-08-10 | 1.14.29 | feat(rate-of-closure, #4274): add strict matched PyQt6 native atomic Open/Save As and React bounded import/canonical download for editor-qualified regional requests; preserve exact unchanged provenance, rebind edited drafts, reject unsupported qualifications without coercion, keep workspace persistence separate, and retain execution, calibration, protected evidence, and release as open work. | +| 2026-08-10 | 1.14.28 | feat(rate-of-closure, #4274): add matched PyQt6 and React regional surface-plan editors with explicit SI material inputs, one-to-eight bounded overlays, illustrative/unvalidated and persistence/execution qualifications, accessible strict validation/readback, provenance bound to the actual draft, and delegation to the separate regional-plan v1 wire contract; retain playback, execution, result interchange, measured calibration, workspace model-input persistence, other runtimes, protected evidence, and release as open work. | | 2026-08-10 | 1.14.27 | feat(ground-roll, #4271): add separate strict Python/TypeScript `ground-regional-material-plan-request/v1` and result/v1 wire contracts with exact keys, SI units, explicit coplanar/static limitations, finite bounded base/overlay intervals, bounded region/document counts, unique region/precedence/surface identities, canonical cross-runtime JSON/SHA-256 evidence, fail-closed no-fabrication result binding, and a Python-only adapter into the existing regional resolver; preserve the frozen flight-to-ground v1 request/result and retain TypeScript/compiled regional physics, UI, changing geometry, internal transition-ledger export, downstream parity, protected CI, review, and release as open work. | | 2026-08-10 | 1.14.26 | feat(ground-roll, #4271): add bounded Python-reference support for finite coplanar material overlays with unique explicit precedence, exact quadratic boundary splitting, base-edge precedence, state/energy continuity, strict Python/TypeScript `surface_transition` events, internal from/to identity evidence, typed transition limits, and randomized piecewise-analytic qualification; reject changing normals, height/velocity discontinuities, and overlays owning the impact handoff rather than fabricating impulses or geometry transitions, while retaining UI, compiled regional physics, and downstream parity as open work. | -| 2026-08-11 | 1.14.28 | merge(ground-regions, #4304 #4332): normally merge exact remote regional-surface child `04ccf08dd990de1cd056a3420e67772773a4be2e` first with exact current skid/roll parent `3f861c1faaa7455faee92eaa7f813174667208e0` second while preserving PR #4332's `feat/4271-ground-skid-roll` base, bounded coplanar material overlays, exact transition splitting and evidence, regional production, tests, fixtures, contracts, limitations, and both append-only handoff/SPEC histories; inherit current impact, bounce, skid, roll, and flight-transfer ancestry without rebase, retarget, force-push, parent rewrite, or remote publication, while keeping changing normals, discontinuous geometry or velocity, regional UI, compiled regional physics, downstream parity, protected exact-head CI, review, approval, and release open. | -| 2026-08-11 | 1.14.27 | chore(ground-regions, #4271 #4332): normally reconcile exact live regional-surface child `1a48d749af508843fac2a5102f4dd56294429bda` with exact newly published skid/roll parent `0ea6740965068542e9d8c7449e06ec07d88969e0` without changing the PR base or rewriting either branch; preserve bounded coplanar material overlays, exact transition splitting and evidence, strict contracts, and all current parent physics while retaining changing normals, discontinuous geometry/velocity, UI, compiled regional physics, and downstream parity as open work. | -| 2026-08-11 | 1.14.27 | merge(ground-roll, #4302 #4304): normally merge exact remote skid/roll child `0ea6740965068542e9d8c7449e06ec07d88969e0` first with exact current impact/bounce parent `62beb3e1aa951645fd556a53f9cbae4bb46c47e5` second while preserving PR #4304's `feat/4270-ground-impact-bounce` base, arbitrary-plane skid, static-feasible pure roll, rolling resistance, qualified rest, edge localization, strict result composition, passive ledgers, fixtures, tests, limitations, and both append-only histories; inherit current bounce and flight-transfer ancestry without rebase, retarget, force-push, parent rewrite, or remote publication, while keeping regional/changing-normal surfaces, deformation, torsional damping, roll-to-skid transitions, UI, compiled physics, protected exact-head CI, review, approval, downstream integration, and release open. | -| 2026-08-11 | 1.14.26 | chore(ground-roll, #4271 #4304): fast-forward the local skid/roll carrier to exact live child `52d9a6a978d8e6b8b19ef92f02f265c9058b00ad`, then normally merge exact live impact/bounce parent `cf6e72bad98e5f36f782254942e6895b8b71e670` without changing the PR base or rewriting either branch; retain the reviewed skid/roll physics and strict contracts while reconciling current ancestry and deterministic formatting evidence. | | 2026-08-10 | 1.14.25 | fix(ground-roll, #4271 #4304): normally propagate exact corrected ground-impact/bounce parent `846653c21bd61a40aab99ab838c29915d0728e70` into the skid/roll descendant without changing its base; preserve the reviewed arbitrary-plane skid, pure-roll, resistance, rest, edge, composition, and passive-ledger behavior while inheriting corrected flight-transfer ancestry, deterministic workspace timestamp parsing, and canonical `swing_sim` import identity; retain explicit exclusions for regional/changing-normal surfaces, terrain deformation, torsional spin damping, roll-to-skid transitions, UI, compiled physics, and downstream parity. | | 2026-08-10 | 1.14.24 | fix(ground-roll, #4304): explicitly allowlist the immutable SHA-256 golden-fixture digest as non-secret test evidence so protected secret scanning distinguishes a scientific integrity fingerprint from a credential; no physics, numerical, schema, API, or fixture bytes change. | | 2026-08-09 | 1.14.23 | feat(ground-roll, #4271): continue exact #4270 capture through arbitrary-plane kinetic skid, static-feasible pure roll, rolling resistance, qualified rest, finite-axis edge localization, bounded typed limits, relative surface-path and passive energy ledgers; compose representable prefix/suffix evidence into strict v1 results without duplicate or epsilon-time samples; pin an analytic shared fixture and retain explicit exclusions for regions, changing normals, torsional spin damping, roll-to-skid, UI, compiled runtimes, and downstream parity. | -| 2026-08-11 | 1.14.26 | merge(ground-impact, #4288 #4302): normally merge exact remote ground-impact/bounce child `cf6e72bad98e5f36f782254942e6895b8b71e670` first with exact current flight-ground-transfer parent `c39297d37a17d5d8d3520ed62c5563cdcc609cab` second while preserving PR #4302's `feat/4269-flight-ground-transfer` base, passive restitution/Coulomb impact, deterministic repeated bounce, exact-contact and capture-to-skid behavior, cancellation/failure evidence, and both append-only histories; apply AST-equivalent pinned Ruff 0.14.10 layout to three inherited PR-delta files; inherit the current transfer and strict-ground ancestry without rebase, retarget, force-push, parent rewrite, or remote publication, while keeping skid, roll, rest, total distance, final ground results, UI, compiled bounce runtimes, protected exact-head CI, review, approval, and release open. | | 2026-08-10 | 1.14.22 | fix(ground-impact, #4270 #4302): normally propagate exact corrected flight-transfer parent `247215422a6d4b677552955b4923bc609a553259` into the ground-impact/bounce descendant without changing its base; preserve the passive restitution/Coulomb impulse, deterministic repeated hops, exact-contact and capture-to-skid behavior while inheriting deterministic workspace timestamp parsing and canonical `swing_sim` import identity; retain explicit non-delivery boundaries for skid, roll, rest, total distance, final ground results, UI, TypeScript physics, and compiled bounce runtimes. | | 2026-08-09 | 1.14.21 | feat(ground-impact, #4270): add a typed passive restitution/Coulomb sphere-plane impulse with full spin and moving-boundary accounting, deterministic repeated ballistic hops, exact bracket contact, capture-to-skid handoff, cancellation and bounded failure states, airborne-segment evidence, a shared golden fixture, and analytic/property/convergence tests; retain #4271 ownership of skid, roll, rest, total distance, and final `GroundSimulationResult`, with UI and compiled runtimes explicitly excluded. | -| 2026-08-11 | 1.14.25 | merge(flight-ground, #4285 #4288): normally merge exact remote flight-ground-transfer child `df716ac740beb9d47dced66f867dc3dde1fa5367` first with exact current strict-ground parent `584e4e53a7990053a346938c4e45538786887ec7` second while preserving #4288's `feat/4268-ground-contract` base, complete Python/TypeScript/Rust/PyO3/WASM transfer production/tests/fixtures/contact evidence, cross-runtime contracts, and explicit incomplete ground-physics/UI/release limitations; retain both append-only histories without rebase, retarget, force-push, parent rewrite, or remote publication, and keep protected exact-head CI, review, approval, and release open. | -| 2026-08-11 | 1.14.24 | docs(flight-ground, #4285 #4288): restore every parent handoff section and specification history row omitted during the local #4288 reconciliation, repair the interleaved rate-of-closure handoff paragraph, and preserve the exact candidate's implementation, tests, schemas, campaign manifest, child-first topology, and `feat/4268-ground-contract` base; keep publication, protected exact-head CI, approval, dependency integration, and release open. | -| 2026-08-11 | 1.14.23 | chore(flight-ground, #4285 #4288): normally reconcile exact published flight-transfer child `afb1bdcfc6701caaf1f7bc3497a6a37dd9698c14` with exact newly published strict-ground parent `e09ab96280cab363b36bd0e7db4a3cd064dc2527` without changing #4288's base or rewriting either branch; preserve the child's bounded TypeScript flight integrator, signed terminal angular state, physical sphere/terrain contact, and Python/TypeScript/Rust/PyO3/WASM transfer while inheriting the parent's current wind/capability, strict-ground, split-kinetics, plotting-catalog, and formatting ancestry; apply AST-equivalent pinned Ruff normalization to seven child-owned Python files and standard line endings to the preserved TypeScript facade; retain bounce, skid, roll, terrain response, total distance, UI, protected evidence, and release as open work. | -| 2026-08-11 | 1.14.24 | merge(rate-of-closure, #4283 #4285): normally merge exact remote ground-contract child `e09ab96280cab363b36bd0e7db4a3cd064dc2527` first with exact current capability-observer carrier `d0b827667e61f0583e1dad0b3cbbca6819624d3c` second while preserving #4285's `feat/4197-capability-observer` base, complete strict `flight-to-ground/v1` production/tests/schemas/fixtures/dependencies, fail-closed unimplemented-physics boundary, and both append-only histories; inherit current wind/capability/release ancestry without rebase, retarget, force-push, parent rewrite, or remote publication, and keep protected exact-head CI, review, approval, release, and normal downstream #4288 propagation open. | -| 2026-08-11 | 1.14.22 | merge(rate-of-closure, #4282 #4283 #4285): normally merge exact remote ground-contract child `7a38b9838d743e051a6900620c4d6e754582aa89` first with exact current workflow/base head `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` second, preserving PR #4285's base and strict flight-to-ground contract while inheriting the complete current wind/capability, Ground/Tee parity, split-kinetics, and pinned-format ancestry; resolve the obsolete formatting-only kinetics hunk wholly to the validated parent facade, retain both append-only histories, and keep protected CI, approval, publication, release, qualified ground physics, and downstream #4288 propagation open. | -| 2026-08-10 | 1.14.19 | fix(rate-of-closure, #4282 #4285): normally propagate exact quality-green responsive wind-workflow head `1e82f15026786ea0b08f78f4c001590ddce9ff39` into strict flight-to-ground contract child `e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` without production/test conflict, topology change, or history rewrite; retain the fail-closed contract boundary and require fresh CI/review before normal #4288 propagation. | -| 2026-08-10 | 1.14.18 | feat/fix(ground, #4199 #4268 #4282 #4285): normally propagate exact repaired responsive wind-workflow carrier `686016196a2f895058b8a566dff103a0fd32cd10` into original strict ground-contract child `788aa547651a3685a363ea401824a5d81477bafb` while preserving base `feat/4197-capability-observer`; retain the fail-closed ground schemas, fixture, migrations, legacy adapter, explicit dependency, import-alias repair, and pinned typing repairs while inheriting the complete deterministic workspace, variation, scalar-wind, capability, campaign-release, and hosted-mypy manifest-repair ancestry; normalize contract-checked scalar plot extraction so the composed skipped-import mypy profile cannot leak `Any`, enforce disabled-command invariants under optimized Python, and document the optional alias finder's reviewed catch-and-continue security boundary; preserve the established no-bounce/no-skid/no-roll/no-terrain/no-total-distance/no-ground-UI/no-Rust-WASM delivery boundary and require #4288 to acquire this exact ancestry through its own normal descendant merge. | -| 2026-08-10 | 1.14.22 | fix(flight-ground, #4285 #4288): normally propagate exact quality-green strict-ground-contract head `a93edb4bfd6a8dc9334122cd2ae660983d5bf424` into flight-transfer child `108a841b1378c992defd3c7b7ee263d41a6c8b24` without production/test conflict, topology change, or history rewrite; retain the qualified cross-runtime transfer and explicit non-delivery boundaries, with fresh CI/review required before release. | -| 2026-08-10 | 1.14.21 | fix(flight-ground, #4199 #4269 #4282 #4285 #4288): normally propagate exact repaired strict-ground parent `e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` into original flight-transfer child `247215422a6d4b677552955b4923bc609a553259` while preserving base `feat/4268-ground-contract`; retain the qualified signed terminal state, physical sphere/terrain contact brackets, strict provenance, and Python/TypeScript/Rust/PyO3/WASM transfer while inheriting the deterministic workspace, variation, scalar-wind, capability, campaign-release, hosted-mypy, import-identity, scalar-extraction, command-invariant, and security-boundary repairs; preserve explicit non-delivery boundaries for bounce, skid, roll, terrain response, total distance, and UI. | | 2026-08-10 | 1.14.20 | fix(flight-ground, #4269 #4288): normally propagate exact corrected ground-contract parent `788aa547651a3685a363ea401824a5d81477bafb` into the flight-transfer descendant without changing its base; preserve the qualified Python/TypeScript/Rust/PyO3/WASM transfer while inheriting deterministic workspace timestamp parsing and canonical `swing_sim` import identity; retain explicit non-delivery boundaries for bounce, skid, roll, terrain response, total distance, and UI. | | 2026-08-09 | 1.14.19 | chore(flight-ground, #4269 #4288): normally propagate exact carrier-reconciled ground parent `6a2bc9d06f6f9a28a0d615b19d2ed4fc13871059` into the flight-transfer descendant without changing its base; preserve the qualified cross-runtime transfer and semantic facade assertions while completing corrected wind-to-ground ancestry; bind terminal samples before exact `FlightStatePoint` narrowing in the pinned-mypy regression; and retain explicit non-delivery boundaries for bounce, skid, roll, terrain response, total distance, and UI. | | 2026-08-09 | 1.14.18 | feat(flight-ground, #4269): propagate full signed terminal angular state and qualified physical sphere/terrain contact brackets across Python, TypeScript, Rust, PyO3, and WASM; preserve exact launch-origin evidence, vertical tee and terrain geometry, strict v1 surface/calibration/provenance data, interpolated terminal contact, typed unavailable outcomes, and bounded synchronous web integration. Reconcile the transfer integrator with the current capability and strict-ground ancestry through normal stacked merges without retargeting or rewriting either PR, and remove the resulting ground/flight package-facade cycle through direct record/type dependencies. | @@ -3109,55 +2963,12 @@ Active development with stable core, continuous tool expansion, and web API in p | 2026-08-10 | 1.14.13 | fix(rate-of-closure, #4282): normally propagate exact corrected scalar-ensemble parent `cf52529b1e68479321bb93b1be3d59c77f782008` into the responsive PyQt6/React wind-workflow carrier without changing its base; retain the consolidated capability workflow and release authority while inheriting the strict cross-version UTC parser, variation export, immutable scalar rows, stable composite identity, availability, and typed wind adapter; route the child-owned capability-observation `StrEnum` through the shared Python 3.10 runtime contract and extend the compatibility regression. | | 2026-08-10 | 1.14.12 | feat(wind variation, #4199 #4281): add matching UI-neutral Python/TypeScript `scalar-ensemble/v1` contracts with structured provenance, labeled stages/categories/cohorts, unit-bearing variables, stable RFC3986 composite row IDs, immutable nullable raw rows, and overall/per-cohort availability; adapt every actual and perfect-information wind-strategy outcome with explicit status, true/estimated wind, launch/aim, target, landing, miss, cost, and information-delta values while leaving impact variables explicitly unavailable because the analysis begins at prescribed launch. | | 2026-08-10 | 1.14.11 | feat(variation, #4144 #4280): complete PyQt6/React selected-scatter CSV export parity with stable trial identity, typed outcome and explicit unavailable values; expose bounded accessible PyQt raw-row tables through one shared population helper; and split scalar scatter and distribution-matrix rendering into focused modules while preserving linked trial selection and all-trial arc analysis. | -| 2026-08-11 | 1.14.23 | merge(rate-of-closure, #4282 #4283 #4285): use the already-merged PR #4283 head branch as the preserved dependency carrier for open draft PR #4285; normally merge exact remote/local capability-observer carrier child `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` first with exact published wind-workflow parent `3faf9e9493c9ba37168d9f65ab10cafeedc2a72f` second without reopening or retargeting a PR or rewriting history; reproduce the exact #4282 implementation while retaining the complete capability-observer history; keep publication, protected exact-head CI, and later #4285 propagation outside the bounded local audit. | -| 2026-08-11 | 1.14.22 | merge(rate-of-closure, #4281 #4282): normally merge exact published responsive wind-workflow child `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` first with exact newly published wind scalar-adapter parent `9321c1d2e091b8c7e5a4a83aa9ad726290e7fb5a` second while preserving PR #4282's `feat/4199-wind-scalar-adapter` base and both histories; retain responsive PyQt6/React wind execution, progress/cancellation, controls, scatter, persistence/export, consolidated capability workflow, and strict campaign release authority while inheriting the current scalar-adapter, variation, workspace/toolstrip, launch-monitor/D-plane, split-kinetics, and Qt repairs; keep review, ordinary publication, protected exact-head CI, unresolved-thread checks, dependency integration, and release open. | -| 2026-08-06 | 1.13.16 | feat(swing_sim, rate_of_closure, #4196): map desired flight to frame-explicit centered driver/iron delivery solution families with strict cross-runtime schemas, observed intervals/correlations, local sensitivities, complete residuals, model manifests, and rejected no-impact/miss diagnostics. | -| 2026-08-06 | 1.13.15 | feat(swing_sim, rate_of_closure, #4195): add strict desired-flight inverse-solver contracts, deterministic bounded multi-objective search, ranked residual-rich candidates, typed infeasible/no-impact/nonconverged outcomes, and Python/TypeScript parity fixtures. | -| 2026-08-06 | 1.13.14 | feat(swing_sim, rate_of_closure, #4194): add the canonical source-backed flight-result metric catalog, analytic landing/trajectory derivation, typed unavailable and qualified-ground boundaries, complete run manifests, deterministic Python/TypeScript exports, and cross-client parity fixtures. | -| 2026-08-11 | 1.14.21 | merge/fix(rate-of-closure, #4281 #4282): normally merge exact published scalar-adapter parent `a7dce5f89b483303938f518b74b4028a1c68ba81` into exact remote responsive-workflow child `29e15d6ff631f7f30afcc745be783f2e716d7dcf` in child-first order; preserve the complete PyQt6/React wind workflow and capability stack while inheriting the parent's split kinetics and scalar-adapter size/parameter repairs; resolve obsolete monolithic kinetics wholly to the parent facade, retain both append-only documentation histories, apply pinned Ruff formatting only to seven surviving child-owned paths, and replace one skipped-import cache-return ignore with an explicit typed cast without changing behavior, APIs, schemas, frames, or units. | -| 2026-08-10 | 1.14.16 | fix(rate-of-closure, #4281 #4282): normally propagate repaired wind scalar-adapter parent `d6fb04e07c2a625412e9208b07103acdc42c621b` into the responsive wind workflow without production/test conflict or history rewrite; retain current-state handoff policy and verify with 25 focused tests plus governance, size, and whitespace checks. | -| 2026-08-10 | 1.14.15 | fix(rate-of-closure, #4282): preserve the strict campaign-manifest return contract under the repository's exact pinned-mypy skipped-import profile by explicitly typing the Pydantic-validated local as `CampaignManifest`; this repairs hosted quality-gate run `31395741841` without changing JSON parsing, validation, failure behavior, PR base, or dependency topology, and requires the resulting exact head to propagate normally into #4285. | -| 2026-08-10 | 1.14.14 | feat/fix(rate-of-closure, #4199 #4281 #4282): normally propagate exact scalar-adapter parent `4a793c4c3f19aad43a3c215800b266be487ace49` into the responsive PyQt6/React wind-workflow carrier without changing its base; preserve the consolidated capability workflow and release authority while inheriting the complete variation, workspace, Python 3.10 compatibility, immutable scalar-row, stable identity, availability, and deterministic wind-scenario repairs; register the child capability tab in the parent's canonical navigation-state tuple so legacy saved orders reveal it without duplicating state; retain runtime invariant enforcement under optimized Python; and satisfy pinned typing/security analysis without weakening the fixed-argument builder boundary. | -| 2026-08-10 | 1.14.13 | feat/fix(wind variation, #4144 #4199 #4280 #4281): normally propagate exact variation parent `8bcc49fc4e16e5e43be0b7f0f03c3017d5b79d0c` into the wind scalar-adapter child while preserving matching UI-neutral Python/TypeScript `scalar-ensemble/v1` contracts with structured provenance, unit-bearing variables, stable RFC3986 row IDs, immutable nullable raw rows, and overall/per-cohort availability; adapt actual and perfect-information wind outcomes with explicit status, true/estimated wind, launch/aim, target, landing, miss, cost, and information-delta values; enforce the deterministic scenario boundary identically in both clients with exact per-trial provenance, zero shear/turbulence, seed zero, and empty gusts; and retain the parent's result-local linked selection and complete visualization/workspace repairs. | -| 2026-08-10 | 1.14.12 | feat/fix(variation, #4144 #4218 #4279 #4280): normally propagate exact workspace parent `6717e9e09d507dbc24bedb36177f1cdf0b4fd90b` into the variation-export child while preserving selected-scatter CSV parity with stable trial identity, typed unavailable outcomes, bounded accessible PyQt raw tables, focused PyQt/React visualization modules, linked selection, and all-trial arc analysis alongside the complete workspace/toolstrip, playback, plot, navigation, compatibility, and module-budget repairs; make linked trial selection result-local in both clients, clear it atomically when a rerun replaces the result, and reject or neutralize indices outside the current trial count so smaller reruns cannot crash or dim every new point. | -| 2026-08-10 | 1.14.11 | feat/fix(rate-of-closure, #4203 #4218 #4279): normally propagate exact launch-registry parent `31cbc007d4c85b5479b7cd0fb0969124eab2af67` into the workspace/toolstrip child while preserving granular playback, path trails, module visibility, and independent plot controls; reuse the parent's single persisted impact-layer mapping and canonical navigation constants without duplicating state; and retain its focused triple-pendulum, plotting-catalog, and primary-navigation repairs. | | 2026-08-10 | 1.14.10 | fix(compatibility, #4279): make workspace UTC timestamp parsing deterministic across Python 3.10-3.12 with one anchored canonical grammar, consistent zero- through six-digit fractional-second parsing, and rejection of greater-than-microsecond precision instead of interpreter-dependent rejection or truncation. | | 2026-08-09 | 1.14.9 | fix(compatibility, #4279): route the child command/view `StrEnum` runtime imports and workspace-validation `UTC` import through `shared.python.compatibility` while preserving native enum typing under `TYPE_CHECKING`, all wire values, schemas, UTC serialization, and UI behavior; merge the parent and child regression into one nine-enum/two-UTC runtime-import contract exercised with real CPython 3.10.20. | | 2026-08-09 | 1.14.8 | feat(rate-of-closure, #4201): harden cross-runtime capability parsing and signed input; expose complete diagnostics, result exports, and quantitative scatter annotations; stabilize supported PyQt6/static-Vite entrypoints; and add a strict campaign manifest with generated schema, four-surface status, explicit gaps/dependencies, and fail-closed feature-stack/protected-parent/`main` release distinctions. | | 2026-08-08 | 1.14.7 | docs(rate-of-closure, #4197): record the capability stack consolidation onto `feat/4199-wind-workflow`, superseding per-slice stacked-branch cautions after #4283, #4289, and #4294 merged, while retaining the incomplete protected-release boundary. | -| 2026-08-08 | 1.14.7 | docs(rate-of-closure, #4197): record the capability stack consolidation onto `feat/4199-wind-workflow`, superseding the per-slice stacked-branch cautions now that #4283, #4289, and #4294 are merged, and note that the unfinished CI matrix reflects an offline runner fleet rather than failures. | | 2026-08-08 | 1.14.6 | feat(rate-of-closure, #4197): add matched PyQt6/React Shot Optimizer workspaces with strict cross-runtime workflow persistence, off-main-thread qualified flight execution, truthful progress/cancellation, complete scalar-ensemble cohort retention, ranked alternatives, stage-qualified selectable scatter axes, zoom/autofit, bounded raw-row paging, lossless CSV/stable JSON, substantive hover guidance, and saved-layout migration that reveals newly registered modules. | | 2026-08-08 | 1.14.5 | feat(ball-flight, #4197): add profile/request-bound Python and TypeScript Waterloo/Penner capability evaluators with exact established parameter IDs, physical-domain and unit validation, sourced per-club spin defaults or paired variable spin inputs, shared gyro-projected positive-fade/right spin-axis convention across result/impact/variation producers, canonical target-frame conversion, target-aware complete scalar metrics, typed horizon nonconvergence, fail-fast invariants, and a shared 16-scalar tolerance fixture. Corrects the TypeScript ground-crossing interpolation so a descending launch from z=0 cannot extrapolate to a negative sample time, which previously raised an untyped `RangeError` that was absorbed as an `evaluator_exception`; such launches now report `nonconverged`, matching the Python runtime. | -| 2026-08-11 | 1.14.21 | merge(rate-of-closure, #4280 #4281): normally merge exact published wind scalar-adapter child `a7dce5f89b483303938f518b74b4028a1c68ba81` first with exact newly published variation-export parent `e6c7460a01082631565fb9ed48aa32538bd7772c` second while preserving PR #4281's `feat/4144-variation-export-continuation` base and both histories; retain matching Python/TypeScript `scalar-ensemble/v1` provenance, availability, deterministic-scenario, wind-strategy adapter, and strict module-budget behavior while inheriting current variation visualization/export, workspace/toolstrip, launch-monitor/D-plane ancestry, split kinetics, and behavior-preserving Qt boundaries; keep review, ordinary publication, protected exact-head CI, unresolved-thread checks, dependency integration, and release open. | -| 2026-08-11 | 1.14.20 | refactor(rate-of-closure, #4281): replace the private wind-scenario validator's five loose parameters with a scenario and one frozen, slotted expectation object; preserve validation order, messages, behavior, public API, and wire output while satisfying the four-parameter and 50-line production-function contracts. | -| 2026-08-11 | 1.14.19 | refactor(rate-of-closure, #4281): split request/analysis validation from the 403-line wind-strategy plot adapter into a private collaborator, leaving 252-line and 186-line production modules below the mandatory 400-line ceiling while preserving the public API, scalar-ensemble wire order, row identity and values, availability, attributes, validation messages, and no-flight-rerun boundary. | -| 2026-08-11 | 1.14.18 | merge(rate-of-closure, #4280 #4281): normally merge exact reviewed variation-export parent `3337945699966b63cb5cd8e52d7c3b194315e911` into exact remote wind scalar-adapter child `247046d55afcad3e6cd4f8029f854856c427f59c` with child-first parent order and no history rewrite; preserve matching Python/TypeScript `scalar-ensemble/v1` provenance, availability, deterministic-scenario, and wind-strategy plot-adapter behavior while inheriting the parent variation/export UI, kinetics split, Ground/Tee parity contracts, workspace/toolstrip repairs, and protected Ruff normalization; resolve the obsolete monolithic kinetics overlap to the validated parent `pendulum.sample(...)` facade, retain both append-only documentation histories, and require independent review plus fresh exact-head protected CI before publication. | -| 2026-08-11 | 1.14.19 | merge(rate-of-closure, #4279 #4280): normally merge exact published variation-export child `3337945699966b63cb5cd8e52d7c3b194315e911` first with exact newly published workspace/toolstrip parent `efbca84095b617b4018732f7802c2da3f0525387` second while preserving PR #4280's `feat/4218-toolstrip-workspace` base and both histories; retain selected-scatter CSV parity, typed unavailable outcomes, bounded accessible tables, linked selection, and all-trial arc analysis while inheriting current workspace, launch-monitor/D-plane ancestry, split kinetics, and behavior-preserving Qt primitive-return boundaries; keep review, ordinary publication, protected exact-head CI, unresolved-thread checks, dependency integration, and release open. | -| 2026-08-11 | 1.14.17 | merge(rate-of-closure, #4279 #4280): normally merge exact reviewed workspace/toolstrip parent `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` into exact remote variation-export child `668ba96746f79f7a12e8092161bd610054197f58` with child-first parent order and no history rewrite; preserve selected-scatter CSV parity, typed unavailable outcomes, bounded accessible tables, linked selection, and all-trial arc analysis while inheriting the parent kinetics split, Ground/Tee parity contracts, and complete workspace/toolstrip behavior; resolve the obsolete monolithic kinetics overlap to the validated parent façade and normalize seven duplicate automation edits to exact protected Ruff 0.14.10 parent blobs while keeping their commit reachable; require independent review and fresh exact-head protected CI before publication. | -| 2026-08-11 | 1.14.18 | merge(rate-of-closure, #4203 #4279): normally merge exact published workspace/toolstrip child `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` first with exact newly published launch-registry parent `7abce9ad767fe8311da66a1e5998b892ea3ca9de` second while preserving PR #4279's `feat/4181-launch-monitor-registry` base and both histories; retain workspace, toolstrip, visibility, navigation, playback, and independent-plot behavior while inheriting current launch-monitor/D-plane ancestry, split kinetics, and behavior-preserving Qt primitive-return boundaries; keep review, ordinary publication, protected exact-head CI, unresolved-thread checks, dependency integration, and release open. | -| 2026-08-11 | 1.14.16 | merge(rate-of-closure, #4279): ordinarily reconcile exact local workspace/toolstrip head `0b22c401a26c31441a599d8d9b39de123706e7ea` with divergent remote automation head `61fe2d556a5413e525d958612ccfd57e65b8d5a2`, preserving every commit and the existing stack topology; recognize 15 already-identical parent paths, normalize seven incompatible formatting edits back to protected Ruff 0.14.10 output, and resolve the sole obsolete pre-split kinetics conflict in favor of the current `pendulum.sample(...)` façade implementation; preserve workspace, toolstrip, visibility, navigation, playback, independent plots, physics, frames, units, schemas, and public contracts; require independent review and fresh exact-head protected CI before publication. | -| 2026-08-11 | 1.14.15 | merge(rate-of-closure, #4203 #4279): normally propagate exact published launch-registry parent `3796b49e40b677fbac4e05739f8be49f905df2cb` into exact workspace/toolstrip child `7806a16f58e1c6999d32f0127a187fbb21f839a1` without rewriting stack topology; inherit only four static NumPy-array casts while preserving runtime arrays, physics, frames, units, public contracts, workspace behavior, and UI behavior; require fresh current-head protected CI and review. | -| 2026-08-11 | 1.14.14 | merge(rate-of-closure, #4203 #4279): normally propagate exact launch-registry parent `0216a547aa79727091a2939b96e779e8ddbd7304` into the workspace/toolstrip child without rewriting stack topology; preserve the child's workspace, toolstrip, module-visibility, navigation, playback, and independent-plot behavior while inheriting the parent's identity-preserving kinetics split and pinned formatting repair; require fresh current-head protected CI and review. | -| 2026-08-11 | 1.14.17 | docs(rate-of-closure, #4202 #4203): restore four exact append-only D-plane parent history rows omitted during the local current-parent reconciliation; preserve the candidate implementation, tests, topology, base, and quality evidence while keeping independent re-review, normal publication, protected exact-head CI, downstream propagation, and release open. | -| 2026-08-11 | 1.14.16 | fix(rate-of-closure, #4203): close four exact-delta MyPy 1.13 Qt-stub boundaries by narrowing responsive-event handling, legend visibility, ball-setup event filtering, and visible status text to their already declared primitive return contracts; preserve values and UI behavior while retaining normal parent reconciliation and protected release gates. | -| 2026-08-11 | 1.14.15 | merge(rate-of-closure, #4202 #4203): normally compose exact published launch-monitor-registry child `217e36dc93d30f79826847f958fbcd10805e58ed` with exact current D-plane parent `f3363aa88868f6a5c7e9ccfc682a9eca014e86c1`; retain the split typed kinetics facade at the sole formatting conflict, preserve parent behavior and history, and keep independent review, protected exact-head CI, downstream propagation, and release open. | -| 2026-08-11 | 1.14.14 | fix(rate-of-closure, #4203): close four hosted MyPy `no-any-return` findings from the kinetics size split with explicit NumPy-array return narrowing at force-norm, RK4 concatenation, and app-frame projection boundaries; preserve exact runtime arrays, physics, frames, units, public contracts, and stack order. | -| 2026-08-11 | 1.14.13 | refactor(rate-of-closure, #4203): split the 646-LOC swing-kinetics monolith into an identity-preserving 222-LOC public façade, 205-LOC pure-dynamics module, and 131-LOC immutable-series contract; preserve physics, frames, fixtures, UI behavior, and established imports while satisfying the changed-file 500-LOC gate. | -| 2026-08-11 | 1.14.12 | style(rate-of-closure, #4203): apply repository-pinned Ruff 0.14.10 formatting to the eight files reported by current-head CI without changing physics, behavior, public contracts, schemas, UI layout, or stack order. | -| 2026-08-10 | 1.14.14 | feat/fix(wind variation, #4144 #4199 #4280 #4281): normally propagate repaired variation parent `b90e5021a59e2081415b51ef29fbed06377bc201` into the wind scalar-adapter child without production/test conflict or history rewrite; preserve matching Python/TypeScript `scalar-ensemble/v1` provenance, availability, deterministic-scenario, and wind-strategy plot-adapter contracts; verify the reconciliation with 25 focused D-plane/impact tests and governance, size, and whitespace gates. | -| 2026-08-10 | 1.14.13 | feat/fix(variation, #4144 #4218 #4279 #4280): normally propagate repaired workspace parent `61b7f48b5aeb7d57246b4963da3df086e79cbe15` into the variation-export child without feature-code conflict or history rewrite; preserve selected-scatter CSV parity, typed unavailable outcomes, bounded accessible tables, linked selection, all-trial arc analysis, and the complete workspace/toolstrip behavior; verify the reconciliation with 25 focused D-plane/impact tests and governance, size, and whitespace gates. | -| 2026-08-10 | 1.14.12 | fix(rate-of-closure, d-plane, #4202 #4203 #4279): normally propagate exact repaired launch-registry parent `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` into the workspace/toolstrip child without rewriting the stack; inherit explicit ndarray result boundaries while preserving numerical semantics, frames, schemas, and UI behavior; verify the reconciled tree with 25 focused D-plane/impact tests and governance, size, and whitespace gates. | -| 2026-08-10 | 1.14.11 | feat/fix(rate-of-closure, #4203 #4218 #4279): normally propagate exact launch-registry parent `31cbc007d4c85b5479b7cd0fb0969124eab2af67` into the workspace/toolstrip child while preserving granular playback, path trails, module visibility, and independent plot controls; reuse the parent's single persisted impact-layer mapping and canonical navigation constants without duplicating state; and retain its focused triple-pendulum, plotting-catalog, and primary-navigation repairs. | -| 2026-08-10 | 1.14.10 | fix(compatibility, #4279): make workspace UTC timestamp parsing deterministic across Python 3.10-3.12 with one anchored canonical grammar, consistent zero- through six-digit fractional-second parsing, and rejection of greater-than-microsecond precision instead of interpreter-dependent rejection or truncation. | -| 2026-08-09 | 1.14.9 | fix(compatibility, #4279): route the child command/view `StrEnum` runtime imports and workspace-validation `UTC` import through `shared.python.compatibility` while preserving native enum typing under `TYPE_CHECKING`, all wire values, schemas, UTC serialization, and UI behavior; merge the parent and child regression into one nine-enum/two-UTC runtime-import contract exercised with real CPython 3.10.20. | -| 2026-08-09 | 1.14.8 | feat(rate_of_closure, #4218 #4279): add a UI-neutral File/View/Tools command registry, strict atomic workspace documents, matched PyQt6/React top toolstrips, persistent module visibility and order, direct Impact/Swing/Flight navigation, deterministic replay/loop/speed controls, and independent per-plot canvases with zoom, Auto Fit, and movable or hidden legends. Propagate exact launch-registry parent `08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` normally while retaining its Linux-safe facade and Python 3.10 compatibility contracts, and type the Qt legend-visibility boundary explicitly for the pinned changed-file mypy gate. | -| 2026-08-10 | 1.14.11 | test/fix(rate-of-closure, #4143 #4202 #4203 #4325): normally propagate repaired launch-registry parent `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` into the shared Ground/Tee parity and rendered-evidence child without production/test-code conflict or history rewrite. | -| 2026-08-10 | 1.14.10 | test(rate-of-closure, #4143): record deterministic Ground/Tee visual evidence through semantic Playwright checks and a hidden-window PyQt capture regression, retaining screenshots as external digested artifacts instead of brittle pixel baselines or repository binaries. | -| 2026-08-10 | 1.14.9 | test(rate-of-closure, #4143): add one strict versioned SI golden fixture consumed by Python and React to pin Ground/Tee defaults, explicit overrides, physical height and center geometry, serialization, invalid finite-domain handling, and backward-compatible legacy migration without changing production behavior. | -| 2026-08-10 | 1.14.8 | feat/fix/refactor(rate-of-closure, #4202 #4203): propagate the exact D-plane parent into the launch-monitor registry without rewriting the stack; preserve the responsive `SimulationViewControlsMixin` architecture while making `ImpactLayerControls` the single owner of persisted D-plane checkbox state; retain the existing automation compatibility seam as an identity alias; and repair the original child's three ungrandfathered size blockers through identity-preserving extractions for triple-pendulum dynamics, immutable plotting metadata, and versioned primary-navigation state. | -| 2026-08-09 | 1.14.7 | fix(compatibility, #4203): route the PyQt torque-profile controller's UTC constant through the shared Python 3.10 compatibility module, preserving UTC timestamp serialization and workspace behavior while removing the remaining parent-owned `datetime.UTC` collection boundary. | -| 2026-08-09 | 1.14.6 | fix(compatibility, #4203): route seven Rate/shared swing string-enum runtime imports through the existing Python 3.10 compatibility contract while retaining native enum typing under `TYPE_CHECKING`; preserve all wire values, schemas, physics, and UI behavior, and add a source-level regression exercised with real CPython 3.10.20. | -| 2026-08-09 | 1.14.5 | fix(ci, #4203): keep the in-package swing flight and solver facade-contract tests in pytest's active package namespace by using relative imports, preventing editable Linux collection from crossing between `src.shared...` and `shared...` before assertions while leaving production APIs and physics unchanged. | | 2026-08-07 | 1.14.4 | feat(rate_of_closure, #4206): add validated manual reference AoA/path, targetward forward shaft lean, and tracked-reference versus registered generated-hosel shaft datums in PyQt6 and React; rotate pose, angular-rate components, and delivered face normals consistently; persist schema-v5 `manual_delivery`; export the reference-contact/reference-impact model boundary; and pin the representative Pitching Wedge decomposition in both runtimes. | | 2026-08-07 | 1.14.3 | fix(variation, #4144): preserve trial identity when filtering finite landing coordinates so carry/lateral values from different incomplete trials cannot form fictitious points; use one paired-row contract for Python/TypeScript ellipse analysis, PyQt/React rendering, and exact plotted-count status. Clarify that the wedge kernel's 20 mm example is synthetic and separately pin the generated Pitching Wedge face-center/hosel cross-check and current UI-state limitations. | | 2026-08-06 | 1.14.2 | feat(rate_of_closure, #4192 #4234): complete the shared spatial-target workflows in PyQt6 and React with canonical cross-tab state, versioned JSON/CSV/manifest persistence, no-run 2D/3D rendering, continuous aerial passage, surface-projected landing assessment, field-linked validation, stale-solver protection, high-DPI canvases, responsive wrapped PyQt forms, collapsible engineering detail/layer controls, and movable or hideable legends; keep aerial requests fail-closed where solver/variation objectives remain ground-only. | @@ -3170,16 +2981,8 @@ Active development with stable core, continuous tool expansion, and web API in p | 2026-08-06 | 1.13.13 | fix(ball-flight, #4199): migrate strategy output to v2; separate policy-fixed true-wind counterfactuals from preset-oracle regret and add failure-inclusive target-hold, miss-distance CVaR, and directional risk metrics with Python/TypeScript parity. | | 2026-08-06 | 1.13.12 | feat(rate_of_closure, #4200): add deterministic timestamp interpolation and accessible play/pause/scrub/speed/restart/Launch/Apex/Landing controls to PyQt6 and React; preserve Matplotlib camera state with mutable markers; add a dependency-free rotatable/zoomable orthographic web canvas with a locked physical metre scale and one cancellable animation loop. | | 2026-08-06 | 1.13.9 | feat(rate_of_closure, swing_sim, #4182 #4183 #4189): add typed reference-frame-explicit 3D D-plane geometry, face-center/contact/reference analyses, exact-versus-planar spin-loft residuals, persistent PyQt6/React engineering layers, and shaded sector exports. | -| 2026-08-06 | 1.13.11 | feat(rate_of_closure, #4200): add deterministic timestamp interpolation and accessible play/pause/scrub/speed/restart/Launch/Apex/Landing controls to PyQt6 and React; preserve Matplotlib camera state with mutable markers; add a dependency-free rotatable/zoomable orthographic web canvas with a locked physical metre scale and one cancellable animation loop. | -| 2026-08-10 | 1.13.11 | fix(swing-sim, d-plane, #4202): add explicit ndarray result boundaries to the private vector conversion and horizontal-projection helpers, closing the exact changed-file MyPy `no-any-return` failures without changing numerical semantics, DbC validation, frames, schemas, or UI behavior. | -| 2026-08-10 | 1.13.10 | feat/fix(rate-of-closure, swing-sim, #4179 #4182 #4183 #4189 #4202): retain typed reference-frame-explicit 3D D-plane geometry, face-center/contact/reference analyses, exact-versus-planar spin-loft residuals, persistent PyQt6/React engineering layers, and shaded sector exports while propagating the Python 3.10 UTC repair and source-wide AST guard through the exact impact-visualization parent; extract persisted D-plane layer controls to restore the protected simulation-view module budget. | -| 2026-08-06 | 1.13.9 | feat(rate_of_closure, swing_sim, #4182 #4183 #4189): add typed reference-frame-explicit 3D D-plane geometry, face-center/contact/reference analyses, exact-versus-planar spin-loft residuals, persistent PyQt6/React engineering layers, and shaded sector exports. | -| 2026-08-10 | 1.13.9 | feat/fix(rate-of-closure, #4162 #4167 #4173 #4174 #4178 #4179): retain exact-event pose/twist/wrist interpolation, the versioned impact-scene contract, locked-scale PyQt6 and React views, named cameras, accessible metrics, and PNG/SVG/JSON exports while propagating the Python 3.10 UTC repair and source-wide AST guard through the exact turf-physics parent. | -| 2026-08-10 | 1.13.8 | feat/fix(golf-club, rate-of-closure, #4166 #4167 #4173 #4174 #4178): retain the passive provenance-gated turf proxy, nine-point wedge contact wrench, strict profile persistence, convergence diagnostics, and explicit force-coupling boundary while propagating the Python 3.10 UTC repair and source-wide AST guard through the exact stacked parent. | | 2026-08-05 | 1.13.7 | feat(rate_of_closure, #4162): add exact-event pose/twist/wrist interpolation; a versioned impact-scene contract; locked-scale orbitable wedge, shaft, ball, contact, orientation, screw-axis, and velocity-decomposition views in PyQt6 and React; named cameras, accessible metric definitions, and PNG/SVG/JSON exports. | -| 2026-08-10 | 1.13.7 | fix(rate-of-closure, #4167 #4173 #4174): propagate the Python 3.10 UTC compatibility repair and source-wide AST guard through the impact-inspector parent into swept wedge ground clearance without rewriting the stacked child or changing its ground-contact contracts. | | 2026-08-06 | 1.13.6 | feat(golf-club, rate_of_closure, #4166): add a passive, provenance-gated compliant turf proxy; nine-point wedge contact wrench; strict profile persistence; cancellation and refinement diagnostics; and a retained-Rate adapter with explicit force-coupling limitations. | -| 2026-08-10 | 1.13.6 | fix(rate-of-closure, #4167 #4173): propagate the Python 3.10 UTC compatibility repair into the impact-inspector child without rewriting its history; torque-profile persistence now uses the shared compatibility export and a source-wide AST guard prevents direct, aliased, or module-attribute `datetime.UTC` regressions. | | 2026-08-06 | 1.13.5 | refactor(gui, ci): deduplicate Rotation Converter plot helpers and extract Movement Optimizer motion helpers, restoring the protected module-size budget inherited by the stacked Rate PRs. | | 2026-08-05 | 1.13.4 | feat(rate_of_closure, golf-club, #4158 #4160 #4163): integrate frame-explicit wedge contact/shaft kinematics into retained Rate runs; add honest impact-or-closest-approach jump controls and engineering readouts to PyQt6 and React; restore manual web angular velocity; and select the documented 30 ms square pose for flat automatic speed plateaus. | | 2026-08-05 | 1.5.5 | fix(ci, #4155): make the Python tool-cache guard inspect `/opt/hostedtoolcache` and optionally require the interpreter's declared link library; run that stronger semantic preflight immediately before the Rust/PyO3 job provisions Python, with Linux fixture and workflow-order contracts. | diff --git a/docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md b/docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md index 9a6195ba7..e3ae4f788 100644 --- a/docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md +++ b/docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md @@ -1,5 +1,38 @@ # Rate of Closure Ball-Flight Campaign Handoff +## 2026-08-11 PR #4342 current-parent propagation candidate + +- PR `#4342` retains branch `feat/4274-regional-plan-io` and base + `feat/4274-regional-surface-ui`. Exact current child + `c1f47f2ef68b3db102da5416aaac17a40f675207` is first and exact reviewed + local #4339 candidate `db335937afc4b587d235eb705e315f577519c5e6` is + second in a normal no-ff merge. +- Child-owned canonical request import/export, bounded UTF-8, native atomic + save, browser-qualified download, tests, and limitations remain intact while + inheriting current editor, wire, regional-physics, and complete ground + ancestry. +- The default shared canonical encoder still rejects floats and integers beyond + JavaScript's safe range. The capability-observation facade alone selects a + separately named extended finite-float policy that reuses the shared + recursion, keeps integers bounded, emits exact exponent-free `1e20` and + `1e21` tokens matching TypeScript, and rejects non-finite values. +- Local qualification passes all `909` Rate-of-Closure Python tests, all `110` + React files / `686` tests, the complete Cargo workspace, `47` focused Python + compatibility/regional-I/O tests, and `12` focused React capability tests. + Pinned Ruff 0.14.10 check/format passes `17` changed Python files; pinned + MyPy 1.13 and Bandit pass `12` changed production files. TypeScript, + zero-warning ESLint, the 199-module Vite build, Rust format and + warning-denied clippy, both changed-file LOC gates, manifest/docs/blocking- + gate/assertion/minimum-test governance, marker scans, and diff checks pass. + One untouched manual-delivery UI test timed out in the first concurrent full + run, then passed alone and in the single complete rerun. +- The candidate has not been rebased, retargeted, rewritten, force-pushed, or + published and remains `not_released`. +- Execution/playback, result interchange, measured calibration, model-input + persistence, changing geometry or velocity, TypeScript/compiled regional + physics, downstream parity, protected exact-head evidence, review, approval, + dependency integration, and release remain open. + ## 2026-08-11 PR #4339 current-parent propagation candidate - PR `#4339` retains branch `feat/4274-regional-surface-ui` and base @@ -29,41 +62,217 @@ physics, downstream parity, protected exact-head evidence, review, approval, dependency integration, and release remain open. + +## 2026-08-11 PR #4342 append-only preservation repair + +Independent audit of local merge `e7fedfb18de1550eed3484ed2fc99d0baaecdca1` +found that three older parent ancestry sections had been summarized instead of +retained verbatim. This docs-only follow-up restores the full parent text below +without changing production code, tests, schemas, manifest state, PR base, or +release claims. The exact parent sections and SPEC rows are now governed by +byte-for-byte comparison against +`d21741e312b849a63f73cabf351a15d9de80fb94`. + +## 2026-08-11 PR #4335 current-parent ancestry candidate + +The clean dedicated `feat/4271-regional-wire-contract` worktree starts from +exact live PR #4335 child `74a053d2d544da9f44a88007660ad28c0127f285` +and normally merges exact newly published PR #4332 parent +`04ccf08dd990de1cd056a3420e67772773a4be2e` as its second parent. PR #4335 +keeps base `feat/4271-regional-surface-transitions`; neither branch is rebased, +retargeted, rewritten, force-pushed, or published by this reconciliation. +Production physics, wire contracts, golden fixtures, numerical ordering, and +public APIs merge byte-exactly; only SPEC, manifest, and handoff records require +truthful reconciliation. + +The child retains the strict cross-runtime regional-plan request/result wire +contract, canonical JSON/SHA-256 evidence, fail-closed parsing, and Python +resolver adapter. The parent retains bounded coplanar regional transitions and +the complete reconciled impact/bounce/skid/roll ancestry. Changing normals, +height or surface-velocity discontinuities, terrain deformation, torsional-spin +damping, roll-to-skid transitions, internal transition-ledger export, regional +UI, compiled or TypeScript regional physics, downstream parity, protected CI, +review, normal stack integration, and main release remain open. This local +merge is not release evidence and requires independent review before an +ordinary fast-forward publication. + +Merged-tree qualification is `132` focused Python ground tests and `9` +focused React regional/ground-contract tests passing. Pinned Ruff 0.14.10 check +and format pass all `45` ground Python files. Pinned MyPy 1.13 passes the exact +two-file isolated CI boundary and all `31` production modules under the coherent +whole-package profile that disables only redundant-cast warnings; those casts +remain required by the isolated protected profile. Bandit reports no +medium/high finding. Documentation governance, manifest validation/layout and +all `8` manifest contracts, changed-production and minimum-test policies, the +official 500-LOC PR-delta gate (`6` files, zero violations), diff checks, and +mandatory maxima of `392` module lines, `46` function lines, and `4` parameters +all pass. + +## 2026-08-11 PR #4332 current-parent ancestry candidate + +The clean dedicated `feat/4271-regional-surface-transitions` worktree starts +from exact live PR #4332 child `1a48d749af508843fac2a5102f4dd56294429bda` +and normally merges exact newly published `feat/4271-ground-skid-roll` parent +`0ea6740965068542e9d8c7449e06ec07d88969e0` as its second parent. PR #4332 +keeps base `feat/4271-ground-skid-roll`; neither branch is rebased, retargeted, +rewritten, force-pushed, or published by this reconciliation. The only textual +merge conflict is the independent SPEC-version collision. SPEC 1.14.27 retains +the regional child record after the parent's 1.14.26 entry; production physics, +contracts, schemas, numerical ordering, and public APIs merge without conflict. + +The child retains bounded coplanar material overlays, explicit precedence, +exact quadratic boundary splitting, base-edge precedence, state and energy +continuity, strict `surface_transition` evidence, request-bound transition +limits, and randomized piecewise-analytic coverage. The current parent retains +its reviewed impact, bounce, skid, roll, resistance, qualified-rest, edge, +composition, and passive-ledger behavior. Changing normals, height or +surface-velocity discontinuities, terrain deformation, torsional-spin damping, +roll-to-skid transitions, regional UI, compiled regional physics, downstream +parity, protected CI, review, normal stack integration, and main release remain +open. This local merge is not release evidence and requires independent review +before an ordinary fast-forward publication. + +Merged-tree qualification is `121` focused Python ground/regional tests and +`5` focused React ground-contract tests passing. Pinned Ruff 0.14.10 check and +format pass all `41` ground Python files; pinned MyPy 1.13 passes all `28` +ground production modules; and Bandit reports no medium/high finding. The +campaign manifest validator and all `8` manifest contracts, documentation +governance, changed-production policy, minimum test contract, both parent and +child diff checks, and the official 500-LOC changed-file gate (`14` files, +zero violations) pass. Production maxima are `392` lines per module, `46` +lines per function, and `4` parameters excluding `self`/`cls`. The manifest +now records open PR #4332 at its still-published child head and open PR #4304 +at its exact newly published parent head; neither record claims protected or +main-release evidence. + +## 2026-08-11 PR #4304 current-parent ancestry candidate + +The clean dedicated `feat/4271-ground-skid-roll` worktree first fast-forwarded +to exact live PR #4304 child `52d9a6a978d8e6b8b19ef92f02f265c9058b00ad`, +then normally merged exact live `feat/4270-ground-impact-bounce` parent +`cf6e72bad98e5f36f782254942e6895b8b71e670`. The PR base remains unchanged; +neither branch was rebased, retargeted, rewritten, force-pushed, or published. +The automatic merge was conflict-free. Its only child-tree change before this +documentation reconciliation is deterministic formatting in the existing +skid/roll regression test; production physics, contracts, schemas, numerical +ordering, and public APIs remain unchanged. + +Local qualification on the merge candidate is `115` focused ground +tests passing on CPython 3.13, pinned Ruff 0.14.10 clean across the ground +package and tests, and pinned MyPy 1.13 clean across all `25` ground production +modules. The manifest validator and all `8` manifest tests, documentation +governance, exact-parent and exact-child diff checks, changed-production policy, +the official changed-file 500-LOC budget, and mandatory production limits of +400 lines per module, 50 lines per function, and four parameters all pass. The +local merge is a PUBLISH candidate for independent review only; protected +exact-head CI, approval, normal child propagation, and publication remain open. + + +## 2026-08-11 PR #4342 current-parent reconciliation candidate + +- The clean `feat/4274-regional-plan-io` worktree normally merges exact + published PR #4342 child `8e1c7ccd99a7c4886c5fb9ccc7e4d94a6d7e3833` + with exact newly published PR #4339 parent + `d21741e312b849a63f73cabf351a15d9de80fb94` as its second parent. +- PR #4342 retains base `feat/4274-regional-surface-ui`; no rebase, retarget, + rewrite, force-push, publication, protected-evidence, or release claim is + made by this reconciliation. +- Strict regional request import/export is preserved. The child widget module + delegates canonical-precision controls to the parent's frozen + `NumberInputSpec` and three-parameter helper while retaining inclusive safe + number bounds and eleven-decimal presentation. +- Merged-tree qualification is 53 focused Python/PyQt/shared-ground tests and + 14 focused React tests passing. Ruff, MyPy, Bandit, TypeScript, zero-warning + ESLint, the 199-module production build, campaign manifest and eight manifest + tests, documentation/tool-manifest governance, changed-Python, minimum-test, + exact-diff assertion, 500-LOC, parent/child diff, and whitespace gates pass. + Structural maxima are 396 module lines, 40 function lines, and three + parameters. +- Independent review, ordinary fast-forward publication, fresh protected + CI/approval, dependency integration, and release remain required. + ## 2026-08-11 PR #4339 structural helper repair candidate -This local follow-up descends exact independently reviewed reconciliation -candidate `eedad6d23b517eb4c99d4ba9000ff6555101099f`. Independent review found -one publication blocker: the regional PyQt number-input helper accepted six -parameters, above the campaign's mandatory four-parameter limit. RED-first -tests now bind the helper's signature and all observable widget settings. A -frozen `NumberInputSpec` validates finite positive step and finite ordered -bounds before widget construction; the three-parameter helper preserves field -names, values, units, ranges, increments, tooltips, and presentation order. - -Eight focused Python/PyQt tests and 25 focused React tests pass; the complete -React suite passes all 108 files / 672 tests. Pinned Ruff check/format, MyPy on -all six affected production modules, Bandit medium/high screening, TypeScript, -zero-warning ESLint, documentation/manifest governance, changed-production, -test-assertion, minimum-test, 500-LOC, and diff gates pass. Mandatory maxima -are 400 module lines, 42 function lines, and three parameters. A broader -Rate-of-Closure Python run reached the ten-minute workstation lifecycle bound -without yielding an assertion failure; it is not counted as passing evidence. -The monorepo-wide lane separately exposed unrelated baseline failures and -xdist worker termination. No schema, digest, regional physics, UI behavior, -PR base, protected evidence, or release boundary changes. +- Parent head `d21741e312b849a63f73cabf351a15d9de80fb94` replaces the regional + PyQt six-parameter input helper with a frozen validated `NumberInputSpec` + and three-parameter helper without changing field behavior or ordering. +- Eight focused Python/PyQt tests, 25 focused React tests, and the complete 672 + React tests pass with Ruff, MyPy, Bandit, TypeScript, ESLint, build, + documentation, manifest, size, structural, and diff gates clean. +- No schema, digest, regional physics, PR base, protected evidence, or release + boundary changes. ## 2026-08-11 PR #4339 current-parent ancestry candidate -The clean `feat/4274-regional-surface-ui` worktree starts from exact published -PR #4339 child `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` and normally merges -exact newly published PR #4335 parent -`9e01ccc3e891cc45907293751a192624195a77a5` as its second parent. The PR -continues to target `feat/4271-regional-wire-contract`; neither branch is -rebased, retargeted, rewritten, or force-pushed. Feature payloads merge without -conflict; only SPEC, manifest, and handoff records require truthful -reconciliation. Independent review, ordinary fast-forward publication, fresh -protected exact-head CI, approval, dependency integration, and release remain -open. +- The parent worktree normally merged exact editor child + `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` with exact published #4335 + parent `9e01ccc3e891cc45907293751a192624195a77a5` while retaining the + `feat/4271-regional-wire-contract` base. +- UI, wire, resolver, regional physics, and ground ancestry were preserved; + protected exact-head review, integration, and release remained open. + +## 2026-08-11 PR #4342 delta-MyPy follow-up + +- Protected CI on exact head + `cffe349ac0a8054f1d168cb36684fd00bc5f8a49` rejected one redundant Boolean + cast in the regional atomic-write adapter. +- The cast is removed and the typed helper's direct return is unchanged. + Focused persistence tests and the CI-equivalent pinned MyPy command pass. +- No wire, validation, file, UI, or physics behavior changes. Fresh protected + CI/review and dependency ordering remain open. + +## 2026-08-11 regional request I/O protected publication + +- Branch `feat/4274-regional-plan-io` is published normally as draft PR + [#4342](https://github.com/D-sorganization/Tools/pull/4342), targeting exact + PR #4339 branch `feat/4274-regional-surface-ui` at parent head + `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980`. +- Reviewed implementation head + `d748e7a5ef3da5e6ce7737ff6829e0f14665fe97` includes canonical PyQt6/React + request import/export, safe-number parity, and bounded strict UTF-8 native + reads. Publication documentation commits change no runtime code. +- Protected CI, review, #4274, dependency ordering, integration, and release + remain open. + +## 2026-08-11 bounded regional request read follow-up + +Independent review of local safe-number commit +`10c394f6b1fd2927e7f3b1f96cc097cae6bfd380` found that native request import +checked file size with `stat()` and then performed a separate unbounded text +read. A concurrently grown or replaced file could therefore allocate beyond +the 1 MiB wire cap before the strict parser rejected it. + +Native import now opens one binary handle, reads at most the wire cap plus one +sentinel byte, rejects overflow, strictly decodes UTF-8, and only then delegates +to the unchanged canonical v1 parser. Tests simulate content growth after the +metadata check and reject invalid UTF-8 explicitly. The complete regional and +atomic persistence set is 28 tests passing. This changes no schema, digest, +physics, browser behavior, or write semantics. Static and governance evidence +is recorded in this commit: Ruff, Ruff format, Black, focused MyPy, manifest, +module-size, documentation-governance, and diff checks pass. The child remains +local and unprotected. + +## 2026-08-11 regional request I/O safe-number follow-up + +Independent review of local commit `e39edf4b50b1fb9811b0032bec4758c7a08c9b74` +found two cross-runtime representation gaps. The PyQt6 precedence spin box +silently narrowed otherwise valid v1 integers above 1,000,000, and Python +accepted integer-valued wire numbers above JavaScript's exact safe range. + +The native editor now uses an exact decimal integer entry for precedence and +preserves every v1 value from zero through 9,007,199,254,740,991 without a +floating-point conversion. Shared Python canonical-number and ground-record +validation now reject magnitudes outside that same range, matching React while +retaining all finite fractional values inside it. PyQt6 floating-point editors +publish the same bounds. Regression coverage pins exact maximum-precedence +open/save round-trip and matched native/browser refusal of unsafe material +numbers. This changes no schema version, provenance algorithm, physics, or +browser filesystem limitation. Final local evidence is 132 shared ground tests, +21 regional editor/I/O tests, five atomic-workspace tests, 23 focused React +tests, the whole-shell tooltip sweep, and eight manifest tests passing. Ruff, +Ruff format, Black, focused MyPy, TypeScript, zero-warning ESLint, the 199-module +production build, module and changed-file size budgets, documentation +governance, and diff checks pass. The child remains local and unprotected. ## 2026-08-10 PR #4339 stale-validation invalidation follow-up @@ -81,6 +290,43 @@ and diff checks are clean. The known polynomial-generator empty-legend warning is unrelated. This changes no wire schema, provenance digest, physics, or persistence boundary; fresh protected CI is still required before merge. +## 2026-08-10 issue #4274 canonical regional request I/O local child + +Local branch `feat/4274-regional-plan-io` started directly from published PR +#4339 head `a9ace5052bcd54b78f79b62d5d9ac26debedb4b1`, then fast-forwarded +normally to corrected exact parent `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980`. +The parent's stale-validation invalidation and tooltip follow-up are preserved. +This child has not been pushed, opened as a PR, reviewed, merged, or released. + +The matched Ground Surfaces editors now import and export the canonical +`ground-regional-material-plan-request/v1` document. PyQt6 uses native Open +and Save As dialogs plus a shared flush/fsync/atomic-replace UTF-8 writer; +cancel is a no-op, failed reads and writes preserve the last-known-good editor +or file, and the recent path advances only after success. React validates a +bounded browser File before committing state and downloads exact canonical +bytes while revoking its object URL. Browser filesystem limitations are +explicit, and workspace persistence remains separate. + +Import accepts only editor producer/provider v1 evidence, the fixed target +frame origin/downrange axis, and one to eight rows. It never relabels external +evidence. An unchanged import round-trips the exact request and provenance; +after any edit, validation binds a fresh draft digest. No measured calibration +is synthesized and neither path executes physics. + +RED-first coverage now includes exact-byte round-trip, native cancel and +atomic rollback, corruption, duplicate keys, oversize input, unsupported +producer/axis qualification, stale-provenance rebinding, transactional PyQt6 +population, browser rollback, URL cleanup, and pre-allocation size rejection. +Focused evidence is 25 Python/PyQt tests and 12 React tests passing. With +adjacent wire and manifest coverage, 44 Python and 16 React tests pass. +Focused MyPy, Ruff, TypeScript, zero-warning ESLint, the 199-module production +build, release-manifest validation, and module budgets are clean. + +Issue #4274 remains open. Measured calibration, workspace model-input +persistence, execution/playback, result interchange, visualization, changing +geometry, compiled regional physics, downstream parity, protected CI/review, +integration of this child into the protected stack, and release remain explicit +gaps. ## 2026-08-10 issue #4274 matched regional surface editor local child Local branch `feat/4274-regional-surface-ui` started from published PR #4335 @@ -125,63 +371,7 @@ terrain/interval visualization, TypeScript or compiled regional physics, UpstreamDrift parity, protected CI/review, parent integration, and main release remain open. -## 2026-08-11 Current regional-surface parent propagated into regional wire - -- Open draft PR `#4335` retains branch `feat/4271-regional-wire-contract` and - base `feat/4271-regional-surface-transitions`. Exact remote regional-wire - child `9e01ccc3e891cc45907293751a192624195a77a5` is merged first and exact current - regional-surface parent `5ac3c1f233de30dd42eeac57073cbdb149bde652` - second by an ordinary no-ff merge. -- Strict Python/TypeScript regional-plan schemas, canonical JSON/SHA-256 - fixture evidence, fail-closed parsing, Python resolver binding, tests, - contracts, limitations, and both append-only histories remain intact. -- Focused local qualification passes all `132` Python ground/regional-wire - tests, `9` focused React regional/ground-contract tests, and all `137` - `tools-core` Rust tests. TypeScript, zero-warning ESLint, the 190-module Vite - build, Rust format and warning-denied clippy, pinned Ruff 0.14.10 across six - changed Python files, pinned MyPy 1.13 and Bandit medium/high across four - production files, the 500-LOC changed-file gate, manifest parsing plus eight - contracts, documentation governance, exact wire-tree preservation, - history/marker, and diff checks pass. -- The candidate is unpublished and `not_released`; changing geometry or - velocity, internal transition-ledger export, regional UI, compiled or - TypeScript regional physics, UpstreamDrift parity, protected exact-head CI, - review, approval, dependency integration, and release remain open. - -## 2026-08-11 PR #4335 current-parent ancestry candidate -The clean dedicated `feat/4271-regional-wire-contract` worktree starts from -exact live PR #4335 child `74a053d2d544da9f44a88007660ad28c0127f285` -and normally merges exact newly published PR #4332 parent -`04ccf08dd990de1cd056a3420e67772773a4be2e` as its second parent. PR #4335 -keeps base `feat/4271-regional-surface-transitions`; neither branch is rebased, -retargeted, rewritten, force-pushed, or published by this reconciliation. -Production physics, wire contracts, golden fixtures, numerical ordering, and -public APIs merge byte-exactly; only SPEC, manifest, and handoff records require -truthful reconciliation. - -The child retains the strict cross-runtime regional-plan request/result wire -contract, canonical JSON/SHA-256 evidence, fail-closed parsing, and Python -resolver adapter. The parent retains bounded coplanar regional transitions and -the complete reconciled impact/bounce/skid/roll ancestry. Changing normals, -height or surface-velocity discontinuities, terrain deformation, torsional-spin -damping, roll-to-skid transitions, internal transition-ledger export, regional -UI, compiled or TypeScript regional physics, downstream parity, protected CI, -review, normal stack integration, and main release remain open. This local -merge is not release evidence and requires independent review before an -ordinary fast-forward publication. - -Merged-tree qualification is `132` focused Python ground tests and `9` -focused React regional/ground-contract tests passing. Pinned Ruff 0.14.10 check -and format pass all `45` ground Python files. Pinned MyPy 1.13 passes the exact -two-file isolated CI boundary and all `31` production modules under the coherent -whole-package profile that disables only redundant-cast warnings; those casts -remain required by the isolated protected profile. Bandit reports no -medium/high finding. Documentation governance, manifest validation/layout and -all `8` manifest contracts, changed-production and minimum-test policies, the -official 500-LOC PR-delta gate (`6` files, zero violations), diff checks, and -mandatory maxima of `392` module lines, `46` function lines, and `4` parameters -all pass. ## 2026-08-10 PR #4335 isolated-MyPy return typing @@ -231,66 +421,8 @@ This child remains `not_released`. Protected CI, independent review, normal stack integration, UI, TypeScript/Rust/PyO3/WASM regional physics, changing normals/heights/velocities, internal transition-ledger wire export, UpstreamDrift parity, and main release remain open. -## 2026-08-11 Current skid/roll parent propagated into regional surfaces - -- Open draft PR `#4332` retains branch - `feat/4271-regional-surface-transitions` and base - `feat/4271-ground-skid-roll`. Exact remote regional-surface child - `04ccf08dd990de1cd056a3420e67772773a4be2e` is merged first and exact current - skid/roll parent `3f861c1faaa7455faee92eaa7f813174667208e0` - second by an ordinary no-ff merge. -- Bounded coplanar material overlays, precedence, exact boundary splitting, - transition evidence, continuity, regional production, tests, fixtures, - contracts, limitations, and both append-only histories remain intact. -- Focused local qualification passes all `121` Python ground/regional tests, - `20` focused React ground-contract/transfer tests, and all `137` `tools-core` - Rust tests. TypeScript, zero-warning ESLint, the 189-module Vite build, Rust - format and warning-denied clippy, pinned Ruff 0.14.10 across 14 changed - Python files, pinned MyPy 1.13 and Bandit medium/high across 12 production - files, the 500-LOC changed-file gate, manifest parsing plus eight contracts, - documentation governance, exact child-tree preservation, history/marker, - and diff checks pass. -- The candidate is unpublished and `not_released`; changing normals, - discontinuous geometry or surface velocity, regional UI, compiled regional - physics, UpstreamDrift parity, protected exact-head CI, review, approval, - dependency integration, and release remain open. - -## 2026-08-11 PR #4332 current-parent ancestry candidate - -The clean dedicated `feat/4271-regional-surface-transitions` worktree starts -from exact live PR #4332 child `1a48d749af508843fac2a5102f4dd56294429bda` -and normally merges exact newly published `feat/4271-ground-skid-roll` parent -`0ea6740965068542e9d8c7449e06ec07d88969e0` as its second parent. PR #4332 -keeps base `feat/4271-ground-skid-roll`; neither branch is rebased, retargeted, -rewritten, force-pushed, or published by this reconciliation. The only textual -merge conflict is the independent SPEC-version collision. SPEC 1.14.27 retains -the regional child record after the parent's 1.14.26 entry; production physics, -contracts, schemas, numerical ordering, and public APIs merge without conflict. -The child retains bounded coplanar material overlays, explicit precedence, -exact quadratic boundary splitting, base-edge precedence, state and energy -continuity, strict `surface_transition` evidence, request-bound transition -limits, and randomized piecewise-analytic coverage. The current parent retains -its reviewed impact, bounce, skid, roll, resistance, qualified-rest, edge, -composition, and passive-ledger behavior. Changing normals, height or -surface-velocity discontinuities, terrain deformation, torsional-spin damping, -roll-to-skid transitions, regional UI, compiled regional physics, downstream -parity, protected CI, review, normal stack integration, and main release remain -open. This local merge is not release evidence and requires independent review -before an ordinary fast-forward publication. -Merged-tree qualification is `121` focused Python ground/regional tests and -`5` focused React ground-contract tests passing. Pinned Ruff 0.14.10 check and -format pass all `41` ground Python files; pinned MyPy 1.13 passes all `28` -ground production modules; and Bandit reports no medium/high finding. The -campaign manifest validator and all `8` manifest contracts, documentation -governance, changed-production policy, minimum test contract, both parent and -child diff checks, and the official 500-LOC changed-file gate (`14` files, -zero violations) pass. Production maxima are `392` lines per module, `46` -lines per function, and `4` parameters excluding `self`/`cls`. The manifest -now records open PR #4332 at its still-published child head and open PR #4304 -at its exact newly published parent head; neither record claims protected or -main-release evidence. ## 2026-08-10 issue #4271 coplanar regional-material local child Local branch `feat/4271-regional-surface-transitions` starts from exact current @@ -327,555 +459,10 @@ regional physics, UpstreamDrift parity, protected CI, review, normal stack integration, and main release remain open. Region plans and from/to identity records are execution-scoped non-wire data in this child. -## 2026-08-11 Current impact/bounce parent propagated into skid/roll - -- Open draft PR `#4304` retains branch `feat/4271-ground-skid-roll` and base - `feat/4270-ground-impact-bounce`. Exact remote skid/roll child - `0ea6740965068542e9d8c7449e06ec07d88969e0` is merged first and exact current - impact/bounce parent `62beb3e1aa951645fd556a53f9cbae4bb46c47e5` - second by an ordinary no-ff merge. -- The child-owned arbitrary-plane skid, static-feasible pure roll, rolling - resistance, qualified rest, edge localization, strict result composition, - passive ledgers, tests, fixture, and limitations remain intact with both - append-only handoff/SPEC histories. -- Local verification passes `154` focused ground/flight tests, all eight - campaign-manifest tests, and all `137` `tools-core` Rust tests. Pinned Ruff - 0.14.10 covers 18 PR-delta Python files; pinned MyPy 1.13 and Bandit - medium/high cover 12 production files. Rust format/clippy, manifest, docs, - exact child-tree, history/marker, and diff gates pass. -- This remains a local `not_released` candidate. Regional/changing-normal - surfaces, deformation, torsional damping, roll-to-skid transitions, UI, - compiled physics, publication, protected exact-head CI, review, approval, - downstream integration, and release remain open. - -## 2026-08-10 PR #4302 corrected-flight-transfer propagation - -Draft PR #4302 remains on `feat/4270-ground-impact-bounce` with unchanged base -`feat/4269-flight-ground-transfer`. Exact corrected #4288 parent -`247215422a6d4b677552955b4923bc609a553259` is incorporated by the normal merge -containing this handoff. The child preserves its passive restitution/Coulomb -sphere-plane impulse, deterministic repeated ballistic hops, exact physical -contact, capture-to-skid handoff, cancellation/failure semantics, and airborne -segment evidence while inheriting the corrected transfer ancestry, deterministic -workspace timestamps, and canonical `swing_sim` import identity. No branch was -rebased, retargeted, rewritten, or force-pushed. - -The child implementation is the scoped Python reference prefix from -`docs/specs/GROUND_IMPACT_BOUNCE.md`: it includes full spin, moving-boundary -accounting, exact first contact, bounded repeat-hop execution, typed airborne -segments, and a shared golden fixture. It remains partial and `not_released`. -Issue #4271 retains skid, roll, rest, total distance, and final -`GroundSimulationResult`; terrain deformation, UI execution, TypeScript bounce -physics, compiled Rust/PyO3/WASM bounce parity, and UpstreamDrift adapters remain -excluded. Protected CI, independent review, and dependency-ordered collapse -remain separate release gates. - -Merged-tree validation is `987` Python tests, `106` React files / `661` tests, -and the complete `tools-core` Rust suite at `137` tests (`111` unit, `20` -transfer, `6` wire). The affected cross-version suite is also `146` tests on -real CPython 3.10.20. The 189-module Vite production build, TypeScript, -zero-warning ESLint, Ruff check/format across 90 files, pinned mypy 1.13 across -all 17 ground and nine transfer production modules, Rust workspace format plus -warning-denied `tools-core` clippy, campaign-manifest validator plus eight -contracts, documentation governance, 11-file 500-LOC budget, marker scan, and -diff checks are clean. Hosted checks and review apply to the new exact merge -head only. - - -## 2026-08-10 PR #4288 corrected-ground propagation - -Draft PR #4288 remains on `feat/4269-flight-ground-transfer` with unchanged -base `feat/4268-ground-contract`. Exact corrected #4285 parent -`788aa547651a3685a363ea401824a5d81477bafb` is incorporated by the normal merge -containing this handoff. The child retains its qualified signed terminal state, -physical sphere/terrain contact brackets, strict provenance, and cross-runtime -Python/TypeScript/Rust/PyO3/WASM contracts while inheriting deterministic -workspace timestamps and canonical `swing_sim` import identity. No branch was -rebased, retargeted, rewritten, or force-pushed. - -This propagation does not add bounce, skid, roll, terrain response, total -distance, or UI execution. Protected CI, independent review, and normal -dependency-ordered collapse remain separate release gates. - -Merged-tree validation is `951` Python tests, `106` React files / `661` tests, -and `26` focused Rust transfer/wire tests. The affected cross-version suite is -also `110` tests on real CPython 3.10.20. The 189-module Vite production build, -TypeScript, zero-warning ESLint, Ruff check/format across 82 files, pinned mypy -1.13 across the six-file transfer and 13-file parent production namespaces, -Rust workspace format plus warning-denied `tools-core` clippy, campaign-manifest -validator plus eight contracts, documentation governance, 13-file 500-LOC -budget, marker scan, and diff checks are clean. Hosted checks and review apply -to the new exact merge head only. - - -## 2026-08-10 PR #4282 workspace timestamp propagation - -Exact corrected #4281 parent -`cf52529b1e68479321bb93b1be3d59c77f782008` is incorporated into -`feat/4199-wind-workflow` by the normal merge containing this handoff. PR #4282 -keeps base `feat/4199-wind-scalar-adapter`; neither branch was rebased, -retargeted, rewritten, or force-pushed. The consolidated wind/capability -workflow inherits the deterministic Python 3.10-3.12 UTC parser, variation -export, and scalar-ensemble history without changing its own behavior. - -The monotonic SPEC assigns 1.14.10 to compatibility, 1.14.11 to variation, -1.14.12 to the scalar adapter, and 1.14.13 to this workflow carrier. The -reconciled tree passes `924` combined Python tests, `28` direct compatibility -tests on real CPython 3.10.20, and `104` React files / `642` tests. The Vite -production build, TypeScript, zero-warning ESLint, Ruff, format, pinned mypy -1.13, campaign-manifest validator and its eight contracts, documentation -governance, source-size, conflict-marker, and diff gates are clean. Protected -CI, review, and downstream propagation remain open. - - -## 2026-08-10 PR #4280 workspace timestamp propagation - -Exact parent `05383d333b6fd87eaf5e37305476f50b505c2c2e` is incorporated into -`feat/4144-variation-export-continuation` through the normal merge containing -this handoff. PR #4280 keeps base `feat/4218-toolstrip-workspace`; neither -branch was rebased, retargeted, force-pushed, or rewritten. The reconciled tree -retains all variation export/accessibility behavior and adds the strict -cross-version workspace timestamp parser. - -SPEC 1.14.10 remains the parent compatibility entry and SPEC 1.14.11 becomes -the child variation entry. The reconciled tree passes `778` Rate tests, `27` -real-Python-3.10.20 compatibility tests, `1 file / 8` focused React tests, -TypeScript, focused zero-warning ESLint, Ruff, format, and pinned mypy 1.13. -Documentation, size, and diff gates must remain clean in the merge commit. -Protected CI, review, and later propagation remain open. - - -## 2026-08-09 PR #4280 variation-export propagation - -Draft #4280 remains based on `feat/4218-toolstrip-workspace` and includes exact -corrected parent `3f67ed466fefc8991db9c4409f921f25e1c37142` through a normal -merge. The child retains complete selected-scatter-axis CSV export parity, -typed unavailable rows, PyQt accessible raw tables, and the focused -table/scatter/matrix split. - - -## 2026-08-10 PR #4279 fractional timestamp compatibility - -Descendant PR #4281's exact-head Python 3.10 lane failed the workspace instant -ordering regression because that interpreter rejects one-, two-, four-, and -five-digit fractional seconds before comparison. The correction belongs on -the earliest carrier, PR #4279: enforce one anchored UTC grammar, parse zero -through six fractional digits consistently, and reject precision beyond -microseconds instead of allowing newer interpreters to truncate it. -Persisted JSON remains unchanged and UTC-only validation stays authoritative. - -Local evidence is `778 passed` for the full Rate suite, `45 passed` for the -workspace/compatibility suites, and `27 passed` for the direct compatibility -suite on CPython 3.10.20. Ruff, format, pinned mypy 1.13, docs governance, and -the 400-line budget pass. Publication is not completion: verify the exact -remote head/base, push normally, then propagate in stack order through #4280, -#4281, #4282, and every later descendant that carries the workspace. - - -## 2026-08-09 Capability results stabilization - -The isolated `feat/4201-capability-results-diagnostics` continuation is based -on exact wind-workflow carrier head `18fe89201`. It closes two audit findings -without changing the optimizer or physics: both clients expose every ranked -diagnostic and parameter unit, both provide result CSV plus versioned result -JSON, and React scalar scatters now carry numeric scales and cohort legends. -Raw observation exports remain lossless and distinct. This is feature-stack -implementation evidence only; #4197/#4201 remain open through integration, -hosted CI, review, downstream parity, and release to `main`. - -Local evidence: 813 Rate Python/PyQt tests and 104 React files / 628 tests, -Ruff check/format, targeted mypy for the new export and tab modules, TypeScript, -zero-warning ESLint, and the 188-module Vite production build passed. The -pre-existing mypy 1.19.1/Python 3.13 internal serialization assertion on -`capability_results.py` reproduces unchanged at carrier `18fe89201`. - - -## 2026-08-09 Web-release stability continuation - -Local branch `feat/4201-web-release-stability` is based exactly on campaign -carrier `18fe89201`. It fixes direct-path execution of -`src/rate_of_closure/launch_web.py`, adds a subprocess delegation smoke -contract, and reconciles the supported release boundary to the files that -exist: static Vite web output plus PyQt6/PyInstaller desktop output. Rate has -no `src-tauri` project, so its stale Tauri scripts, CLI dependency, lockfile -entries, and current documentation claims were removed instead of inventing an -unqualified wrapper. - -The load-sensitive `FlightExplorerPanel` assertion now explicitly settles the -real lazy Wind Strategy import inside React `act`; it does not extend a timeout -or replace the child component with a mock. This is test synchronization only, -not a UI or physics change. The branch must remain local until reviewed and -folded into the established campaign carrier; no PR, push, or merge belongs to -this handoff slice. - -Exact local evidence: 813 Rate Python/PyQt tests passed with 15 existing -warnings; 9 launcher/registration tests passed; 102 React files / 624 tests -passed; and five sequential focused Flight Explorer runs passed 25/25 tests. -TypeScript type-check, zero-warning ESLint, the 187-module static build, -focused Ruff check/format, targeted mypy, package installation/audit, and diff -checks pass. `tests/test_dry_compliance.py` retains two unrelated baseline -failures for the Movement Optimizer and Optimizer GUI PyQt launchers. - - -## 2026-08-09 Machine-readable campaign authority - -`docs/release/rate_of_closure_campaign.v1.json` is now the canonical current -state for the primary Rate, impact, flight, variation, club-builder, wedge, -toolstrip, design-quality, parity, and ground programs. Its normalized carrier -and evidence tables replace status inference from the chronological entries -below. `scripts/rate_campaign_manifest.py` supplies strict Pydantic validation -and a generated JSON Schema; it rejects missing programs, unresolved evidence, -placeholders, malformed SHAs, and contradictory release claims. - -The authority records the current campaign as **not released**. Capability PRs -#4294, #4289, and #4283 are merged into feature parent #4282, but those were not -protected `main` merges. Current carrier head `18fe89201` contains the hermetic -`swing_core` parity-lane correction and its focused workflow regression; a -fresh hosted parity run, top-down stack propagation, #4133 reconciliation, -#4119 current-main conflict resolution, protected checks, installed-package -evidence, and UpstreamDrift parity are still required. - -Maintain the JSON authority and the current-state handoffs in the same commit -whenever a carrier SHA, test result, limitation, supported surface, or release -stage changes. Historical detail below remains useful provenance but must not -override a contradictory validated manifest record. - -The four reviewed stabilization slices are composed on implementation head -`2c1a77baa`: strict workflow parsing/signed editing, complete capability -diagnostics and result exports, static-web entrypoint/package truth, and this -manifest authority. Combined local evidence is 828 Rate Python/PyQt tests and -104 React files / 642 tests, TypeScript, zero-warning ESLint, the 188-module -Vite build, Ruff, targeted mypy, deterministic manifest/schema validation, and -nine manifest/parity contracts. This remains local evidence; #4282 still needs -a normal push, exact-head hosted CI, review, and dependency-ordered release. - -The first exact-head hosted quality gate (`31340032608`) passed checkout, -dependency installation, Ruff, and formatting, then failed mypy 1.13 because -`--follow-imports=skip` exposed Pydantic and Qt boundary returns as `Any`. The -loader now casts the validated model and the playback adapter converts elapsed -milliseconds to a concrete `float`; these are static typing fixes, not schema -or runtime behavior changes. The exact Python 3.12/mypy 1.13 command passes all -54 delta files; Ruff, 62 focused regression tests, and eight campaign-manifest -tests pass locally. - - -## 2026-08-11 Current flight-transfer parent propagated into ground impact - -- Open draft PR `#4302` retains branch `feat/4270-ground-impact-bounce` and base - `feat/4269-flight-ground-transfer`. Exact remote bounce child - `cf6e72bad98e5f36f782254942e6895b8b71e670` is merged first and exact current - transfer parent `c39297d37a17d5d8d3520ed62c5563cdcc609cab` second by an - ordinary no-ff merge. -- Passive sphere-plane impact, restitution/friction, deterministic repeated - bounce, exact contact, capture-to-skid handoff, cancellation/failure evidence, - and the full current transfer ancestry are retained with both append-only - handoff/SPEC histories. -- Three inherited PR-delta Python files receive AST-equivalent pinned Ruff - 0.14.10 normalization; analysis, persistence, and contract assertion behavior - are unchanged. -- Local verification passes `1129` Rate/ground/flight Python tests, `25` - focused React transfer tests, and all `137` `tools-core` Rust tests, plus - TypeScript, zero-warning ESLint, the 189-module build, Rust format/clippy, - pinned Ruff 0.14.10, pinned MyPy 1.13, Bandit medium/high, manifest parsing, - history preservation, and diff checks. -- This remains a local `not_released` candidate. Skid, roll, rest, total - distance, final ground results, UI, TypeScript bounce physics, compiled bounce - runtimes, publication, protected exact-head CI, review, approval, dependency - integration, and release remain open. - -## 2026-08-10 PR #4285 workspace timestamp propagation - -Draft PR #4285 remains on `feat/4268-ground-contract` with unchanged base -`feat/4197-capability-observer`. Exact corrected #4282 carrier -`5f77af4add23547a21cc3fabce98ae9ad4260427` is incorporated through the normal -merge containing this handoff. The strict ground-contract child retains its -schemas, canonical fixture, migrations, legacy-result adapter, declared -dependency, and pinned typing repairs while inheriting the deterministic Python -3.10-3.12 UTC parser and the corrected variation, scalar, wind, capability, and -campaign-release ancestry. No branch was rebased, retargeted, rewritten, or -force-pushed. - -The preceding exact-head Python 3.12 job then exposed an import-order defect, -not a physics failure: embedded `src.shared.python.swing_sim` test packages and -canonical `shared.python.swing_sim` imports could become distinct module trees, -so ground and impact contract collection failed. The shared alias registry now -coalesces `swing_sim`; a subprocess identity regression was RED before the fix -and passes with both affected public-API suites afterward. The contemporaneous -file-size run was cancelled during checkout before its budget step, so no size -violation was reported. - -Merged-tree evidence is `915` Rate/ground/impact Python tests, the full -`12`-test shared-alias architecture suite, `28` focused tests on CPython 3.12, -`28` direct compatibility tests on real CPython 3.10.20, and `104` React files / -`642` tests. The 188-module Vite build, TypeScript, zero-warning ESLint, Ruff, -format, pinned mypy 1.13, campaign-manifest validator plus eight contracts, -documentation governance, the 44-file 500-LOC budget, marker scan, and diff -checks are clean. Hosted CI and review still apply only to the new exact head. - -This is ancestry reconciliation, not new landing physics. Qualified bounce, -skid, roll, terrain profiles, total distance, UI execution, Rust/WASM parity, -protected CI, review, and release remain open. PR #4288 must normally merge the -resulting exact #4285 head before its transfer behavior is evaluated as a -descendant of the corrected carrier. - -## 2026-08-11 Current strict-ground parent propagated into flight transfer - -- Open draft PR `#4288` retains branch `feat/4269-flight-ground-transfer` and - base `feat/4268-ground-contract`. Exact remote child - `df716ac740beb9d47dced66f867dc3dde1fa5367` is merged first and exact current - parent `584e4e53a7990053a346938c4e45538786887ec7` second by an ordinary - no-ff merge. -- The child-owned Python/TypeScript/Rust/PyO3/WASM transfer, physical contact - evidence, production, tests, fixtures, and limitations remain intact. Only - append-only handoff/SPEC conflicts require aggregation, preserving every dated - record from both parents. -- Focused verification passes 85 Python contract/transfer tests, 25 React tests, - and 137 Rust library and transfer/wire tests. Pinned Ruff 0.14.10 covers 13 - PR-delta Python files, pinned MyPy 1.13 covers nine production files, and - Bandit reports no medium/high findings. TypeScript, exact-delta ESLint, the - 189-module build, Rust format, docs, strict manifest, diff, exact transfer-tree, - and both-parent preservation checks pass. -- This bounded local audit does not authorize publication or release. Protected - exact-head CI, review, approval, and release remain open. - -## 2026-08-11 PR #4288 append-only history preservation repair - -This documentation-only follow-up to exact local candidate -`1eb4188ff1a87a3d8e9a55aeca68194ca04e0bb4` restores every omitted #4285 -parent handoff section and specification history row verbatim. It repairs one -interleaved rate-of-closure paragraph without changing implementation, tests, -schemas, manifest data, merge topology, or #4288's -`feat/4268-ground-contract` base. The repaired candidate remains local pending -independent review, ordinary publication, fresh protected CI, approval, -dependency integration, and release. - -## 2026-08-11 PR #4288 current-ground-parent ancestry candidate - -Draft PR #4288 remains on `feat/4269-flight-ground-transfer` with unchanged -base `feat/4268-ground-contract`. Exact published child -`afb1bdcfc6701caaf1f7bc3497a6a37dd9698c14` normally merges exact newly -published #4285 parent `e09ab96280cab363b36bd0e7db4a3cd064dc2527` -second. The child keeps its bounded TypeScript integrator and qualified -cross-runtime terminal-state/contact transfer; the parent contributes the -current strict-ground, wind/capability, split-kinetics, plotting-catalog, and -format ancestry. Seven child-owned Python files receive pinned Ruff 0.14.10 -normalization with no AST change, and the child TypeScript facade is retained -with standard line endings. No branch is rebased, retargeted, rewritten, force-pushed, or -released. Independent review, ordinary publication, fresh protected exact-head -CI, approval, dependency integration, and release remain required. - -## 2026-08-11 Current capability carrier propagated into ground contract - -- Open draft PR `#4285` retains `feat/4268-ground-contract` over - `feat/4197-capability-observer`. Exact remote child - `e09ab96280cab363b36bd0e7db4a3cd064dc2527` is merged first and exact current - capability-observer carrier `d0b827667e61f0583e1dad0b3cbbca6819624d3c` - second by an ordinary no-ff merge. -- The merge preserves the complete strict flight-to-ground contract tree and - all current wind/capability ancestry. Only append-only handoff/SPEC documents - conflict; every dated record from both histories is retained. -- Focused validation passes 214 Python/PyQt tests. Pinned Ruff 0.14.10 covers - all 27 PR-delta Python files, pinned MyPy 1.13 covers all 20 production files, - and Bandit reports no medium/high findings. Docs, strict manifest, diff, exact - ground-tree, and append-only preservation checks pass. -- This local candidate is not published or released. Protected exact-head CI, - review, approval, and normal descendant propagation into #4288 remain open. - -## 2026-08-11 Current workflow/base ancestry reconciled into ground contract - -- Draft PR `#4285` remains on `feat/4268-ground-contract`, based on - `feat/4197-capability-observer`. Exact remote child - `7a38b9838d743e051a6900620c4d6e754582aa89` is the first parent and exact - published base/workflow head - `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is merged second. -- GitHub ancestry established that the published base contains exact merged - #4283 head `9bbb98e16e435a0d4c74153b909f2ebfefbbce7a` before this reconciliation. - No branch is rebased, retargeted, force-pushed, or rewritten. -- Ground-contract behavior is preserved. The only source conflict is an - obsolete formatting-only edit to monolithic kinetics and resolves to the - parent's validated split facade; all append-only documentation histories - remain present. -- The retained child `float` narrowing selects the plotting catalog as changed. - Its literal registry is split by scalar and series responsibility behind the - unchanged public catalog facade, restoring the strict 400/50/4 production - budgets while preserving registry order and behavior. -- Complete local evidence is 1,539 passed with one optional Rust-wheel skip for - Rate/shared-swing Python, 106 React files / 648 tests plus type-check, lint, - and the 188-module build, and 12 Rust tests. The focused contract/parity/ - kinetics/wind/manifest suite passes 146 tests and the catalog/plot regression - suite passes 57 tests. -- This local candidate is not published or released. Independent exact-head - review, ordinary publication, fresh protected CI, required approval, and a - later normal descendant merge into #4288 remain release gates. - -## 2026-08-11 merged capability-observer carrier receives current #4282 - -- Merged PR `#4283` used `feat/4197-capability-observer`, which remains the - current base of open draft PR `#4285`. Exact remote/local carrier child - `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is the first parent and exact - published #4282 head `3faf9e9493c9ba37168d9f65ab10cafeedc2a72f` - is the second parent of this normal local no-ff merge. -- The carrier is already an ancestor of #4282, so all implementation merges - without conflict. The exact #4282 responsive wind/capability/manifest tree and - the complete merged capability-observer history are preserved; only this - current carrier handoff and SPEC release row are intentionally added. -- Focused validation is green: 86 Python/PyQt capability, wind, and campaign- - manifest tests and all 86 tests in 12 focused React capability/wind suites - pass. React type-check, zero-warning lint, and the production build pass. Docs - governance, strict campaign-manifest validation, and exact-parent diff hygiene - pass. The exact #4282 delta is documentation-only, so changed-Python - Ruff/MyPy/Bandit gates are not applicable. -- This bounded audit does not authorize publication. Independent review, - ordinary branch publication, protected exact-head CI, - and later #4285 propagation remain open. - -## 2026-08-11 current scalar-adapter propagation into wind workflow PR #4282 - -- PR `#4282` remains on `feat/4199-wind-workflow`, based on - `feat/4199-wind-scalar-adapter`. Exact published child - `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is the first parent and exact - newly published scalar-adapter head - `9321c1d2e091b8c7e5a4a83aa9ad726290e7fb5a` is the second parent of this - normal local merge. -- Production and test paths merge automatically. Responsive PyQt6/React wind - execution, progress/cancellation, controls, scatter, persistence/export, - consolidated capability workflow, and strict campaign release authority - remain authoritative while inheriting the current scalar-adapter, variation, - workspace/toolstrip, launch-monitor/D-plane, split-kinetics, and Qt repairs. - Only append-only handoffs and SPEC conflict textually; both histories remain. -- Focused pre-commit regression is green: 94 Python/PyQt wind, responsive- - layout, navigation, playback, and manifest tests pass, as do all 44 tests in - eight focused React wind/responsive suites. Docs governance and strict - campaign-manifest generation/validation also pass. -- Exact post-commit PR-delta gates are also green: pinned Ruff 0.14.10 checks - and formats 57 changed Python files, pinned MyPy 1.13.0 accepts 38 production - files, and pinned Bandit 1.7.7 finds no medium/high issues in 37 scanned source - files. The 500-LOC budget, changed-Python policy, minimum-test contract, - changed-test assertions, diff hygiene, React type-check/lint, and production - web build all pass. -- No issue or epic is completed by this propagation. Independent review, - normal publication, - protected exact-head CI, unresolved-thread checks, dependency integration, - and release remain open. - -## 2026-08-11 Exact #4281 parent propagation into PR #4282 - -- Draft PR `#4282` retains branch `feat/4199-wind-workflow` and base - `feat/4199-wind-scalar-adapter`. Exact remote child - `29e15d6ff631f7f30afcc745be783f2e716d7dcf` normally merges exact published - parent `a7dce5f89b483303938f518b74b4028a1c68ba81` second without rewriting either - history or the dependency stack. -- Responsive PyQt6/React wind execution, progress/cancellation, controls, - scatter, persistence/export, and the consolidated capability stack remain - authoritative. The parent contributes its split kinetics facade, Ground/Tee - parity, and strict 252-line public/213-line private scalar-adapter design. -- The obsolete formatting-only child edit to monolithic kinetics resolves to - the parent facade. All documentation history remains present. Seven - child-owned Ruff-format failures remain the only known current-head code - formatting correction. The skipped-import MyPy profile additionally replaces - one now-unused cache-return ignore with an explicit typed cast that preserves - the cached object and runtime behavior. Independent review and protected CI - remain required. -- Local evidence is 74 focused Python/PyQt wind, kinetics, and Ground/Tee - tests; 29 focused React tests; and 8 campaign-manifest tests. TypeScript, - focused zero-warning ESLint, Ruff check/format, pinned MyPy 1.13, Bandit's - medium/high threshold, strict wind module/signature/function budgets, - manifest, documentation, policy, SPEC, and diff gates pass. - -## 2026-08-11 current variation propagation into wind scalar PR #4281 - -- PR `#4281` remains on `feat/4199-wind-scalar-adapter`, based on - `feat/4144-variation-export-continuation`. Exact published child - `a7dce5f89b483303938f518b74b4028a1c68ba81` is the first parent and exact - newly published variation head `e6c7460a01082631565fb9ed48aa32538bd7772c` - is the second parent of this normal local merge. -- Production and test paths merge automatically. Matching Python/TypeScript - `scalar-ensemble/v1` provenance, availability, deterministic-scenario, - wind-strategy adapter, and strict module-budget behavior remain authoritative - while inheriting current variation visualization/export, workspace/toolstrip, - launch-monitor/D-plane ancestry, split kinetics, and Qt typing repairs. Only - the three canonical handoffs and SPEC conflict textually; both append-only - histories are retained. -- Focused pre-commit regression is green: 77 Python wind/variation tests and all - 20 tests in the five focused React wind/variation suites pass. Exact - post-commit PR-delta gates are also green: pinned Ruff 0.14.10 checks/formats - five changed Python files, pinned MyPy 1.13.0 accepts three production files, - and pinned Bandit 1.7.7 finds no issues in those three files. Both 500- and - strict 400-LOC budgets, docs governance, changed-Python policy, minimum-test - contract, changed-test assertions, diff hygiene, React type-check/lint, and - the production web build pass. The manifest artifact/checker/test exist on - neither side of this pre-manifest stack and are not applicable. -- No issue or epic is completed by this propagation. Independent review, - normal publication, protected exact-head CI, unresolved-thread checks, - dependency integration, and release remain open. - -## 2026-08-11 PR #4281 wind adapter module-budget repair - -- The public `wind_strategy_plot_adapter.py` is reduced from 403 to 252 lines - by extracting its request/analysis validation into the 213-line private - `_wind_strategy_plot_validation.py` collaborator. Both now satisfy the - mandatory below-400 production-module ceiling. -- A frozen, slotted scenario-expectation object reduces the private scenario - validator from five loose parameters to two cohesive parameters. Every - production function is at or below four parameters and 50 lines. -- Public imports, the `scalar-ensemble/v1` dataset, variable and cohort order, - composite row identity, values, availability, attributes, validation - messages, and the rule that adaptation never invokes flight physics are - unchanged. -- Local focused evidence is 14 Python adapter tests and 16 React wind tests, - plus Ruff/format, pinned MyPy 1.13, Bandit, and the explicit line budget. - Independent review, exact-head protected CI, ordinary publication, and - dependency order remain required. - -## 2026-08-11 reviewed variation parent propagation into wind scalar PR #4281 - -- PR `#4281` remains on `feat/4199-wind-scalar-adapter`, based on - `feat/4144-variation-export-continuation`. Exact remote child - `247046d55afcad3e6cd4f8029f854856c427f59c` normally merges exact reviewed - parent `3337945699966b63cb5cd8e52d7c3b194315e911` in child-first order, - preserving both histories without rebase, reset, retarget, force-push, or - parent rewrite. -- Matching Python/TypeScript `scalar-ensemble/v1` provenance, availability, - deterministic-scenario, and wind-strategy plot-adapter behavior remain - authoritative. The parent contributes selected-scatter export and linked - visualization behavior, the kinetics split, Ground/Tee parity contracts, - workspace/toolstrip repairs, and protected Ruff normalization. -- The sole feature-code conflict referenced obsolete monolithic kinetics and - is resolved to the validated parent `pendulum.sample(...)` facade. Both - append-only handoff/SPEC histories are retained. This local reconciliation - still requires independent review, fresh exact-head protected CI, - unresolved-thread checks, dependency order, and ordinary publication before - any merge or release claim. - -## 2026-08-10 Second #4280 propagation into wind scalar PR #4281 -## 2026-08-10 Repaired wind-scalar parent propagation into PR #4282 - Status verified 2026-08-08. This isolated integration is published as draft [PR #4217](https://github.com/D-sorganization/Tools/pull/4217). No source PR branch was rewritten. -## 2026-08-11 PR #4304 current-parent ancestry candidate - -The clean dedicated `feat/4271-ground-skid-roll` worktree first fast-forwarded -to exact live PR #4304 child `52d9a6a978d8e6b8b19ef92f02f265c9058b00ad`, -then normally merged exact live `feat/4270-ground-impact-bounce` parent -`cf6e72bad98e5f36f782254942e6895b8b71e670`. The PR base remains unchanged; -neither branch was rebased, retargeted, rewritten, force-pushed, or published. -The automatic merge was conflict-free. Its only child-tree change before this -documentation reconciliation is deterministic formatting in the existing -skid/roll regression test; production physics, contracts, schemas, numerical -ordering, and public APIs remain unchanged. - -Local qualification on the merge candidate is `115` focused ground -tests passing on CPython 3.13, pinned Ruff 0.14.10 clean across the ground -package and tests, and pinned MyPy 1.13 clean across all `25` ground production -modules. The manifest validator and all `8` manifest tests, documentation -governance, exact-parent and exact-child diff checks, changed-production policy, -the official changed-file 500-LOC budget, and mandatory production limits of -400 lines per module, 50 lines per function, and four parameters all pass. The -local merge is a PUBLISH candidate for independent review only; protected -exact-head CI, approval, normal child propagation, and publication remain open. - ## 2026-08-10 PR #4304 corrected-impact propagation Draft PR #4304 remains on `feat/4271-ground-skid-roll` with unchanged base @@ -918,140 +505,6 @@ repair. All `115` ground tests, Ruff, formatting, a finding-free local scan of the affected file, documentation governance, the `370`-line source-size check, and diff gates pass before an ordinary guarded fast-forward publication; protected CI and review remain open. -## 2026-08-10 Final repaired #4285 propagation into PR #4288 - -## Inherited current-parent campaign history - -## 2026-08-10 PR #4282 exact-head mypy repair - -- Hosted run `31395741841`, quality job `93478091420`, checked merge ref - `ae75c4b006072b20a713e45b177defcc16a380fe` for exact #4282 head - `aa6eeffb0395f7ed7954f2315b1c625cada552d8`. -- Checkout, installation, Ruff, and format passed. Pinned mypy 1.13 failed only - `scripts/rate_campaign_manifest.py:335:5 [no-any-return]` because the exact - skipped-import profile treats Pydantic's validator result as `Any`. -- The validated local now has an explicit `CampaignManifest` annotation. This - preserves the strict JSON contract and avoids both a suppression and the - redundant cast reported by the non-skipped profile. -- The failed run belongs to the obsolete head. Publish normally, preserve the - PR base/draft state, and propagate the resulting exact head into #4285. - -## 2026-08-10 Exact #4281 propagation into wind workflow PR #4282 - -- PR `#4282` remains on `feat/4199-wind-workflow`, based on - `feat/4199-wind-scalar-adapter`. -- Original child `5f77af4add23547a21cc3fabce98ae9ad4260427` normally merges exact - parent `4a793c4c3f19aad43a3c215800b266be487ace49`; preserve that parent order - and do not rebase, retarget, force-push, rewrite a parent, change draft state, - or merge the PR. -- The responsive PyQt6/React wind workflow, consolidated capability stack, and - campaign release authority remain additive with the parent's strict - scalar-ensemble wind adapter, variation visualization, result-local - selection, workspace/toolstrip, and Python 3.10 compatibility repairs. -- The canonical navigation-state tuple now includes the child-owned capability - tab while retaining the parent's legacy-order visibility migration; no - duplicate navigation constant remains. -- Static review replaces optimized-away UI/capability assertions with explicit - runtime invariant failures and records the fixed-argument executable builder - subprocess boundary using Bandit's native suppression syntax. The separate - exact-CI Pydantic return repair is recorded above. -- SPEC 1.14.14 is the unique combined child entry. Verification passes 73 - focused Python tests, the complete 1,657-test Rate/shared-swing/golf-club - matrix with two explicit optional build123d skips, 643 React tests across 105 - files plus type-check/lint/build, 12 Rust tests, 31 real-CPython-3.10 - compatibility tests, and 43 post-review invariant/GUI/manifest tests. - Ruff/format, pinned MyPy 1.13 across 37 changed production files, Bandit, - exact-parent size, manifest, docs, minimum-test, assertions, CI-policy - secrets, compilation, and diff gates pass. Independent re-review found no - actionable findings after 94 Python workflow/navigation tests, 20 - manifest/GUI tests, 61 React workflow tests, and independent static checks. - Protected current-head CI, unresolved threads, and repository review remain - release gates after publication. -## 2026-08-09 PR #4282 corrected-parent propagation - -Draft #4282 remains on `feat/4199-wind-workflow` with unchanged base -`feat/4199-wind-scalar-adapter`. Exact corrected #4281 parent -`958770049f0124dac0426a6dd62fd4edbf437e7a` is incorporated by the normal -local merge containing this handoff; no branch was rebased, retargeted, -force-pushed, or published. The result preserves the responsive PyQt6/React -wind-strategy workflow, the consolidated capability stack, release-manifest -authority, and launcher/type-gate repairs while inheriting the complete -Python 3.10 compatibility, variation-export, and scalar-ensemble corrections. - -## 2026-08-09 Capability workflow hardening continuation - -Local branch `feat/4201-capability-contract-hardening` starts at exact carrier -`18fe89201d657116bbca99922297c14968356c44`. It makes the Python and TypeScript -`capability-optimization-workflow/v1` readers fail closed on JSON primitive -type mismatches and pins the identical accept/reject matrix in a shared golden -fixture. The Python reader validates the complete nested wire document before -calling model constructors, so numeric strings, booleans-as-numbers, numeric -text identifiers/provenance, and fractional integer fields cannot be silently -normalized. Integral JSON numbers remain portable between runtimes. - -The React Shot Optimizer also replaces browser-managed number inputs with -decimal text drafts. This makes leading-minus and decimal entry reliable while -preserving numeric commit and existing workflow validation. RED evidence was -Python `8 failed, 16 passed` and React `2 failed, 26 passed`; final focused -evidence is Python `43 passed`, React `9 files / 69 tests passed`, with Ruff, -format, mypy, TypeScript, ESLint, structural, and diff checks clean. This -continuation also builds 187 Vite modules without a size warning; it is local -only and has not changed GitHub state. - -## 2026-08-10 Final repaired #4282 propagation into PR #4285 - -- Draft PR `#4288` keeps branch `feat/4269-flight-ground-transfer`, base - `feat/4268-ground-contract`, and original child - `108a841b1378c992defd3c7b7ee263d41a6c8b24` first. -- Exact quality-green strict-contract head - `a93edb4bfd6a8dc9334122cd2ae660983d5bf424` is the second parent. -- Only the four canonical handoff/spec files conflicted; transfer production - and tests did not. No history or topology rewrite was used. -- Fresh exact-head protected CI and review remain mandatory; queued checks are - not release evidence. - -## 2026-08-10 PR #4288 exact repaired-ground propagation - -Draft PR #4288 remains on `feat/4269-flight-ground-transfer` with unchanged -base `feat/4268-ground-contract`. Original child -`247215422a6d4b677552955b4923bc609a553259` normally incorporates exact repaired -#4285 parent `e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` second in the -merge containing this handoff. The child retains its qualified signed terminal state, -physical sphere/terrain contact brackets, strict provenance, and cross-runtime -Python/TypeScript/Rust/PyO3/WASM contracts while inheriting deterministic -workspace timestamps, canonical `swing_sim` import identity, the hosted-mypy -manifest repair, and the complete variation, wind, capability, and campaign -ancestry. No branch was rebased, retargeted, rewritten, or force-pushed. - -This propagation does not add bounce, skid, roll, terrain response, total -distance, or UI execution. Protected CI, independent review, and normal -dependency-ordered collapse remain separate release gates. - -Exact composed-tree verification is 1,080 Python tests passed with six explicit -optional installed-`tools_core` wheel skips, 107 React files / 662 tests, -26 direct Rust transfer/wire tests, TypeScript, zero-warning ESLint, and the -189-module production build. Ruff check/format passes all 28 changed Python -files; pinned mypy 1.13 passes all 21 changed production files. Campaign -manifest validation, documentation governance, and diff checks are clean. The -missing local wheel is not accelerated installed-package evidence and remains -an explicit release boundary; the direct Rust suites executed rather than -being relabeled as wheel parity. - -## 2026-08-10 Exact repaired #4282 propagation into PR #4285 - -Draft PR #4285 remains on `feat/4268-ground-contract` with unchanged base -`feat/4197-capability-observer`. Original child -`788aa547651a3685a363ea401824a5d81477bafb` normally incorporates exact -repaired #4282 carrier `686016196a2f895058b8a566dff103a0fd32cd10` -second. That parent contains merged capability PR #4283 commit -`c1827bbdc50a6e11cc475db2636b4e47a4c15416`, exact observer head -`9bbb98e16e435a0d4c74153b909f2ebfefbbce7a`, and the hosted pinned-mypy -manifest repair. The strict ground-contract child retains its -schemas, canonical fixture, migrations, legacy-result adapter, declared -dependency, and pinned typing repairs while inheriting the deterministic Python -3.10-3.12 UTC parser and the corrected variation, scalar, wind, capability, and -campaign-release ancestry. No branch was rebased, retargeted, rewritten, or -force-pushed. ## 2026-08-09 PR #4304 corrected implementation evidence @@ -1064,29 +517,6 @@ all pass locally. This registry/handoff commit is documentation-only and makes no material runtime, physics, numerical, schema, or API change. Fresh protected CI and review remain required after an ordinary guarded push. -## 2026-08-10 Exact repaired #4282 propagation into PR #4285 (continued) - -The inherited ground descendant passes 1,703 Python tests with two optional `build123d` -skips, 643 React tests across 105 files plus type-check/lint/build, 12 Rust tests, -and 77 real-CPython-3.10 ground and compatibility tests. Ruff/format pass 78 -changed Python files; pinned mypy and Bandit pass 52 changed production files. -Manifest, docs, minimum-test, assertions, 500-LOC, changed-file secrets, Python -3.10 compilation, and diff checks are clean. Hosted CI and review still apply -only to the new exact head. That repaired ground head is now incorporated into -#4288; normal propagation of the reviewed #4288 head into #4298 is the next -ancestry gate. - -The repaired parent owns the explicit Pydantic manifest annotation. The -composed tree additionally normalizes contract-checked scalar plot values, -enforces disabled-command invariants under optimized Python, and documents the -optional alias finder's reviewed catch-and-continue security boundary. - -This is ancestry reconciliation, not new landing physics. Qualified bounce, -skid, roll, terrain profiles, total distance, UI execution, Rust/WASM parity, -protected CI, review, and release remain open. The exact repaired #4285 head is -now incorporated into #4288; the transfer behavior is evaluated on that -corrected descendant before normal propagation into #4298. - ## 2026-08-09 PR #4304 isolated-MyPy correction Hosted quality-gate run `31354071845` (job `93350276996`) failed exact @@ -1236,32 +666,6 @@ terrain deformation, UI, TypeScript physics, Rust/PyO3/WASM, and UpstreamDrift adapters remain excluded. Protected CI, required review, ordinary parent integration, and downstream delivery are still required. -## 2026-08-09 PR #4285 corrected-carrier reconciliation - -Draft #4285 remains on `feat/4268-ground-contract` with unchanged base -`feat/4197-capability-observer`. Exact corrected wind carrier -`bb101cedd555d07d493aae998b46050c68660cdd` is incorporated through the -normal local merge containing this handoff; no branch was rebased, retargeted, -force-pushed, or published. The ground parent retains its strict schemas, -canonical fixture, migrations, legacy-result adapter, explicit dependency, and -pinned-mypy repairs while acquiring the corrected wind/scalar/variation, -Python 3.10 compatibility, capability, and campaign-release ancestry. - -This is an ancestry reconciliation, not new landing physics. Qualified bounce, -skid, roll, terrain profiles, total distance, UI, Rust/WASM parity, protected -CI, review, and release remain open. PR #4288 must normally merge the resulting -exact #4285 head and rerun its transfer and combined compatibility gates. That -next propagation is where the descendant acquires the observer-to-wind -reconciliation; neither PR base should change. -Draft #4282 remains on `feat/4199-wind-workflow` with unchanged base -`feat/4199-wind-scalar-adapter`. Exact corrected #4281 parent -`958770049f0124dac0426a6dd62fd4edbf437e7a` is incorporated by the normal -local merge containing this handoff; no branch was rebased, retargeted, -force-pushed, or published. The result preserves the responsive PyQt6/React -wind-strategy workflow, the consolidated capability stack, release-manifest -authority, and launcher/type-gate repairs while inheriting the complete -Python 3.10 compatibility, variation-export, and scalar-ensemble corrections. - ## 2026-08-09 PR #4288 corrected-ground-parent propagation Draft #4288 remains on `feat/4269-flight-ground-transfer` with unchanged base @@ -1329,443 +733,6 @@ against a `1e-12` absolute tolerance. This branch does not change the wind workflow. The hosted Rust `-lpython3.11` linker failure remains runner/toolchain infrastructure. -## Additional inherited parent campaign history - -This is an ancestry reconciliation, not new landing physics. Qualified bounce, -skid, roll, terrain profiles, total distance, UI, Rust/WASM parity, protected -CI, review, and release remain open. PR #4288 must normally merge the resulting -exact #4285 head and rerun its transfer and combined compatibility gates. That -next propagation is where the descendant acquires the observer-to-wind -reconciliation; neither PR base should change. -Draft #4282 remains on `feat/4199-wind-workflow` with unchanged base -`feat/4199-wind-scalar-adapter`. Exact corrected #4281 parent -`958770049f0124dac0426a6dd62fd4edbf437e7a` is incorporated by the normal -local merge containing this handoff; no branch was rebased, retargeted, -force-pushed, or published. The result preserves the responsive PyQt6/React -wind-strategy workflow, the consolidated capability stack, release-manifest -authority, and launcher/type-gate repairs while inheriting the complete -Python 3.10 compatibility, variation-export, and scalar-ensemble corrections. -## 2026-08-11 current workspace propagation into variation PR #4280 - -- PR `#4280` remains on `feat/4144-variation-export-continuation`, based on - `feat/4218-toolstrip-workspace`. Exact published child - `3337945699966b63cb5cd8e52d7c3b194315e911` is the first parent and exact - newly published workspace head `efbca84095b617b4018732f7802c2da3f0525387` - is the second parent of this normal local merge. -- Production and test paths merge automatically. Variation selected-scatter - CSV parity, typed unavailable outcomes, bounded accessible tables, linked - selection, and all-trial arc analysis remain authoritative while inheriting - the parent's current workspace/toolstrip, launch-monitor/D-plane ancestry, - split kinetics, and Qt typing repairs. Only the three canonical handoffs and - SPEC conflict textually; both append-only histories are retained. -- Focused pre-commit regression is green: 56 Python variation tests and all 10 - tests in the three focused React variation suites pass. Exact post-commit - PR-delta gates are also green: pinned Ruff 0.14.10 checks/formats five changed - Python files, pinned MyPy 1.13.0 accepts four production files, and pinned - Bandit 1.7.7 finds no issues in those four files. Docs governance, 500-LOC - budget, changed-Python policy, minimum-test contract, changed-test assertions, - diff hygiene, React type-check/lint, and the production web build pass. The - manifest artifact/checker/test exist on neither side of this pre-manifest - stack, so that later release gate is structurally not applicable. -- No issue or epic is completed by this propagation. Independent review, - normal publication, protected exact-head CI, unresolved-thread checks, - dependency integration, and release remain open. - -## 2026-08-11 reviewed workspace parent propagation into variation PR #4280 - -- PR `#4280` remains on `feat/4144-variation-export-continuation`, based on - `feat/4218-toolstrip-workspace`. Exact remote child - `668ba96746f79f7a12e8092161bd610054197f58` normally merges exact reviewed - parent `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` in child-first order, - preserving every commit and both histories without rebase, reset, retarget, - force-push, or parent rewrite. -- Variation selected-scatter CSV parity, typed unavailable outcomes, bounded - accessible tables, linked selection, and all-trial arc analysis remain - authoritative. The parent contributes its validated kinetics split, - Ground/Tee parity contracts, protected Ruff normalization, complete - workspace/toolstrip behavior, and remote-history reconciliation. -- The sole feature-code conflict was obsolete monolithic kinetics source and - is resolved to the current `pendulum.sample(...)` façade. Both append-only - handoff histories are retained. Seven duplicate child automation edits fail - protected Ruff 0.14.10 formatting and are normalized to exact reviewed - parent blobs without removing their commit from history. This local merge - still requires independent review, fresh exact-head protected CI, - unresolved-thread checks, dependency order, and ordinary publication before - any release or merge claim. - -## 2026-08-10 Second #4279 propagation into variation PR #4280 - -- PR `#4280` stays on `feat/4144-variation-export-continuation`, based on - `feat/4218-toolstrip-workspace`. -- Exact repaired parent `61b7f48b5aeb7d57246b4963da3df086e79cbe15` - is incorporated through a normal merge commit. No feature code conflicts and - no branch/PR topology or parent history is rewritten. -- Preserve the variation/export implementation and both append-only handoff - histories. Fresh protected CI, review, and dependency order remain open. -- Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs - governance, changed-file-size, and whitespace gates. - -## 2026-08-10 Exact #4279 propagation into variation PR #4280 - -- PR `#4280` remains the immediate child on - `feat/4144-variation-export-continuation`, based on - `feat/4218-toolstrip-workspace`. -- Original child `f90836e342efc8be624739802375af2876d11e5f` normally merges - exact parent `6717e9e09d507dbc24bedb36177f1cdf0b4fd90b`; preserve that - parent order and do not rebase, retarget, force-push, rewrite a parent, or - change draft state. -- The variation selected-scatter export, typed unavailable rows, accessible - raw tables, linked trial selection, and focused PyQt/React visualization - modules merge cleanly with the parent's full workspace/toolstrip, playback, - plots, navigation, compatibility, and module-budget repairs. -- Staged review found a release-blocking stale linked selection after rerunning - a smaller study. PyQt now clears selection before each result replacement - and validates public selection indices against the current trial count; - React clears on result identity change and bounds the value shared with all - linked views. Larger-to-smaller rerun regressions cover both clients. -- SPEC 1.14.12 is the unique combined child release entry. Verification is - green across 37 focused variation tests, 1,528 complete - Rate/shared-swing/golf-club tests with two explicit optional build123d skips, - 546 React tests across 90 files plus type-check/lint/build, exact-parent - Ruff/Ruff-format/Black/pinned MyPy/Bandit, file-size, docs, minimum-test, - assertion, detect-secrets, diff, real CPython 3.10.20 compilation, and 30 - compatibility regressions. There is no Rust delta from the exact parent. - Independent staged re-review found no actionable findings after checking - both the first replacement-render React boundary and validated PyQt values. - Current-head protected CI, review threads, and repository review remain - release gates after publication. -## 2026-08-11 current #4203 propagation into workspace PR #4279 - -- PR `#4279` remains on `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. Exact published child - `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` is the first parent and exact - newly published #4203 head `7abce9ad767fe8311da66a1e5998b892ea3ca9de` - is the second parent of this normal local merge. -- Production and test paths merge automatically. Workspace/toolstrip, - module-visibility, navigation, granular playback, and independent plots are - preserved while the descendant inherits the parent's current launch-monitor, - D-plane, split-kinetics, and Qt typing repairs. Only the three canonical - handoffs and SPEC conflict textually; both append-only histories are retained. -- Focused pre-commit regression is green: 142 exact PR-delta Python tests pass, - and all 32 tests in the eight changed React suites pass. Exact post-commit - PR-delta gates are also green: pinned Ruff 0.14.10 checks/formats 27 changed - Python files, pinned MyPy 1.13.0 accepts 18 production files, and pinned - Bandit 1.7.7 finds no medium/high issues in those 18 files. Docs governance, - 500-LOC budget, changed-Python policy, minimum-test contract, changed-test - assertions, diff hygiene, React type-check/lint, and the production web build - pass. The manifest artifact/checker/test exist on neither side of this - pre-manifest stack, so that later release gate is structurally not applicable. -- No issue or epic is completed by this propagation. Independent review, - normal publication, protected exact-head CI, unresolved-thread checks, - dependency integration, and release remain open. - -## 2026-08-11 remote automation reconciliation for workspace PR #4279 - -- PR `#4279` remains on `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. Exact local head - `0b22c401a26c31441a599d8d9b39de123706e7ea` ordinarily merges exact remote - head `61fe2d556a5413e525d958612ccfd57e65b8d5a2`; both histories and every - commit remain reachable without reset, rebase, force-push, retarget, or - parent rewrite. -- The remote automation commit spans 23 paths but is formatting-only. Fifteen - paths were already byte-identical through the current parent, including its - six existing `.codex-worktrees` gitlinks. Its seven unique formatting edits - do not match protected Ruff 0.14.10 output and are normalized back to the - pinned form. The sole content conflict was between obsolete pre-split - kinetics source and the current façade; resolution retains the current - `pendulum.sample(...)` implementation and parent module split. -- No workspace/toolstrip feature code is lost. Module visibility, navigation, - granular playback, independent plots, physics, frames, units, schemas, and - public contracts remain unchanged. Fresh exact-head protected CI, - independent review, unresolved-thread checks, dependency order, and normal - publication are still required; this local merge is not a release claim. - -## 2026-08-11 hosted MyPy repair propagation into workspace PR #4279 - -- PR `#4279` remains on `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. Exact child - `7806a16f58e1c6999d32f0127a187fbb21f839a1` normally merges exact published - parent `3796b49e40b677fbac4e05739f8be49f905df2cb` without rebase, retarget, - force-push, or history rewrite. -- There are no feature-code conflicts. The only inherited production changes - are four static NumPy-array casts that close hosted MyPy return boundaries; - workspace/toolstrip behavior and numerical, frame, unit, schema, rendering, - and public-API semantics remain unchanged. -- Preserve both append-only histories below. This local merge requires fresh - merged-tree protected CI, required review, unresolved-thread checks, and - dependency order before publication or merge. - -## 2026-08-11 latest #4203 propagation into workspace PR #4279 - -- PR `#4279` remains on `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`; exact parent - `0216a547aa79727091a2939b96e779e8ddbd7304` is incorporated by a normal - two-parent merge without rebase, retarget, force-push, or history rewrite. -- There are no feature-code conflicts. The child retains its workspace, - toolstrip, module-visibility, navigation, granular playback, and independent - plot behavior while inheriting the parent's pinned formatting and - identity-preserving 222/205/131-line kinetics split. -- Preserve both append-only histories below. Fresh merged-tree protected CI, - required review, unresolved-thread checks, and dependency order remain - release gates; this local merge is not a completion or publication claim. - -## 2026-08-10 Second #4203 propagation into workspace PR #4279 - -- PR `#4279` remains the immediate child on - `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. -- Exact repaired parent head - `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` is incorporated through a - normal merge commit; no feature code conflicts and no branch or PR topology - is rewritten. -- Preserve both append-only handoff histories. Fresh child protected CI, - review, and earlier dependency gates remain required. -- Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs - governance, changed-file-size, and whitespace gates. - -## 2026-08-10 Exact #4203 propagation into workspace PR #4279 - -- PR `#4279` remains the immediate child on branch - `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. -- Original child `05383d333b6fd87eaf5e37305476f50b505c2c2e` normally merges - exact parent `31cbc007d4c85b5479b7cd0fb0969124eab2af67`; preserve that - two-parent order and do not rebase, retarget, force-push, or change draft - state. -- The child workspace/toolstrip, module-visibility, granular playback, path - trail, and independent plot behavior remain authoritative. The parent - `ImpactLayerControls`, navigation-state constants, plotting catalog, and - triple-pendulum extractions are integrated without duplicate state. -- Verification is green across 1,339 Python tests with six explicit skips, 545 - React tests plus type-check/lint/build, the 40-test post-format PyQt rerun, - exact-parent Ruff/Ruff-format/Black/pinned MyPy/Bandit, the 500-line budget, - docs/minimum-test/assertion/detect-secrets/diff gates, real CPython 3.10.20 - compile/import checks, and 30 compatibility regressions. There is no Rust - delta from the exact parent. Independent staged review found no actionable - findings after 76 additional focused PyQt/navigation/workspace tests. - Current-head protected CI, unresolved-thread checks, and required repository - review remain release gates after guarded publication. - -## 2026-08-11 #4203 append-only SPEC preservation repair - -- Independent review of local candidate `e20b4f630...` found four exact - current-parent history rows missing from SPEC: 2026-08-10 versions 1.13.11, - 1.13.9, 1.13.7, and 1.13.6. The current documentation-only follow-up restores - those rows verbatim and advances the declared/changelog version together. -- Runtime files, tests, ordered merge parents, PR base, and validation evidence - are byte-unchanged. Re-review, normal publication, exact-head protected CI, - and downstream propagation remain required. - -## 2026-08-11 #4203 current-parent reconciliation - -- The current D-plane base is exact head - `f3363aa88868f6a5c7e9ccfc682a9eca014e86c1`; #4203's exact published child - is `217e36dc93d30f79826847f958fbcd10805e58ed`. They are being composed in - that order by a normal merge while retaining base `feat/4189-dplane`. -- The parent's nine changed files merge without semantic conflict except for - formatting around the inherited kinetics origin offset. The split child - facade remains authoritative because the obsolete parent expression reaches - through `source.inner`; the equivalent explanatory comment is preserved. -- The exact CI-pinned MyPy 1.13 delta found four additional Qt-stub `Any` - boundaries after the merge. Explicit `bool`/`str` narrowing now closes the - responsive-event, legend, ball-setup event-filter, and status-text contracts - without changing their runtime values or interaction behavior. -- No issue or epic is complete from this reconciliation. Independent review, - ordinary publication, protected CI, downstream propagation, and release - gates remain open. - -## 2026-08-11 #4203 exact-head format completion - -- Exact published head `7d69a545ae555679f0318940e67c1786626d6794` - failed only the Ruff format step. The exact pinned 0.14.10 reproduction found - eleven noncompliant changed files: four inherited files plus seven altered by - the automated pre-commit repair. -- The pending correction is mechanical Ruff formatting of those eleven files. - It changes no runtime behavior or public contract and still requires AST - equivalence, focused tests, independent review, ordinary fast-forward - publication, and fresh protected exact-head CI. - -## 2026-08-11 #4203 hosted MyPy NumPy boundary repair - -- Exact PR head `0216a547aa79727091a2939b96e779e8ddbd7304` reached runtime merge - ref `aede309` but failed CI Standard run `31477542889`, job `93734652129`, - with four `no-any-return` findings introduced when kinetics was split for the - size budget. -- Explicit `numpy.ndarray` casts now close only the static return boundaries - around force norms, the RK4 derivative concatenation, and the app-frame - projection. There is no numerical operation, copy, schema, frame, unit, - rendering, or public API change. -- The acceptance profile is the entire 102-file PR-base changed-source MyPy - set, followed by focused kinetics/presentation/PyQt tests, the full Rate - suite, and the repository's Ruff/format, size, Bandit, documentation, and - diff gates. A three-file MyPy pass alone is insufficient release evidence. -- That local profile is now green: MyPy 102 files; Ruff/format 141 files; - Bandit 101 production files with no medium/high finding; 28 focused and 701 - full Rate tests; plus module/file size, documentation, minimum-test, and diff - gates. -- The fix remains local pending independent review and ordinary protected CI. - Do not resume #4279 propagation from an unreviewed or unpublished commit. - -## 2026-08-11 #4203 kinetics size-budget repair - -- The exact `572bf525d` PR tree passes its base-relative candidate scan, but - `python scripts/check_file_size_budget.py --max-loc 500 --changed-only - --base-ref HEAD~1 --baseline-file scripts/monolith_baseline.txt` reproduces - the proactive release failure: Ruff-formatted `simulation/kinetics.py` is - selected at 646 LOC and is not grandfathered. -- A behavior-preserving extraction leaves a 222-LOC stable public façade and - delegates immutable result validation (131 LOC) and pure pendulum dynamics - (205 LOC) to focused private modules. Public export identity and the existing - `_reaction_forces` compatibility seam are test-pinned. -- Existing numerical parity, inverse/forward dynamics, energy, reaction-force, - presentation, and PyQt behavior remain the acceptance basis. This local-only - implementation does not change PR base, stack order, protected review/CI - requirements, or any downstream issue completion state. -- Local regression evidence is 28 focused kinetics/presentation/PyQt tests - and all 701 Rate-of-Closure Python tests passing. - -## 2026-08-11 #4203 pinned-Ruff formatting repair - -- No material handoff change: the eight Python files reported by CI Standard - run `31468208320`, job `93705508050`, receive only the repository-pinned - Ruff 0.14.10 formatting output. -- No physics, behavior, frame, schema, UI, release-stack, or dependency - contract changes. Current-head protected CI and review remain release - requirements; queued checks remain unresolved rather than passing. - -## 2026-08-10 #4143 child receives repaired launch-registry parent - -- Ready PR `#4325` stays on `feat/4143-tee-parity-fixture`, based on - `feat/4181-launch-monitor-registry`. -- Exact parent `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` is incorporated by a - normal merge commit. There is no production/test-code conflict and no - rebase, retarget, force-push, or parent rewrite. -- Preserve the shared parity fixture and deterministic web/PyQt evidence. - Fresh exact-head CI, review, dependency order, and release to `main` remain - required before #4143 can close. - -## 2026-08-10 #4143 Python/React golden ball-setup parity - -- The bounded `feat/4143-tee-parity-fixture` branch starts at exact PR #4203 - head `31cbc007d4c85b5479b7cd0fb0969124eab2af67`, preserving its draft state, - base, and stack order. -- A single `ball_setup_golden_v1.json` fixture declares schema/version, metre - units, the ground-plane-to-ball-bottom reference, ball radius, Driver/Tee and - iron/Ground defaults, explicit club-default overrides, Ground zero effective - height, center/serialization geometry, invalid finite-domain cases, and a - legacy simulation-run migration. -- Python and React independently consume every case through their public - configuration/persistence boundaries. Verification is 18 passing Python - tests, 24 passing React tests, and green TypeScript, ESLint, Vite production - build, Ruff check, and Ruff format. -- Recorded visual evidence is stored under - `C:\Users\diete\AppData\Local\Temp\rate-4143-visual-evidence-8050eeba`. - Playwright captured the 1600 x 1200 default Driver/Tee and rerun - explicit-Ground React states after semantic control/diagram and zero-error - checks. A hidden 1400 x 900 PyQt harness captured the same states after - canonical center, editor, and tee-artist assertions. The browser manifest - SHA-256 is `43df78e04b47e1b3209ff7a574718f90847ccda6dde5afd863d43191a950ccf7`; - the PyQt manifest SHA-256 is - `07822495dbcfa7568615ccb2728481210c28963614434c80f6997210c325a6f9`. - PNGs remain external evidence rather than oversized repository binaries. -- #4143 remains open for protected CI/review and release to `main`. The strict - campaign release manifest does not exist in this exact #4203 history; it was - added later on a divergent branch and is not backported by this bounded - slice. - -## 2026-08-10 Second propagation into launch-monitor registry - -- Draft child PR `#4203` retains base `feat/4189-dplane` and receives exact - repaired parent head `7d8d2f06dc797021d01939691e58f8425b652b33` - through a normal merge commit. No branch history, PR base, or draft state is - rewritten. -- The inherited repair closes the parent head's two pinned MyPy - `no-any-return` findings with explicit ndarray boundaries and makes no - numerical, frame, schema, or UI change. -- Parent quality-gate success is not child release evidence. Current-head child - CI, review, all earlier ancestors, and #4189 acceptance remain required. -- Reconciled child-tree evidence is 25 focused D-plane/impact tests, docs - governance, changed-file size, and whitespace checks. The local Windows - MyPy 1.15/installed-NumPy stub combination is incompatible with the branch's - Python 3.11 target, while WSL currently fails to start with `E_FAIL`; the - successful pinned typing evidence remains the exact parent hosted gate. - -## 2026-08-10 Propagation into launch-monitor registry - -- Immediate child PR `#4203` keeps base `feat/4189-dplane`. -- Its original head `08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` - normally merges exact parent `#4202` head - `b443fdbed7064c5db0320106013c8413e3e24356`; no branch rewrite, retarget, - or force push is permitted. -- The semantic reconciliation keeps #4203's responsive - `SimulationViewControlsMixin`, while the parent's `ImpactLayerControls` - helper becomes the single owner of persisted D-plane checkbox state. The - automation compatibility mapping aliases that helper state exactly. -- The launch-monitor registry, Python 3.10 compatibility layer, frame-explicit - D-plane contracts, responsive layout, and exports remain additive. Both - affected PyQt modules satisfy the protected 500-line limit. -- The untouched original child had three additional ungrandfathered size - blockers: swing sources at 540 LOC, the plotting catalog at 533 LOC, and the - main window at 528 LOC. Narrow extractions move triple-pendulum dynamics, - plotting metadata, and versioned primary-tab state into focused modules, - while identity-pinned re-exports preserve every established import seam. The - resulting module pairs are 282/282, 459/98, and 494/85 lines. -- Focused evidence is 36 passing PyQt simulation/layout tests, 38 - plotting/navigation tests, and 21 simulation source/export tests. Combined - evidence is 1,249 passing Python tests with six explicit optional skips, 521 - React tests and all web gates, 12 `swing-core` tests, real CPython 3.10 - checks, scoped static analysis, docs/minimum-test/assertion governance, - changed-file size, detect-secrets, and diff checks. The protected size gate - passes all 107 changed candidates; a separate full-tree audit retains two - untouched non-candidate monoliths (`kinetics.py` and - `torque_profile_panel.py`). Independent staged review found no actionable - findings after 95 additional focused tests. Current-head protected CI and - required repository review remain pending release evidence. - -Status verified 2026-08-07. This isolated integration is published as draft -[PR #4217](https://github.com/D-sorganization/Tools/pull/4217). No source PR -branch was rewritten. -## 2026-08-10 PR #4281 workspace timestamp propagation - -Exact parent `f90836e342efc8be624739802375af2876d11e5f` is incorporated into -`feat/4199-wind-scalar-adapter` through the normal merge containing this -handoff. PR #4281 keeps base `feat/4144-variation-export-continuation`; no -branch was rebased, retargeted, rewritten, or force-pushed. The child retains -its scalar ensemble and wind adapter while inheriting the deterministic UTC -parser and complete variation parent. - -The monotonic SPEC now assigns 1.14.10 to compatibility, 1.14.11 to variation, -and 1.14.12 to the wind child. The reconciled tree passes `794` Rate tests, -`27` direct compatibility tests on real CPython 3.10.20, and `2 files / 10` -focused React tests, plus TypeScript, focused zero-warning ESLint, Ruff, -format, pinned mypy 1.13, documentation, size, and diff gates. Protected CI, -review, and later propagation remain open. - -## 2026-08-09 PR #4281 scalar-ensemble parent propagation - -Draft #4281 remains based on `feat/4144-variation-export-continuation` and now -includes exact corrected #4280 parent -`38ed58cab96842a3007e76a855db83ee2452b8fd` through the normal merge containing -this handoff. No branch was rebased, retargeted, force-pushed, or published. -The child retains its matching Python/TypeScript `scalar-ensemble/v1` contract -and wind-strategy adapter while inheriting the full variation-export and -Python 3.10 compatibility history. SPEC 1.14.12 records this child source delta -independently and monotonically above parent 1.14.11. - -SPEC 1.14.13 records the current #4282 propagation monotonically above the -corrected parent's 1.14.12, 1.14.11, and 1.14.10 entries. Protected CI, review, -publication, installed-package evidence, downstream UpstreamDrift parity, and -the remaining scientific/accessibility/performance release gates remain -separate. This local merge is not a protected release. - -Focused evidence is 89 ground-contract, compatibility, scalar-adapter, and -responsive-wind tests on Python 3.11 plus the same 89 on real CPython 3.10.20. -Ruff check/format passes 34 focused Python files, pinned mypy 1.13 passes 23 -production modules, and ground modules/functions remain within 400/50-line -budgets without placeholders. The inherited campaign manifest validates and -all nine manifest/parity contracts pass. Documentation governance, ancestry, -SPEC-order, and final diff assertions are required in the same local merge. - ## 2026-08-09 Ground-contract stack recovery Protected quality-gate run `31341468033` on PR #4285 exact head @@ -2366,10 +1333,8 @@ an explicit mocked-integrator regression test for that boundary. Current exact local evidence is 906 Python/PyQt/shared-swing tests passed with one expected optional-Rust skip and 15 existing warnings, plus 91 React test files / 555 tests passed. Ruff, formatting, Black, focused mypy, TypeScript, -zero-warning ESLint, the 166-module production build, and `git diff --check` -passed. The function budget passed, but the 403-line wind adapter did not meet -the mandatory below-400 module ceiling at that historical head; the -2026-08-11 repair above corrects that blocker. The adapter is plot-ready model +zero-warning ESLint, the 166-module production build, `git diff --check`, and +the production module/function budgets pass. The adapter is plot-ready model infrastructure, not an end-user workflow; #4199 remains open for worker, progress/cancellation, client controls, strategy/scatter displays, persistence, and exports. @@ -2764,6 +1729,7 @@ existing local SciPy/NumPy compatibility warning also remains environmental. All new source files are below 400 lines. The oversized append-only SPEC and handoff registries plus the preserved Waterloo and `from_imperial` public signatures predate #4269 and are explicitly retained for compatibility. + ## 2026-08-09 PR #4302 deterministic-digest scanner repair The protected run at exact PR #4302 head @@ -2776,477 +1742,3 @@ The digest, fixture, physics, scanner scope, and baseline remain unchanged. Commit and push this bounded repair normally before propagating it into #4304, #4305, or later ground children. The contemporaneous file-size cancellation occurred in checkout and remains infrastructure evidence, not a code failure. -## 2026-08-11 parent sections preserved during #4282 reconciliation - -## 2026-08-10 Exact #4280 propagation into wind scalar PR #4281 - -- PR `#4281` remains on `feat/4199-wind-scalar-adapter`, based on - `feat/4144-variation-export-continuation`. -- Original child `cf52529b1e68479321bb93b1be3d59c77f782008` normally merges - exact parent `8bcc49fc4e16e5e43be0b7f0f03c3017d5b79d0c`; preserve that - parent order and do not rebase, retarget, force-push, rewrite a parent, or - change draft state. -- The Python/TypeScript `scalar-ensemble/v1` contract and wind-strategy plot - adapter retain stable row identity, provenance, typed unavailable values, - and per-cohort availability while inheriting the complete result-local - selection, visualization, workspace, compatibility, and module-budget tree. - Both implementations enforce the same deterministic scenario boundary: - exact per-trial provenance, zero shear/turbulence, seed zero, and no gusts. -- SPEC 1.14.13 is the unique combined child entry. Verification passes 27 - focused Python contract/adapter/selection tests, 1,549 complete - Rate/shared-swing/golf-club tests with two explicit optional build123d skips, - and all 556 React tests across 92 files plus type-check/lint/build. Exact- - parent Ruff/format/pinned MyPy/Bandit, the two-file 500-line budget, docs, - minimum-test, assertions, detect-secrets, diff, and CPython 3.10 compilation - pass. Independent re-review found no actionable findings after checking the - exact provenance derivation and all five deterministic-scenario regressions. - Protected current-head CI, unresolved threads, and repository review remain - release gates after publication. - -## 2026-08-11 latest #4203 propagation into workspace PR #4279 - -- PR `#4279` remains on `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`; exact parent - `0216a547aa79727091a2939b96e779e8ddbd7304` is incorporated by a normal - two-parent merge without rebase, retarget, force-push, or history rewrite. -- There are no feature-code conflicts. The child retains its workspace, - toolstrip, module-visibility, navigation, granular playback, and independent - plot behavior while inheriting the parent's pinned formatting and - identity-preserving 222/205/131-line kinetics split. -- Preserve both append-only histories below. Fresh merged-tree protected CI, - required review, unresolved-thread checks, and dependency order remain - release gates; this local merge is not a completion or publication claim. - -## 2026-08-10 Second #4203 propagation into workspace PR #4279 - -- PR `#4279` remains the immediate child on - `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. -- Exact repaired parent head - `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` is incorporated through a - normal merge commit; no feature code conflicts and no branch or PR topology - is rewritten. -- Preserve both append-only handoff histories. Fresh child protected CI, - review, and earlier dependency gates remain required. -- Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs - governance, changed-file-size, and whitespace gates. - -## 2026-08-10 Exact #4203 propagation into workspace PR #4279 - -- PR `#4279` remains the immediate child on branch - `feat/4218-toolstrip-workspace`, based on - `feat/4181-launch-monitor-registry`. -- Original child `05383d333b6fd87eaf5e37305476f50b505c2c2e` normally merges - exact parent `31cbc007d4c85b5479b7cd0fb0969124eab2af67`; preserve that - two-parent order and do not rebase, retarget, force-push, or change draft - state. -- The child workspace/toolstrip, module-visibility, granular playback, path - trail, and independent plot behavior remain authoritative. The parent - `ImpactLayerControls`, navigation-state constants, plotting catalog, and - triple-pendulum extractions are integrated without duplicate state. -- Verification is green across 1,339 Python tests with six explicit skips, 545 - React tests plus type-check/lint/build, the 40-test post-format PyQt rerun, - exact-parent Ruff/Ruff-format/Black/pinned MyPy/Bandit, the 500-line budget, - docs/minimum-test/assertion/detect-secrets/diff gates, real CPython 3.10.20 - compile/import checks, and 30 compatibility regressions. There is no Rust - delta from the exact parent. Independent staged review found no actionable - findings after 76 additional focused PyQt/navigation/workspace tests. - Current-head protected CI, unresolved-thread checks, and required repository - review remain release gates after guarded publication. - -## 2026-08-11 #4203 append-only SPEC preservation repair - -- Independent review of local candidate `e20b4f630...` found four exact - current-parent history rows missing from SPEC: 2026-08-10 versions 1.13.11, - 1.13.9, 1.13.7, and 1.13.6. The current documentation-only follow-up restores - those rows verbatim and advances the declared/changelog version together. -- Runtime files, tests, ordered merge parents, PR base, and validation evidence - are byte-unchanged. Re-review, normal publication, exact-head protected CI, - and downstream propagation remain required. - -## 2026-08-11 #4203 current-parent reconciliation - -- The current D-plane base is exact head - `f3363aa88868f6a5c7e9ccfc682a9eca014e86c1`; #4203's exact published child - is `217e36dc93d30f79826847f958fbcd10805e58ed`. They are being composed in - that order by a normal merge while retaining base `feat/4189-dplane`. -- The parent's nine changed files merge without semantic conflict except for - formatting around the inherited kinetics origin offset. The split child - facade remains authoritative because the obsolete parent expression reaches - through `source.inner`; the equivalent explanatory comment is preserved. -- The exact CI-pinned MyPy 1.13 delta found four additional Qt-stub `Any` - boundaries after the merge. …11026 tokens truncated… PR #4217 -was squash-merged there. It adds one -UI-neutral registry for 17 File/View/Tools commands, a strict versioned -workspace document with atomic file persistence, matched PyQt/React top -toolstrips, persistent module visibility/order, theme and shortcut surfaces, -and direct Impact/Swing/Flight navigation. File actions that do not yet have a -complete client adapter remain visibly disabled with a reason rather than -pretending to save incomplete state. - -The same continuation corrects the interaction defects reported against the -live Swing and Plots views. Playback now has deterministic replay-from-end, -Restart, granular 0.05x through 4.00x speed, pause, and loop behavior. The -full swing path is opt-in so a persistent trail does not obscure the current -frame. Each managed plot now owns a distinct figure/canvas, zoom state, -Auto Fit action, wheel zoom, and independently movable or hideable legend; -the plot workspace presents all managed plots instead of reusing one selected -canvas. PyQt small-window testing caught the new playback editor compressing -below the 64 px readability floor; the explicit editor minimum fixes that case -and the three-case layout suite passes. - -Two read-only cross-repository audits are now tracked as separate programs: - -- [#4260](https://github.com/D-sorganization/Tools/issues/4260), with - #4261-#4266, establishes one impact/flight authority and a machine-readable - parity contract across Tools PyQt, Tools React, UpstreamDrift PyQt, and - UpstreamDrift React. -- [#4267](https://github.com/D-sorganization/Tools/issues/4267), with - #4268-#4276, defines qualified landing, bounce, skid, roll, and total-distance - modeling with editable ground profiles and exact UpstreamDrift adapters. - -The parity audit found that UpstreamDrift PyQt reuses Tools, while the -UpstreamDrift React launcher has no native Rate React route. UpstreamDrift's -Tools gitlink `ff4240217005e1415ca409fd124e50b64ee642d2` also predates the -current integration head by 184 commits, and its sibling/vendor resolution is -ambiguous. The ground audit found a useful existing fail-closed -`GroundModelResult` boundary plus reusable putting/terrain primitives, but no -qualified end-to-end ground solver. Before bounce can be correct, airborne -flight must terminate against physical terrain plus ball radius and preserve -the full terminal angular-velocity vector; the current relative launch-plane -event and spin-free trajectory state do neither. Those prerequisites are -explicit in #4269 and must not be hidden by UI-derived estimates. - -The final local verification pass is green. The complete Rate-of-Closure and -shared swing-model run passed 890 tests with one expected skip because the -optional `swing_core` Rust wheel is not installed; the remaining 15 warnings -are the existing Hypothesis collection warning. React passed 89 files / 545 -tests, zero-warning ESLint, TypeScript checking, and the production Vite build. -Ruff, Black, targeted mypy, `git diff --check`, and the repository structural -limits also pass: every changed production Python file is at most 400 lines and -every changed production Python function is at most 50 lines. Rendered PyQt -inspection confirmed independent plot canvases, responsive single-column -reflow at the tested desktop width, independent 125%/100% zoom state, working -Auto Fit, and the opt-in trail/playback controls. These are local validation -results only; they do not establish protected CI, review, merge, or release -status. - -### 2026-08-07 variation export and completion audit continuation - -The post-toolstrip branch `feat/4144-variation-export-continuation` is published -as [draft PR #4280](https://github.com/D-sorganization/Tools/pull/4280), based -on exact parent head `c36ca36e91f34fa849d2508708bf9dd6c0cdc392`. It keeps #4279 unchanged -while closing one remaining #4144 parity gap: selected scalar scatter data can -now be exported as CSV from both clients, retaining every raw trial, typed -outcome, and unavailable cell rather than only the finite points drawn on the -canvas. PyQt also has a bounded read-only raw-trial table matching the web -workflow, and the table population is shared with the matrix view. - -The complete post-change local gates passed: - -- Python/PyQt/shared swing suite: `890 passed, 1 skipped, 15 warnings`; the - skip is the optional `swing_core` wheel and the warnings are the existing - Hypothesis collection and empty polynomial-preview legend warnings. -- React: `89` files / `545` tests passed. -- Ruff check/format, Black, targeted mypy, TypeScript, zero-warning ESLint, - the `166`-module Vite production build, and `git diff --check` passed. -- Every changed production file is below 400 lines and every changed - production function is at most 50 lines. - -A live GitHub/source reconciliation covered every requested epic in this -campaign. No epic yet satisfies its own definition of done: most implementation -is still on feature branches, #4119 is the only Rate platform PR targeting -`main` and is currently dirty, #4203 and #4279 remain draft/unstable, and only -formal club-builder child #4147 is closed. The variation request is -substantively implemented, but #4142/#4144 remain open because bounded -large-ensemble execution, nonlinear global sensitivity, localized execution, -the immutable UpstreamDrift consumer pin, protected CI, and default-branch -release are incomplete. - -The literal universal-runner audit also found two uncovered many-evaluation -paths. Wind strategy analysis retains all paired outcomes but has no user -workflow or universal plot adapter; capability optimization retains aggregates -but not individual sample rows. The next safe model slice is a UI-neutral -scalar-ensemble contract with unique composite row IDs, unit-bearing variable -metadata, caller-defined cohorts, paired-finite scatter extraction, and exact -availability accounting. Wind integration must accept both its immutable -request and analysis so launch definitions and provenance are not inferred. -Issue #4199 already owns the required controls, scatter, strategy table, -progress/cancellation, and export workflow. - -The first narrow #4199 implementation slice is published as -[draft PR #4281](https://github.com/D-sorganization/Tools/pull/4281) from branch -`feat/4199-wind-scalar-adapter`, stacked on exact PR #4280 head -`d71b0ea01b5659d3049ff05627c41f06481207e4`. Implementation commit -`4a28114aa` introduces an exact -cross-runtime `scalar-ensemble/v1` wire contract and pure wind-strategy -adapters. The contract preserves structured provenance, unit-bearing variable -definitions, caller-defined cohorts, RFC3986 composite identities, nullable -raw rows, and exact scatter availability. The adapters validate the immutable -request against the stored paired analysis, preserve completed, -nonconverged, and invalid outcomes, and never invoke a flight model. React has -an explicit mocked-integrator regression test for that boundary. - -Current exact local evidence is 906 Python/PyQt/shared-swing tests passed with -one expected optional-Rust skip and 15 existing warnings, plus 91 React test -files / 555 tests passed. Ruff, formatting, Black, focused mypy, TypeScript, -zero-warning ESLint, the 166-module production build, and `git diff --check` -passed. The function budget passed, but the 403-line wind adapter did not meet -the mandatory below-400 module ceiling at that historical head; the -2026-08-11 repair above corrects that blocker. The adapter is plot-ready model -infrastructure, not an end-user workflow; #4199 remains open for worker, -progress/cancellation, client controls, strategy/scatter displays, -persistence, and exports. - -### 2026-08-07 ground and four-surface audit refinement - -The rolling-ground and cross-application parity requests remain tracked by the -existing [ground epic #4267](https://github.com/D-sorganization/Tools/issues/4267) -and [parity epic #4260](https://github.com/D-sorganization/Tools/issues/4260); -no duplicate epic or child issue is required. The latest exact-path audit and -acceptance refinements are attached to -[the ground epic](https://github.com/D-sorganization/Tools/issues/4267#issuecomment-5222725556) -and [the parity epic](https://github.com/D-sorganization/Tools/issues/4260#issuecomment-5222726010). - -The scientific implementation order is contractual: #4268 defines the -surface/contact/trajectory/result transfer state, then #4269 corrects physical -terrain contact and preserves terminal full angular velocity. Only then may -#4270/#4271 qualify the 3D impulse, repeated bounce, skid, and pure-roll -phases. Carry remains first physical contact. Final downrange, final lateral, -horizontal displacement, surface path length, and launch-monitor-style total -distance are distinct quantities; no implementation may silently assume -`total distance = carry + roll distance`. - -Reusable UpstreamDrift scope is deliberately narrow: its split terrain -material/elevation/normal/region package can feed a one-way versioned DTO -adapter. Current scalar landing, heuristic putting-roll, duplicate legacy -terrain, and Rust tangential-loss implementations are reference material, not -the qualified physics authority. Upstream surface defaults remain illustrative -until citations, calibration, uncertainty, and applicability are recorded. - -The parity matrix must distinguish seven product identities: standalone Rate -PyQt6 and React, the Upstream Rate PyQt provider and React route, Upstream Shot -Tracer PyQt6 and React, and the legacy Upstream ball-flight GUI. Current -Upstream `main` (`0782853295e005af68818617e4725eb980890f43`) pins Tools at -`ff4240217005e1415ca409fd124e50b64ee642d2`, exposes no native Rate React route, -and contains contradictory vendor-first and sibling-first Tools resolvers. -These facts are current audit evidence, not completion; #4260, #4267, and all -children remain open. - -## 2026-08-10 PR #4202 D-plane ndarray typing repair - -- The repair is based on exact published PR `#4202` head - `b443fdbed7064c5db0320106013c8413e3e24356` and retains base - `feat/4162-wedge-impact-visualization`. -- CI Standard run `31384810375`, job `93442745760`, reported two pinned MyPy - 1.13 `no-any-return` errors in private NumPy conversion/projection helpers. - Explicit ndarray local boundaries resolve those errors without changing - geometry, validation, frames, serialized contracts, or UI behavior. -- RED/GREEN evidence is exact: two errors reproduced before the edit and zero - afterward. Twenty-four focused D-plane/impact tests, seven metadata/pre-push - contract tests, scoped Ruff/Ruff-format/Black, docs governance, minimum-test, - module-size, changed-file-size, and diff checks pass. Three exploratory - CI-workflow contract tests retain unrelated older-branch toolcache/env drift; - no workflow file is changed here. -- This repair does not alter the stacked base, publish the branch, change its - draft state, or authorize a merge. Parent-first ordering, protected CI, and - review remain required. - -## 2026-08-10 Propagation into 3D D-plane geometry - -- Immediate child PR `#4202` keeps base - `feat/4162-wedge-impact-visualization`. -- Its original head `b4abec03bccfbdd87ddf91427159c5c2332c21dd` - normally merges exact parent `#4179` head - `6704a3e541a3e74c28b4a284530d1a21269dd340`; no branch rewrite, retarget, or - force push is permitted. -- The Python 3.10 UTC repair and AST guard are inherited alongside the typed, - frame-explicit D-plane, spin-loft, visualization, and export contracts. -- Persisted D-plane layer controls are extracted into a focused helper so the - simulation view satisfies the protected 500-line module budget without a - behavior or compatibility-seam change. -- Combined-stack verification is green: 93 focused and 825 scoped Python tests - (two optional `build123d` skips), 360 React tests and all web gates, real - CPython 3.10.20 compilation/UTC, scoped Ruff/Black/MyPy, and repository - governance gates. The exact parent's 12 unchanged `swing-core` tests remain - applicable because this child has no Rust delta. The inherited 17-error broad - MyPy Qt/NumPy baseline in 11 untouched files remains outside scope. - Protected CI and required review remain release gates. - -## 2026-08-10 Propagation into wedge impact visualization - -- Immediate child PR `#4179` keeps base `feat/4166-wedge-turf-physics`. -- Its original head `0eb804e70887c788421332369e42792411aff55a` - normally merges exact parent `#4178` head - `bfa83aedc88ead380babc73a699377d98b971006`; no branch rewrite, retarget, or - force push is permitted. -- The Python 3.10 UTC repair and AST guard are inherited alongside the - exact-event, locked-scale, exportable impact-scene contract. -- Combined-stack verification is green: 58 focused and 739 scoped Python tests - (two optional `build123d` skips), 347 React tests and all web gates, real - CPython 3.10.20 compilation/UTC, scoped Ruff/Black/MyPy, and repository - governance gates. The exact parent's 12 unchanged `swing-core` tests remain - applicable because this child has no Rust delta. The inherited 17-error broad - MyPy Qt/NumPy baseline in 11 untouched files remains outside scope. - Protected CI and required review remain release gates. - -## 2026-08-10 Propagation into wedge turf physics - -- Immediate child PR `#4178` keeps base `feat/4161-wedge-ground-clearance`. -- Its original head `aaae3f73e17dbfaad5cca1dc6f49559b3aebe9d5` - normally merges exact parent `#4174` head - `9ea93e92563280ec34bca682ad44d7409edd7a02`; no branch rewrite, retarget, or - force push is permitted. -- The Python 3.10 UTC repair and AST guard are inherited alongside the passive, - provenance-gated turf-contact model and explicit force-coupling boundary. -- Combined-stack verification is green: 56 focused and 732 scoped Python tests - (two optional CAD-dependency skips), real CPython 3.10.20 checks, scoped - static analysis, and repository governance gates. With no web or Rust delta, - the exact parent's green 345 React and 12 Rust tests remain applicable. The - inherited 17-error broad MyPy Qt/NumPy baseline in 11 untouched files remains - outside scope. - -## 2026-08-10 Propagation into wedge ground clearance - -- Immediate child PR `#4174` keeps base `feat/4163-impact-inspector`. -- Its original head `880a6465fc872cf3d6650283db154ddc41793a31` - normally merges exact parent `#4173` head - `9ddaff3b6bca542fd7a2befc7d7b0ae53910a60a`; no branch rewrite, retarget, or - force push is permitted. -- The Python 3.10 UTC repair and AST guard are inherited alongside the swept - wedge ground-clearance model, persistence, PyQt, and React surfaces. -- Combined-stack verification is green: 56 focused and 703 scoped Python tests - (two optional CAD-dependency skips), 345 React tests and all web gates, 12 - Rust tests, real CPython 3.10.20 checks, scoped static analysis, and - repository governance gates. The inherited 17-error broad MyPy Qt/NumPy - baseline in 11 untouched files remains outside scope. - -## 2026-08-10 Propagation into impact inspector - -- Immediate child PR `#4173` keeps base `feat/4144-variation-visualizations`. -- Its original head `3c43955aaeb3964ff8c3ef2748d626baae518b76` - normally merges exact parent `#4167` head - `22b66b560652b78de84141344c4ddd9a92a83b26`; no branch rewrite, retarget, or - force push is permitted. -- The Python 3.10 UTC compatibility repair and its AST guard are inherited - additively alongside the existing shared wedge impact-inspector contract. -- Combined-stack verification is green: 63 focused and 562 total Rate Python - tests; 334 React tests plus type-check, lint, and production build; 12 Rust - tests; real CPython 3.10.20 compile/UTC checks; scoped static analysis and - repository governance gates. The broad MyPy sweep retains 17 pre-existing - Qt/NumPy typing findings in 11 untouched files. Current-head protected CI and - required review remain pending release evidence. - -## Dependency position - -PR `#4167` (`feat/4144-variation-visualizations`) is the base-most open Rate -feature above the already merged `feat/investigation-suite` carrier. Later -wedge, D-plane, launch-monitor, workspace, wind, capability, and ground work -depends on this line and must receive any repair through ordinary parent -propagation; child branches must not be rewritten. - -## 2026-08-10 Python 3.10 repair - -- Protected CI at exact pre-repair head - `edaa56358a9ccf47809533fcab28e6415b336771` collected 13 Rate test modules - unsuccessfully because `datetime.UTC` does not exist on Python 3.10. -- The torque-profile controller now consumes the repository's existing - `shared.python.compatibility.UTC` export. -- A source-tree AST guard rejects future direct imports and unaliased or - aliased `datetime.UTC` module-attribute access anywhere under - `src/rate_of_closure`. -- Local evidence is green: 27 focused controller/history/AST tests and the - complete 554-test Rate suite on Python 3.13; real CPython 3.10.20 compatibility - import; Ruff check/format; focused pinned MyPy 1.13; detect-secrets; - touched-file size and diff checks. - -## Truthful release state - -This is an actionable compatibility repair, not completion of issue `#4144` or -the variation epic. Current-head protected CI, required review, dependency -propagation, and ordinary merges remain required. Runner download timeouts, -missing toolcache/link libraries, cancelled jobs, and queued jobs are tracked -as infrastructure and are never counted as green evidence. - -Every implementation commit must update this file, both other canonical -handoffs, and `SPEC.md`, or explicitly record no material handoff change and -the reason. - -## 2026-08-11 additional parent sections preserved during #4282 reconciliation - -## 2026-08-09 PR #4279 Python 3.10 compatibility completion - -Exact corrected #4203 parent -`08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` is incorporated into #4279 by -normal local merge `a340fabefa443d47325c5538f342683b38c01ade`; the stack base is -unchanged and nothing was rebased, retargeted, force-pushed, or published. -The two child-owned string-enum modules and child workspace UTC validator now -use the existing shared Python 3.10 compatibility contract at runtime. Native -enum typing remains explicit under `TYPE_CHECKING`, and wire IDs, schemas, -timestamp serialization, physics, and UI behavior are unchanged. - -The reconciled test covers nine `StrEnum` runtime imports, both `UTC` runtime -imports, and direct execution of all three child workspace modules. Python -3.11 passes `126` focused tests. Real CPython 3.10.20 passes all `14` -compatibility cases and imports 10 dotted Rate/shared targets. Ruff -check/format and pinned mypy 1.13 pass all affected files; documentation -governance and diff checks are required in the same commit. Protected CI, -review, publication, and normal propagation to #4280 and later descendants -remain outstanding. - -## 2026-08-09 PR #4279 parent propagation - -The #4279 continuation remains based on `feat/4181-launch-monitor-registry` and -now contains exact parent head -`08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` through a normal merge. Source -changes applied cleanly; the overlapping handoff/specification histories were -reconciled monotonically. The result retains the parent's Linux-safe facade -and Python 3.10 compatibility contracts plus the child's workspace, -top-toolstrip, module-navigation, playback, and independent plot controls. No -branch was rebased, retargeted, force-pushed, or published by this continuation. - -Current focused evidence is `126 passed` for both facade modules and all -Python/PyQt tests changed by #4279, plus `8 React files / 32 tests passed` for -the matching workspace surfaces. Ruff check/format is clean across all 28 -relevant Python files. CI-pinned mypy 1.13 is clean across the 18 changed -production files and both facade tests after making the child's -`legend_visible()` Qt boundary return an explicit `bool`. Documentation -governance, staged/unstaged diff checks, and the affected `29`-test simulation -GUI rerun pass. Protected CI, review, and publication remain separate release -requirements. - -## 2026-08-09 Python 3.10 compatibility follow-up - -The descendant Python 3.10 lane revealed seven unconditional -`enum.StrEnum` imports already present at PR #4203. The earliest owning parent -now routes runtime imports through `shared.python.compatibility.StrEnum` while -using the stdlib type only under `TYPE_CHECKING`. The change preserves every -enum value and schema while removing the Python 3.11-only import boundary. -Local evidence is 64 focused contract/physics/compatibility tests, Ruff and -format, pinned mypy 1.13 across eight changed files, and a real CPython 3.10.20 -probe of the shared fallback and seven module import declarations. Parent is -published at exact head `ab7de5a47977417e02926c3fbc7476002e82b690`; -propagate it through #4279, #4280, #4281, and #4282 before retrying descendants. - -The same scan found one parent-owned `datetime.UTC` import in the PyQt torque -profile controller. It now consumes the established compatibility constant, -preserving UTC serialization while allowing Python 3.10 collection. This -follow-up belongs on #4203 before the child stack is propagated. - -## 2026-08-09 Launch-registry parent CI repair - -The earliest campaign parent, draft PR #4203, remains based on -`feat/4189-dplane` at exact published head -`912ebc9d69b05763a76c2c8f198d943737e2d3fb`. CI run `31199764932` passed its -quality gate, then all Python versions failed before assertions because pytest -collected the flight and solver contract modules through `src.shared...` while -their absolute dotted facade aliases requested the editable `shared...` -namespace. The scoped repair converts only those two test imports to relative -package imports. Production APIs and physics are unchanged. The same run's -Rust failure is the known runner inability to link `-lpython3.11`. Validate -the two contract modules under importlib collection, publish a new exact head, -and propagate it through #4279, #4280, #4281, and #4282 in normal order. -Both modules now pass all `12` tests on Windows and WSL Python 3.11 with -importlib collection. Ruff check/format and pinned mypy 1.13 are clean. A -test-only `Any` cast keeps frozen-dataclass metadata introspection explicit -without weakening the runtime contract. diff --git a/docs/release/rate_of_closure_campaign.v1.json b/docs/release/rate_of_closure_campaign.v1.json index 1f60a6630..133582e1f 100644 --- a/docs/release/rate_of_closure_campaign.v1.json +++ b/docs/release/rate_of_closure_campaign.v1.json @@ -134,7 +134,7 @@ "pr": 4282, "branch": "feat/4199-wind-workflow", "base_branch": "feat/4199-wind-scalar-adapter", - "head_sha": "b2baf6ef615b0d756a86ac4ca7eef2fc583210ee", + "head_sha": "18fe89201d657116bbca99922297c14968356c44", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -154,7 +154,7 @@ "pr": 4285, "branch": "feat/4268-ground-contract", "base_branch": "feat/4197-capability-observer", - "head_sha": "584e4e53a7990053a346938c4e45538786887ec7", + "head_sha": "6a2bc9d06f6f9a28a0d615b19d2ed4fc13871059", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -164,7 +164,7 @@ "pr": 4288, "branch": "feat/4269-flight-ground-transfer", "base_branch": "feat/4268-ground-contract", - "head_sha": "c39297d37a17d5d8d3520ed62c5563cdcc609cab", + "head_sha": "4972e55e0bb6e5b6bf7da0f899eed5d4f54e7d9d", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -194,7 +194,7 @@ "pr": 4302, "branch": "feat/4270-ground-impact-bounce", "base_branch": "feat/4269-flight-ground-transfer", - "head_sha": "62beb3e1aa951645fd556a53f9cbae4bb46c47e5", + "head_sha": "cf6e72bad98e5f36f782254942e6895b8b71e670", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -204,7 +204,7 @@ "pr": 4304, "branch": "feat/4271-ground-skid-roll", "base_branch": "feat/4270-ground-impact-bounce", - "head_sha": "3f861c1faaa7455faee92eaa7f813174667208e0", + "head_sha": "0ea6740965068542e9d8c7449e06ec07d88969e0", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -214,7 +214,7 @@ "pr": 4332, "branch": "feat/4271-regional-surface-transitions", "base_branch": "feat/4271-ground-skid-roll", - "head_sha": "5ac3c1f233de30dd42eeac57073cbdb149bde652", + "head_sha": "04ccf08dd990de1cd056a3420e67772773a4be2e", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -224,7 +224,7 @@ "pr": 4335, "branch": "feat/4271-regional-wire-contract", "base_branch": "feat/4271-regional-surface-transitions", - "head_sha": "8f933ed8dcb29e55ece4ec6bb1e60813f6794d57", + "head_sha": "9e01ccc3e891cc45907293751a192624195a77a5", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -234,7 +234,17 @@ "pr": 4339, "branch": "feat/4274-regional-surface-ui", "base_branch": "feat/4271-regional-wire-contract", - "head_sha": "d21741e312b849a63f73cabf351a15d9de80fb94", + "head_sha": "db335937afc4b587d235eb705e315f577519c5e6", + "state": "open", + "merge_commit_sha": null, + "protection_evidence": "not_recorded" + }, + { + "id": "pr-4342", + "pr": 4342, + "branch": "feat/4274-regional-plan-io", + "base_branch": "feat/4274-regional-surface-ui", + "head_sha": "c1f47f2ef68b3db102da5416aaac17a40f675207", "state": "open", "merge_commit_sha": null, "protection_evidence": "not_recorded" @@ -423,6 +433,42 @@ "src/rate_of_closure/AGENT_HANDOFF.md", "docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md" ] + }, + { + "id": "ground-regional-ui-helper-local-d217", + "kind": "local", + "commit_sha": "d21741e312b849a63f73cabf351a15d9de80fb94", + "outcome": "passed", + "commands": [ + "python -m pytest tests/rate_of_closure/test_regional_surface_plan.py tests/rate_of_closure/test_gui.py tests/rate_of_closure/test_layout_minsize.py -q", + "npm test -- --run", + "npm run type-check && npm run lint && npm run build", + "uvx --from ruff==0.14.10 ruff check src/rate_of_closure tests/rate_of_closure && uvx --from ruff==0.14.10 ruff format --check src/rate_of_closure tests/rate_of_closure" + ], + "summary": "The current PR #4339 parent passed focused Python/PyQt and React qualification plus the complete 672-test React suite after replacing its six-parameter number-input helper with a frozen specification and three-parameter helper. This remains local evidence, not protected release evidence.", + "source_paths": [ + "AGENT_HANDOFF.md", + "src/rate_of_closure/AGENT_HANDOFF.md", + "docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md" + ] + }, + { + "id": "ground-regional-io-local-8e1c", + "kind": "local", + "commit_sha": "8e1c7ccd99a7c4886c5fb9ccc7e4d94a6d7e3833", + "outcome": "passed", + "commands": [ + "python -m pytest tests/rate_of_closure/test_regional_surface_plan.py tests/rate_of_closure/test_regional_surface_plan_io.py tests/rate_of_closure/test_workspace_files.py -q", + "npm test -- --run src/components/RegionalSurfacePlanPanel.test.tsx", + "npm run type-check && npm run lint && npm run build", + "uvx --from ruff==0.14.10 ruff check src/rate_of_closure tests/rate_of_closure && uvx --from ruff==0.14.10 ruff format --check src/rate_of_closure tests/rate_of_closure" + ], + "summary": "The published PR #4342 child passed strict native atomic and bounded browser regional request I/O qualification, safe-number parity, bounded UTF-8 import, static analysis, build, and governance gates before parent reconciliation. Fresh protected evidence remains open.", + "source_paths": [ + "AGENT_HANDOFF.md", + "src/rate_of_closure/AGENT_HANDOFF.md", + "docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md" + ] } ], "programs": [ @@ -1204,7 +1250,8 @@ "pr-4304", "pr-4332", "pr-4335", - "pr-4339" + "pr-4339", + "pr-4342" ], "supported_surfaces": { "tools.pyqt6": "implemented_unverified", @@ -1217,14 +1264,16 @@ "ground-skid-roll-local-f475", "ground-regional-local-1a48", "ground-regional-wire-local-74a0", - "ground-regional-ui-local-cbb9" + "ground-regional-ui-local-cbb9", + "ground-regional-ui-helper-local-d217", + "ground-regional-io-local-8e1c" ], - "evidence_gap": "The contract, flight-transfer, impact/bounce, static-plane skid/roll, regional-surface, regional-plan wire, and regional-editor carriers remain open on draft PRs 4285, 4288, 4302, 4304, 4332, 4335, and 4339. Exact local evidence exists, but fresh protected evidence for the reconciled heads, execution/playback, result interchange, workspace model-input persistence, changing geometry, compiled-runtime physics, and downstream parity remain absent.", + "evidence_gap": "The contract, flight-transfer, impact/bounce, static-plane skid/roll, regional-surface, regional-plan wire, regional-editor, and regional request-I/O carriers remain open on draft PRs 4285, 4288, 4302, 4304, 4332, 4335, 4339, and 4342. Exact local evidence exists, but fresh protected evidence for the reconciled heads, execution/playback, result interchange, workspace model-input persistence, measured calibration, changing geometry, compiled-runtime physics, and downstream parity remain absent.", "limitations": [ "Airborne flight must first terminate against physical terrain and preserve terminal angular velocity.", "Current UpstreamDrift terrain and putting implementations are reference inputs rather than the qualified authority.", "The #4270 rigid impact law does not consume firmness, grass, compressibility, moisture, or rolling-resistance fields.", - "Published open PR #4304 qualifies one immutable planar profile and optional finite tangent-axis edge; open PR #4332 adds bounded coplanar material overlays; open PR #4335 adds a strict Python/TypeScript plan wire boundary and Python resolver; and open PR #4339 adds matched session-only PyQt6/React request editors. Changing normals, height or velocity discontinuities, terrain deformation, torsional-spin damping, roll-to-skid transitions, internal transition-ledger export, execution/playback, result interchange, measured calibration, workspace model-input persistence, compiled or TypeScript regional physics, and downstream adapters remain unimplemented." + "Published open PR #4304 qualifies one immutable planar profile and optional finite tangent-axis edge; open PR #4332 adds bounded coplanar material overlays; open PR #4335 adds a strict Python/TypeScript plan wire boundary and Python resolver; open PR #4339 adds matched PyQt6/React request editors; and open PR #4342 adds editor-qualified canonical request import/export with native atomic semantics and explicit browser limitations. Changing normals, height or velocity discontinuities, terrain deformation, torsional-spin damping, roll-to-skid transitions, internal transition-ledger export, execution/playback, result interchange, measured calibration, workspace model-input persistence, compiled or TypeScript regional physics, and downstream adapters remain unimplemented." ], "depends_on_issues": [ 4191 diff --git a/docs/specs/GROUND_SKID_ROLL.md b/docs/specs/GROUND_SKID_ROLL.md index c8b7e1a28..1e39b2750 100644 --- a/docs/specs/GROUND_SKID_ROLL.md +++ b/docs/specs/GROUND_SKID_ROLL.md @@ -203,11 +203,23 @@ schema, unit, provenance, and request readback. The regional v1 wire schema has no calibration record, so the editor does not invent one or widen that schema. `unvalidated` is explicit presentation/source -qualification and is included in the source digest. This first slice is -session-only: current web workspace file commands do not persist model inputs, -and neither client claims request export/import, execution, result playback, -or measured-course calibration. Those capabilities require separate contracts -and acceptance evidence. +qualification and is included in the source digest. PyQt6 native Open/Save As +and React browser import/download persist only the canonical regional request; +workspace model-input persistence remains a separate contract. Import is +transactional and accepts only the editor producer/provider v1, fixed qualified +axis/geometry, and editor row capacity. An unchanged import retains the exact +request and provenance; editing rebinds the draft digest. Browser downloads +cannot promise a native path, atomic replacement, or recent-file access. +Wire numbers are bounded to the shared cross-runtime safe range. Native +precedence entry preserves every nonnegative integer through +9,007,199,254,740,991 exactly, so a qualified import cannot be silently narrowed +before validation or Save As. +Native import reads one binary handle with a one-byte overflow sentinel before +strict UTF-8 decoding, so mutable files cannot bypass the 1 MiB allocation cap +between a metadata check and content parsing. +Neither client claims execution, result playback, or measured-course +calibration. Those capabilities require separate contracts and acceptance +evidence. Skid and roll distances are accumulated separately from centre speed relative to the moving surface. Collinear constant-acceleration segments use the exact diff --git a/src/rate_of_closure/AGENT_HANDOFF.md b/src/rate_of_closure/AGENT_HANDOFF.md index 52a1d5c5f..d858b22d7 100644 --- a/src/rate_of_closure/AGENT_HANDOFF.md +++ b/src/rate_of_closure/AGENT_HANDOFF.md @@ -1,5 +1,38 @@ # AGENT_HANDOFF — rate_of_closure +## 2026-08-11 PR #4342 current-parent propagation candidate + +This local no-publish merge keeps `feat/4274-regional-plan-io` over +`feat/4274-regional-surface-ui`. Exact current child +`c1f47f2ef68b3db102da5416aaac17a40f675207` is the first parent and exact +reviewed local #4339 candidate `db335937afc4b587d235eb705e315f577519c5e6` +is the second parent. Child-owned canonical request import/export, bounded UTF-8, +native atomic save, browser-qualified download, tests, and limitations remain +intact while inheriting current editor, wire, regional physics, and complete +ground ancestry. + +The default shared canonical encoder continues to reject floats and integers +outside JavaScript's safe range. Only the capability-observation facade selects +a separately named extended finite-float policy. It shares the same recursive +encoder, retains safe-range integer checks, emits exact exponent-free `1e20` +and `1e21` tokens matching TypeScript, and rejects non-finite values. + +Local qualification passes all `909` Rate-of-Closure Python tests, all `110` +React files / `686` tests, the complete Cargo workspace, `47` focused Python +compatibility/regional-I/O tests, and `12` focused React capability tests. +Pinned Ruff 0.14.10 check/format passes `17` changed Python files; pinned MyPy +1.13 and Bandit pass `12` changed production files. TypeScript, zero-warning +ESLint, the 199-module Vite build, Rust format/warning-denied clippy, 400- and +500-LOC gates, manifest/docs/blocking-gate/assertion/minimum-test governance, +marker scans, and diff checks pass. One untouched manual-delivery UI test timed +out in the first concurrent full run, then passed alone and in the single +complete rerun. + +The candidate is not published or released. Execution/playback, result +interchange, measured calibration, persistence, changing geometry or velocity, +TypeScript/compiled regional physics, downstream parity, protected exact-head +evidence, review, approval, dependency integration, and release remain open. + ## 2026-08-11 PR #4339 current-parent propagation candidate This local no-publish merge keeps `feat/4274-regional-surface-ui` over @@ -28,184 +61,16 @@ interchange, measured calibration, persistence, changing geometry or velocity, TypeScript/compiled regional physics, downstream parity, protected exact-head evidence, review, approval, dependency integration, and release remain open. -## 2026-08-11 PR #4339 structural helper repair candidate - -This local follow-up descends exact independently reviewed reconciliation -candidate `eedad6d23b517eb4c99d4ba9000ff6555101099f`. Independent review found -one publication blocker: the regional PyQt number-input helper accepted six -parameters, above the campaign's mandatory four-parameter limit. RED-first -tests now bind the helper's signature and all observable widget settings. A -frozen `NumberInputSpec` validates finite positive step and finite ordered -bounds before widget construction; the three-parameter helper preserves field -names, values, units, ranges, increments, tooltips, and presentation order. - -Eight focused Python/PyQt tests and 25 focused React tests pass; the complete -React suite passes all 108 files / 672 tests. Pinned Ruff check/format, MyPy on -all six affected production modules, Bandit medium/high screening, TypeScript, -zero-warning ESLint, documentation/manifest governance, changed-production, -test-assertion, minimum-test, 500-LOC, and diff gates pass. Mandatory maxima -are 400 module lines, 42 function lines, and three parameters. A broader -Rate-of-Closure Python run reached the ten-minute workstation lifecycle bound -without yielding an assertion failure; it is not counted as passing evidence. -The monorepo-wide lane separately exposed unrelated baseline failures and -xdist worker termination. No schema, digest, regional physics, UI behavior, -PR base, protected evidence, or release boundary changes. - -## 2026-08-11 PR #4339 current-parent ancestry candidate - -The clean `feat/4274-regional-surface-ui` worktree normally merges exact -published child `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` with exact newly -published #4335 parent `9e01ccc3e891cc45907293751a192624195a77a5`, -without changing #4339's base. The accessible PyQt6/React editors and strict -invalidation behavior remain intact alongside the parent's wire, resolver, -regional-physics, and complete ground ancestry. Execution/playback, result -interchange, persistence, compiled physics, downstream parity, protected -evidence, integration, and release remain open. - -## 2026-08-10 PR #4339 stale-validation invalidation follow-up - -Rendered exact-head browser QA found that a validated one-overlay readback -remained visible after adding a second overlay. The broad PyQt6 suite also -found missing hover hints on the new controls. PyQt6 and React now clear both -canonical readback and prior validation state whenever any identity, interval, -material, or overlay-row draft value changes; PyQt6 exposes the explicit -"Changes not validated" pending state, and every PyQt6 interactive has a -specific engineering-context tooltip. RED-first regression tests cover the -dynamic-row path on both surfaces. Final local evidence is 870 Python/PyQt -tests and 672 React tests passing; Ruff, format, MyPy, TypeScript, zero-warning -ESLint, the 198-module production build, manifest/docs/file-size governance, -and diff checks are clean. The known polynomial-generator empty-legend warning -is unrelated. This changes no wire schema, provenance digest, physics, or -persistence boundary; fresh protected CI is still required before merge. - -## 2026-08-11 Regional wire receives current regional-surface parent - -Open draft PR `#4335` retains `feat/4271-regional-wire-contract` over -`feat/4271-regional-surface-transitions`. Exact remote regional-wire child -`9e01ccc3e891cc45907293751a192624195a77a5` is merged first and exact current -regional-surface parent `5ac3c1f233de30dd42eeac57073cbdb149bde652` -second by an ordinary no-ff merge. Child-owned wire production, schemas, -tests, canonical fixture evidence, resolver binding, and limitations remain -intact while inheriting current regional, skid/roll, impact/bounce, -flight-transfer, and strict-ground ancestry. - -Focused local qualification passes all `132` Python ground/regional-wire tests, -`9` focused React regional/ground-contract tests, and all `137` `tools-core` -Rust tests. TypeScript, zero-warning ESLint, the 190-module Vite build, Rust -format and warning-denied clippy, pinned Ruff 0.14.10 across six changed Python -files, pinned MyPy 1.13 and Bandit medium/high across four production files, -the 500-LOC changed-file gate, manifest validation plus eight contracts, -documentation governance, exact wire-tree preservation, history/marker, and -diff checks are green. - -This candidate remains unpublished and `not_released`. Changing geometry or -velocity, internal transition-ledger export, regional UI, compiled or -TypeScript regional physics, UpstreamDrift parity, protected exact-head CI, -review, approval, dependency integration, and release remain open. - -## 2026-08-11 Regional surfaces receive current skid/roll parent - -Open draft PR `#4332` retains -`feat/4271-regional-surface-transitions` over -`feat/4271-ground-skid-roll`. Exact remote regional-surface child -`04ccf08dd990de1cd056a3420e67772773a4be2e` is merged first and exact current -skid/roll parent `3f861c1faaa7455faee92eaa7f813174667208e0` second by an ordinary no-ff -merge. Child-owned regional transition production, tests, fixtures, contracts, -evidence, and limitations remain intact while inheriting current skid/roll, -impact/bounce, flight-transfer, and strict-ground ancestry. - -Focused local qualification passes all `121` Python ground/regional tests, -`20` focused React ground-contract/transfer tests, and all `137` `tools-core` -Rust tests. TypeScript, zero-warning ESLint, the 189-module Vite build, Rust -format and warning-denied clippy, pinned Ruff 0.14.10 across 14 changed Python -files, pinned MyPy 1.13 and Bandit medium/high across 12 production files, the -500-LOC changed-file gate, manifest validation plus eight contracts, -documentation governance, exact child-tree preservation, history/marker, and -diff checks are green. - -This candidate remains unpublished and `not_released`. Changing normals, -discontinuous geometry or surface velocity, regional UI, compiled regional -physics, UpstreamDrift parity, protected exact-head CI, review, approval, -dependency integration, and release remain open. - -## 2026-08-11 Skid/roll receives current impact/bounce parent - -Open draft PR `#4304` retains `feat/4271-ground-skid-roll` over -`feat/4270-ground-impact-bounce`. Exact remote skid/roll child -`0ea6740965068542e9d8c7449e06ec07d88969e0` is merged first and exact current -impact/bounce parent `62beb3e1aa951645fd556a53f9cbae4bb46c47e5` -second by an ordinary no-ff merge. Child-owned skid/roll production, contracts, -tests, fixture, and limitations remain intact while inheriting current impact, -flight-transfer, and strict-ground ancestry. - -Local verification passes `154` focused ground/flight tests, all eight manifest -tests, and all `137` `tools-core` Rust tests. Pinned Ruff 0.14.10 covers the 18 -PR-delta Python files; pinned MyPy 1.13 and Bandit medium/high cover 12 -production files. Rust format/clippy, manifest, docs, exact child-tree, -history/marker, and diff gates are green. - -This local model slice remains `not_released`. Regional/changing-normal -surfaces, deformation, torsional damping, roll-to-skid transitions, UI, -compiled physics, publication, protected exact-head CI, review, approval, -downstream integration, and release remain open. - -## PR #4302 corrected-flight-transfer propagation - -Exact corrected #4288 parent -`247215422a6d4b677552955b4923bc609a553259` is incorporated into -`feat/4270-ground-impact-bounce` by the normal merge containing this handoff. -PR #4302 keeps base `feat/4269-flight-ground-transfer`; neither branch was -rebased, retargeted, rewritten, or force-pushed. The child retains passive -impact, deterministic repeated hops, exact contact, capture-to-skid, bounded -cancellation/failure, and airborne evidence while inheriting corrected flight -transfer, deterministic workspace timestamps, and canonical `swing_sim` -identity. - -This remains a partial `not_released` slice. Issue #4271 retains skid, roll, -rest, total distance, and final ground results; terrain deformation, UI, -TypeScript bounce physics, compiled bounce runtimes, and UpstreamDrift adapters -remain excluded. Protected CI, independent review, and normal stack collapse -remain open. -Merged-tree validation is `987` Python tests, `106` React files / `661` tests, -and the complete `tools-core` Rust suite at `137` tests (`111` unit, `20` -transfer, `6` wire). The affected cross-version suite is also `146` tests on -real CPython 3.10.20. The 189-module Vite production build, TypeScript, -zero-warning ESLint, Ruff check/format across 90 files, pinned mypy 1.13 across -all 17 ground and nine transfer production modules, Rust workspace format plus -warning-denied `tools-core` clippy, campaign-manifest validator plus eight -contracts, documentation governance, 11-file 500-LOC budget, marker scan, and -diff checks are clean. Hosted checks and review apply to the new exact merge -head only. - - -## PR #4288 corrected-ground propagation - -Exact corrected #4285 parent -`788aa547651a3685a363ea401824a5d81477bafb` is incorporated into -`feat/4269-flight-ground-transfer` by the normal merge containing this handoff. -PR #4288 keeps base `feat/4268-ground-contract`; neither branch was rebased, -retargeted, rewritten, or force-pushed. The child retains its qualified -cross-runtime terminal-state/contact transfer and inherits the corrected UTC -parser plus canonical `swing_sim` import identity. - -This is ancestry propagation, not bounce, skid, roll, terrain response, total -distance, or UI delivery. Protected CI, independent review, and normal stack -collapse remain open. - -Merged-tree validation is `951` Python tests, `106` React files / `661` tests, -and `26` focused Rust transfer/wire tests. The affected cross-version suite is -also `110` tests on real CPython 3.10.20. The 189-module Vite production build, -TypeScript, zero-warning ESLint, Ruff check/format across 82 files, pinned mypy -1.13 across the six-file transfer and 13-file parent production namespaces, -Rust workspace format plus warning-denied `tools-core` clippy, campaign-manifest -validator plus eight contracts, documentation governance, 13-file 500-LOC -budget, marker scan, and diff checks are clean. Hosted checks and review apply -to the new exact merge head only. +## 2026-08-11 PR #4342 append-only preservation repair - -> **Update this file with every PR and every push to main.** -> Last updated: 2026-08-11 +Independent audit of local merge `e7fedfb18de1550eed3484ed2fc99d0baaecdca1` +found that three older parent ancestry sections had been summarized instead of +retained verbatim. This docs-only follow-up restores the full parent text below +without changing production code, tests, schemas, manifest state, PR base, or +release claims. The exact parent sections and SPEC rows are now governed by +byte-for-byte comparison against +`d21741e312b849a63f73cabf351a15d9de80fb94`. ## 2026-08-11 PR #4335 current-parent ancestry candidate @@ -279,55 +144,6 @@ now records open PR #4332 at its still-published child head and open PR #4304 at its exact newly published parent head; neither record claims protected or main-release evidence. -## 2026-08-11 Ground-impact bounce receives current flight-transfer parent - -Open draft PR `#4302` retains `feat/4270-ground-impact-bounce` over -`feat/4269-flight-ground-transfer`. Exact remote bounce child -`cf6e72bad98e5f36f782254942e6895b8b71e670` is merged first and exact current -transfer parent `c39297d37a17d5d8d3520ed62c5563cdcc609cab` second by an -ordinary no-ff merge. The child-owned impact and repeated-bounce contracts, -tests, fixture, and explicit limitations remain intact while inheriting current -strict-ground and cross-runtime flight-transfer ancestry. - -Three inherited PR-delta Python files receive only their pinned Ruff 0.14.10 -layout. Analysis, persistence, and contract assertion behavior are unchanged. - -Local verification passes `1129` Rate/ground/flight Python tests, `25` focused -React transfer tests, and `137` Rust tests. TypeScript, zero-warning ESLint, the -189-module Vite build, Rust format/clippy, pinned Ruff 0.14.10, pinned MyPy -1.13, Bandit medium/high, manifest parsing, history preservation, and diff -checks are green. - -This is a local `not_released` candidate. Skid, roll, rest, total distance, -final ground results, UI, TypeScript bounce physics, and compiled bounce -runtimes remain outside this slice. Publication, protected exact-head CI, -review, approval, dependency integration, and release remain open. - -## PR #4285 workspace timestamp propagation - -Exact corrected #4282 parent -`5f77af4add23547a21cc3fabce98ae9ad4260427` is incorporated into -`feat/4268-ground-contract` by the normal merge containing this handoff. PR -#4285 keeps base `feat/4197-capability-observer`; neither branch was rebased, -retargeted, rewritten, or force-pushed. The child retains its strict -flight-to-ground contract and inherits the deterministic Python 3.10-3.12 UTC -parser plus complete variation, scalar, wind, capability, and release ancestry. - -The preceding exact-head Python 3.12 CI lane loaded embedded -`src.shared.python.swing_sim` tests and canonical `shared.python.swing_sim` -imports as distinct package trees, producing ground/impact collection errors. -The shared alias registry now coalesces that package root. A subprocess identity -contract failed before the fix and now passes together with both affected -public-API suites. The file-size job was cancelled in checkout before its -budget step and is not a code failure. - -Merged-tree evidence is `915` Rate/ground/impact Python tests, all `12` shared -alias architecture tests, `28` focused tests on CPython 3.12, `28` direct -workspace compatibility tests on real CPython 3.10.20, and `104` React files / -`642` tests. The production build, TypeScript, zero-warning ESLint, Ruff, -format, pinned mypy 1.13, campaign manifest and eight contracts, docs -governance, 500-LOC budget, marker scan, and diff checks pass. - ## 2026-08-11 PR #4304 current-parent ancestry candidate The clean dedicated `feat/4271-ground-skid-roll` worktree first fast-forwarded @@ -350,6 +166,180 @@ the official changed-file 500-LOC budget, and mandatory production limits of local merge is a PUBLISH candidate for independent review only; protected exact-head CI, approval, normal child propagation, and publication remain open. + +## 2026-08-11 PR #4342 current-parent reconciliation candidate + +The clean `feat/4274-regional-plan-io` worktree normally merges exact +published PR #4342 child `8e1c7ccd99a7c4886c5fb9ccc7e4d94a6d7e3833` +with exact newly published PR #4339 parent +`d21741e312b849a63f73cabf351a15d9de80fb94` as its second parent. PR #4342 +continues to target `feat/4274-regional-surface-ui`; neither branch is rebased, +retargeted, rewritten, force-pushed, or published by this reconciliation. +The merge preserves strict regional request import/export together with the +parent's frozen engineering-number specification and bounded helper. + +The child widget module now delegates its canonical-precision controls to that +shared three-parameter helper while retaining the inclusive cross-runtime safe +number bounds and eleven-decimal presentation required by its I/O contract. +Merged-tree qualification is 53 focused Python/PyQt/shared-ground tests and 14 +focused React tests passing. Pinned Ruff 0.14.10 check/format, MyPy 1.13 over +all ten affected production modules, Bandit medium/high screening, TypeScript, +zero-warning ESLint, and the 199-module production build pass. Campaign +manifest validation and all eight manifest tests, documentation and tool +manifest governance, changed-Python, minimum-test, exact-diff assertion, +500-LOC, parent/child diff, and whitespace gates pass. Mandatory structural +maxima are 396 module lines, 40 function lines, and three parameters. +The local merge is not protected or release evidence. Independent review, +ordinary fast-forward publication, fresh protected CI/approval, dependency +integration, and release remain required. + +## 2026-08-11 PR #4339 structural helper repair candidate + +This parent follow-up descends exact independently reviewed reconciliation +candidate `eedad6d23b517eb4c99d4ba9000ff6555101099f`. Independent review found +one publication blocker: the regional PyQt number-input helper accepted six +parameters, above the campaign's mandatory four-parameter limit. RED-first +tests bind the helper's signature and all observable widget settings. A frozen +`NumberInputSpec` validates finite positive step and finite ordered bounds +before widget construction; the three-parameter helper preserves field names, +values, units, ranges, increments, tooltips, and presentation order. + +Eight focused Python/PyQt tests and 25 focused React tests pass; the complete +React suite passes all 108 files / 672 tests. Pinned Ruff check/format, MyPy, +Bandit medium/high screening, TypeScript, zero-warning ESLint, +documentation/manifest governance, changed-production, test-assertion, +minimum-test, 500-LOC, and diff gates pass. Mandatory maxima are 400 module +lines, 42 function lines, and three parameters. No schema, digest, regional +physics, UI behavior, PR base, protected evidence, or release boundary changes. + +## 2026-08-11 PR #4339 current-parent ancestry candidate + +The clean `feat/4274-regional-surface-ui` worktree normally merged exact +published child `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980` with exact published +#4335 parent `9e01ccc3e891cc45907293751a192624195a77a5`, while preserving +#4339's `feat/4271-regional-wire-contract` base. Production UI, contract, +resolver, regional physics, and ground ancestry merged without conflict; only +SPEC, manifest, and handoffs were reconciled. Independent review, ordinary +publication, protected exact-head CI/approval, dependency integration, and +release remained open. + +## 2026-08-11 PR #4342 delta-MyPy follow-up + +Protected CI on exact PR #4342 head +`cffe349ac0a8054f1d168cb36684fd00bc5f8a49` identified one redundant `bool` +cast in the regional atomic-write adapter under the Linux delta-MyPy gate. The +cast is removed; the typed helper's direct Boolean return is preserved. This +changes no wire bytes, validation, file semantics, UI behavior, or physics. +Focused persistence tests and the CI-equivalent pinned MyPy command pass +locally; fresh protected CI/review and dependency ordering remain required. + +## 2026-08-11 regional request I/O protected publication + +Branch `feat/4274-regional-plan-io` is published normally as draft PR +[#4342](https://github.com/D-sorganization/Tools/pull/4342), targeting exact +PR #4339 branch `feat/4274-regional-surface-ui` at parent head +`cbb9c0a6bdc6a50f59f7a661139b9d53e1892980`. Its reviewed implementation +head is `d748e7a5ef3da5e6ce7737ff6829e0f14665fe97`; publication commits change +no runtime behavior. Protected CI, independent review, issue #4274, parent +ordering, integration, and release remain open. + +## 2026-08-11 bounded regional request read follow-up + +Independent review of local safe-number commit +`10c394f6b1fd2927e7f3b1f96cc097cae6bfd380` found that native request import +checked file size with `stat()` and then performed a separate unbounded text +read. A concurrently grown or replaced file could therefore allocate beyond +the 1 MiB wire cap before the strict parser rejected it. + +Native import now opens one binary handle, reads at most the wire cap plus one +sentinel byte, rejects overflow, strictly decodes UTF-8, and only then delegates +to the unchanged canonical v1 parser. Tests simulate content growth after the +metadata check and reject invalid UTF-8 explicitly. The complete regional and +atomic persistence set is 28 tests passing. This changes no schema, digest, +physics, browser behavior, or write semantics. Static and governance evidence +is recorded in this commit: Ruff, Ruff format, Black, focused MyPy, manifest, +module-size, documentation-governance, and diff checks pass. The child remains +local and unprotected. + +## 2026-08-11 regional request I/O safe-number follow-up + +Independent review of local commit `e39edf4b50b1fb9811b0032bec4758c7a08c9b74` +found two cross-runtime representation gaps. The PyQt6 precedence spin box +silently narrowed otherwise valid v1 integers above 1,000,000, and Python +accepted integer-valued wire numbers above JavaScript's exact safe range. + +The native editor now uses an exact decimal integer entry for precedence and +preserves every v1 value from zero through 9,007,199,254,740,991 without a +floating-point conversion. Shared Python canonical-number and ground-record +validation now reject magnitudes outside that same range, matching React while +retaining all finite fractional values inside it. PyQt6 floating-point editors +publish the same bounds. Regression coverage pins exact maximum-precedence +open/save round-trip and matched native/browser refusal of unsafe material +numbers. This changes no schema version, provenance algorithm, physics, or +browser filesystem limitation. Final local evidence is 132 shared ground tests, +21 regional editor/I/O tests, five atomic-workspace tests, 23 focused React +tests, the whole-shell tooltip sweep, and eight manifest tests passing. Ruff, +Ruff format, Black, focused MyPy, TypeScript, zero-warning ESLint, the 199-module +production build, module and changed-file size budgets, documentation +governance, and diff checks pass. The child remains local and unprotected. + +## 2026-08-10 PR #4339 stale-validation invalidation follow-up + +Rendered exact-head browser QA found that a validated one-overlay readback +remained visible after adding a second overlay. The broad PyQt6 suite also +found missing hover hints on the new controls. PyQt6 and React now clear both +canonical readback and prior validation state whenever any identity, interval, +material, or overlay-row draft value changes; PyQt6 exposes the explicit +"Changes not validated" pending state, and every PyQt6 interactive has a +specific engineering-context tooltip. RED-first regression tests cover the +dynamic-row path on both surfaces. Final local evidence is 870 Python/PyQt +tests and 672 React tests passing; Ruff, format, MyPy, TypeScript, zero-warning +ESLint, the 198-module production build, manifest/docs/file-size governance, +and diff checks are clean. The known polynomial-generator empty-legend warning +is unrelated. This changes no wire schema, provenance digest, physics, or +persistence boundary; fresh protected CI is still required before merge. + +> **Update this file with every PR and every push to main.** +> Last updated: 2026-08-11 + +## 2026-08-10 issue #4274 canonical regional request I/O local child + +Local branch `feat/4274-regional-plan-io` started directly from published PR +#4339 head `a9ace5052bcd54b78f79b62d5d9ac26debedb4b1`, then fast-forwarded +normally to corrected exact parent `cbb9c0a6bdc6a50f59f7a661139b9d53e1892980`. +The parent's stale-validation invalidation and tooltip follow-up are preserved. +This child has not been pushed, opened as a PR, reviewed, merged, or released. + +The matched Ground Surfaces editors now import and export the canonical +`ground-regional-material-plan-request/v1` document. PyQt6 uses native Open +and Save As dialogs plus a shared flush/fsync/atomic-replace UTF-8 writer; +cancel is a no-op, failed reads and writes preserve the last-known-good editor +or file, and the recent path advances only after success. React validates a +bounded browser File before committing state and downloads exact canonical +bytes while revoking its object URL. Browser filesystem limitations are +explicit, and workspace persistence remains separate. + +Import accepts only editor producer/provider v1 evidence, the fixed target +frame origin/downrange axis, and one to eight rows. It never relabels external +evidence. An unchanged import round-trips the exact request and provenance; +after any edit, validation binds a fresh draft digest. No measured calibration +is synthesized and neither path executes physics. + +RED-first coverage now includes exact-byte round-trip, native cancel and +atomic rollback, corruption, duplicate keys, oversize input, unsupported +producer/axis qualification, stale-provenance rebinding, transactional PyQt6 +population, browser rollback, URL cleanup, and pre-allocation size rejection. +Focused evidence is 25 Python/PyQt tests and 12 React tests passing. With +adjacent wire and manifest coverage, 44 Python and 16 React tests pass. +Focused MyPy, Ruff, TypeScript, zero-warning ESLint, the 199-module production +build, release-manifest validation, and module budgets are clean. + +Issue #4274 remains open. Measured calibration, workspace model-input +persistence, execution/playback, result interchange, visualization, changing +geometry, compiled regional physics, downstream parity, protected CI/review, +integration of this child into the protected stack, and release remain explicit +gaps. + ## 2026-08-10 issue #4274 matched regional surface editor local child Local branch `feat/4274-regional-surface-ui` started from published PR #4335 @@ -521,420 +511,6 @@ fixture bytes. There is no physics, numerical, schema, or API change. SPEC a finding-free local scan of the affected file, documentation governance, the `370`-line source-size check, and diff gates pass; fresh protected CI/review remain required after a normal guarded push. -## 2026-08-11 Flight-ground transfer receives current strict-ground parent - -Open draft PR `#4288` retains `feat/4269-flight-ground-transfer` over -`feat/4268-ground-contract`. Exact remote child -`df716ac740beb9d47dced66f867dc3dde1fa5367` is merged first and exact current -parent `584e4e53a7990053a346938c4e45538786887ec7` second by an ordinary -no-ff merge. All transfer production/tests/fixtures and Python, TypeScript, -Rust, PyO3, and WASM contracts remain intact. Only append-only handoff/SPEC -records conflict, and both dated histories are retained. Focused verification -passes 85 Python, 25 React, and 137 Rust tests; pinned Ruff 0.14.10, MyPy 1.13, -Bandit, TypeScript, exact-delta ESLint, the production web build, Rust format, -docs, strict manifest, diff, exact transfer-tree, and append-only preservation -gates pass. Publication, protected exact-head CI, review, approval, and release - remain open. - -## 2026-08-11 PR #4288 append-only history preservation repair - -This documentation-only follow-up to exact local candidate -`1eb4188ff1a87a3d8e9a55aeca68194ca04e0bb4` restores every omitted parent -handoff section and specification row and repairs the interleaved paragraph -below. Production code, tests, schemas, the campaign manifest, child-first -merge topology, and #4288's `feat/4268-ground-contract` base are unchanged. -Publication, protected exact-head CI, approval, dependency integration, and -release remain open. - -## 2026-08-11 PR #4288 current-ground-parent ancestry candidate - -The clean `feat/4269-flight-ground-transfer` reconciliation starts from exact -published child `afb1bdcfc6701caaf1f7bc3497a6a37dd9698c14` and normally merges -exact newly published #4285 parent -`e09ab96280cab363b36bd0e7db4a3cd064dc2527` second without changing #4288's -base. The child's bounded `flightIntegrator.ts` facade is preserved instead of -restoring the parent's superseded inline loop, while kinetics resolves to the -parent's split validated implementation. Seven child-owned Python files receive -pinned Ruff 0.14.10 normalization with no AST change; the preserved TypeScript -facade uses standard line endings. Bounce, skid, roll, terrain response, total -distance, UI integration, protected evidence, and release remain open. - -> Update this append-only handoff with every implementation commit and every -> push to `main`. Last updated: 2026-08-11. - -## 2026-08-11 Ground contract receives current capability carrier - -Open draft PR `#4285` retains branch `feat/4268-ground-contract` and base -`feat/4197-capability-observer`. Exact remote ground-contract child -`e09ab96280cab363b36bd0e7db4a3cd064dc2527` is merged first and exact current -capability-observer parent `d0b827667e61f0583e1dad0b3cbbca6819624d3c` -second by an ordinary no-ff merge. All strict flight-to-ground production, -tests, schemas, fixtures, dependencies, and fail-closed limitations are -preserved. Only append-only handoff/SPEC files conflict; their dated records -from both parents remain. Publication, protected exact-head CI, review, -approval, release, and downstream #4288 propagation remain open. Focused -verification passes 214 Python/PyQt tests, pinned Ruff 0.14.10 across 27 -PR-delta Python files, pinned MyPy 1.13 across 20 production files, and Bandit's -medium/high threshold. Docs, strict manifest, diff, exact ground-tree, and -both-parent append-only preservation gates pass. - -## 2026-08-11 Merged capability-observer carrier receives current wind workflow - -PR `#4283` is merged, while its former head branch -`feat/4197-capability-observer` remains the base of open draft PR `#4285`. -Exact remote/local carrier child -`b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is merged first and exact published -#4282 parent `3faf9e9493c9ba37168d9f65ab10cafeedc2a72f` second by a normal -no-ff merge. Since the carrier is already the first parent of #4282, the source -merge is conflict-free: the complete capability-observer implementation and -history remain present while the exact current wind workflow and manifest tree -are inherited. Only handoff/SPEC carrier records differ from #4282. All 86 -focused Python/PyQt capability, wind, and manifest tests and all 86 tests in 12 -focused React capability/wind suites pass. React type-check, zero-warning lint, -and the production build pass. Docs, manifest, and exact-parent diff gates pass; -changed-Python static gates are not applicable to the documentation-only exact -delta. This local audit does not authorize publication; review, -protected CI, and -later dependency propagation into #4285 remain open. - -## 2026-08-11 Wind workflow receives newly published scalar-adapter parent - -PR `#4282` keeps branch `feat/4199-wind-workflow` and base -`feat/4199-wind-scalar-adapter`. Exact published child -`b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` is merged first and exact current -parent `9321c1d2e091b8c7e5a4a83aa9ad726290e7fb5a` second. Implementation and test -paths merge automatically: responsive PyQt6/React wind execution, -progress/cancellation, controls, scatter, persistence/export, consolidated -capability workflow, and strict campaign release authority remain intact while -the parent contributes current scalar-adapter, variation, workspace, -launch-monitor/D-plane, split-kinetics, and Qt repairs. Only append-only -handoffs and SPEC conflict textually; both histories are preserved. All 94 -focused Python/PyQt wind, responsive-layout, navigation, playback, and manifest -tests pass, as do all 44 tests in eight focused React wind/responsive suites. -Docs governance and strict campaign-manifest generation/validation pass. -Pinned Ruff checks/formats all 57 changed Python files; pinned MyPy accepts 38 -production files; pinned Bandit finds no medium/high issues in 37 scanned source -files; the 500-LOC, changed-Python policy, test-contract/assertion, diff, React -type-check/lint, and production-build gates pass. Review, ordinary publication, -protected exact-head CI, unresolved threads, dependency order, and release -remain open. - -## 2026-08-11 Wind workflow receives current scalar-adapter parent - -PR `#4282` remains on `feat/4199-wind-workflow`, based on -`feat/4199-wind-scalar-adapter`. Exact remote child -`29e15d6ff631f7f30afcc745be783f2e716d7dcf` normally merges exact published -parent `a7dce5f89b483303938f518b74b4028a1c68ba81` second, preserving child-first -history and the existing base. The responsive PyQt6/React workflow and -consolidated capability stack inherit the parent's split kinetics facade, -Ground/Tee parity, and 252-line public/213-line private wind-adapter repair. - -The only source conflict is an obsolete formatting-only edit to the pre-split -kinetics monolith and resolves wholly to the validated parent facade. Both -append-only documentation histories remain present. Seven surviving -child-owned paths receive only repository-pinned Ruff formatting. The exact -skipped-import MyPy profile also replaces one now-unused cache-return ignore -with an explicit `KineticsSeries | None` cast; the cached object and runtime -behavior are unchanged. Protected exact-head CI, independent review, -unresolved-thread checks, publication, and dependency order remain release -gates. - -Local evidence is 74 focused Python/PyQt wind, kinetics, and Ground/Tee tests; -29 focused React tests; and 8 campaign-manifest tests. TypeScript, focused -zero-warning ESLint, Ruff check/format, pinned MyPy 1.13, Bandit's medium/high -threshold, strict wind module/signature/function budgets, manifest, -documentation, policy, SPEC, and diff gates pass. - -## 2026-08-11 Ground contract receives current workflow/base ancestry - -Draft PR `#4285` keeps branch `feat/4268-ground-contract` and base -`feat/4197-capability-observer`. Exact published child -`7a38b9838d743e051a6900620c4d6e754582aa89` is merged first with exact current -base/workflow head `b2baf6ef615b0d756a86ac4ca7eef2fc583210ee` second. The base contains -merged #4283 head `9bbb98e16e435a0d4c74153b909f2ebfefbbce7a`; no rebase, retarget, -force-push, parent rewrite, or publication is used. - -The child's strict UI-neutral `flight-to-ground/v1` schemas, canonical fixture, -migrations, legacy-result adapter, explicit dependency, enum compatibility, -and fail-closed validation remain authoritative. The parent contributes the -current responsive wind/capability ancestry, Ground/Tee parity, and split -kinetics modules. Its facade wholly resolves the sole formatting-only source -conflict; both append-only documentation histories remain present. - -The ground branch's contract-checked scalar extraction repair remains intact. -Because it makes the plotting catalog part of the effective delta, the former -459-line registry now delegates immutable ordered rows to focused private -scalar/series modules. The public catalog facade is 61 lines; every changed -production module is at most 400 lines, every function at most 50 lines, and -every signature at most four non-receiver parameters. Stable keys, display -order, units, categories, extractor behavior, and public objects do not change. - -Complete local regression evidence is 1,539 Rate/shared-swing Python tests -passed with one explicit optional Rust-wheel skip; 106 React files / 648 tests, -TypeScript, zero-warning ESLint, and the 188-module Vite build passed; and all -12 `swing-core` Rust tests passed. The focused ground, Ground/Tee parity, -kinetics, wind adapter, compatibility, and manifest set passes 146 tests; 57 -additional plotting/catalog/variation/kinetics regressions pin the structural -split. Pinned Ruff 0.14.10, MyPy 1.13, Bandit 1.7.7, manifest, documentation, -SPEC, policy, diff, and structural gates are required again on the committed -candidate before publication. - -This is an unpublished local candidate. It does not claim bounce, skid, roll, -terrain, total distance, ground UI, Rust/WASM ground delivery, protected CI, -approval, or release. Independent review and fresh protected checks are -required before normal publication and later #4288 propagation. - -## 2026-08-10 Repaired scalar-adapter propagation into wind workflow - -Draft PR `#4282` remains on `feat/4199-wind-workflow`, based on -`feat/4199-wind-scalar-adapter`. It now normally incorporates repaired parent -head `d6fb04e07c2a625412e9208b07103acdc42c621b` after that head's quality gate -passed. The merge had no wind-workflow production/test conflict and used no -rebase, retarget, force-push, or history rewrite. Twenty-five focused tests and -the documentation, size, and whitespace gates pass locally; protected CI, -review, and later-stack propagation remain outstanding. - -## 2026-08-10 Exact-head manifest typing repair - -PR #4282 exact head `aa6eeffb0395f7ed7954f2315b1c625cada552d8` -failed hosted quality-gate run `31395741841` only at pinned-mypy -`scripts/rate_campaign_manifest.py:335:5 [no-any-return]`. The CI profile skips -import analysis, so the Pydantic validator result becomes `Any`; an explicit -local `CampaignManifest` annotation now retains the validated return contract -without changing parsing, validation, or error behavior. Ruff and format had -already passed on the failed head. Publish this repair normally, then propagate -its new exact head into #4285; do not retry the obsolete run. - -## 2026-08-10 Wind workflow receives exact scalar-adapter parent - -PR `#4282` keeps branch `feat/4199-wind-workflow`, base -`feat/4199-wind-scalar-adapter`, and original child first parent -`5f77af4add23547a21cc3fabce98ae9ad4260427`. Exact parent -`4a793c4c3f19aad43a3c215800b266be487ace49` merges normally second. The -responsive PyQt6/React wind strategy workflow, consolidated capability stack, -and campaign release authority remain additive with the parent's complete -variation, workspace, compatibility, and strict scalar-adapter history. - -The parent's extracted navigation-state tuple is the single authority and now -includes the child-owned `capability_optimization` ID. This preserves safe -legacy visibility migration and prevents a persisted pre-capability workspace -from hiding the new tab. Runtime-only UI and capability invariants now raise -explicit errors under optimized Python, and the safe fixed-argument builder -subprocess is annotated for Bandit. The skipped-import manifest return repair -is recorded above. SPEC 1.14.15 is the current exact-head repair entry. -Verification passes 73 focused Python tests, the complete 1,657-test -Rate/shared-swing/golf-club matrix with two explicit optional build123d skips, -all 643 React tests across 105 files plus type-check/lint/build, 12 Rust tests, -31 real-CPython-3.10 compatibility tests, and 43 post-review invariant/GUI/ -manifest tests. Ruff/format, pinned MyPy 1.13 across 37 changed production -files, Bandit, exact-parent size, manifest, docs, minimum-test, assertions, -CI-policy secrets, compilation, and diff gates pass. Independent re-review -found no actionable findings after 94 Python workflow/navigation tests, 20 -manifest/GUI tests, 61 React workflow tests, and independent static checks. -Protected CI/review and dependency-ordered propagation remain release gates. - -## Current continuation - -The active local continuation is integrated directly on the existing PR #4282 -carrier `feat/4199-wind-workflow`, starting from original published head -`5f77af4add23547a21cc3fabce98ae9ad4260427` and normally incorporating exact -published #4281 parent `4a793c4c3f19aad43a3c215800b266be487ace49`. -The base remains `feat/4199-wind-scalar-adapter`; no branch was rebased, -retargeted, force-pushed, or published by this continuation. It adds strict -cross-runtime capability parsing, reliable signed decimal entry, complete -ranked diagnostics and result exports, quantitative React scatter annotations, -package-safe static-web release entrypoints, and the strict -`rate-of-closure-campaign/v1` release authority. It also carries the corrected -parent's Python 3.10 compatibility, variation-export, scalar-ensemble, and -wind-adapter history. Normal publication does not establish a protected -release; CI, review, and downstream evidence remain required. - -The direct web launcher dynamically loads the root bootstrap module without a -launcher-local `sys.path` mutation; its subprocess delegation test and the -changed-production-Python policy guard cover this release entrypoint. - -Use these authorities together: - -- `docs/release/rate_of_closure_campaign.v1.json` — machine state; -- `scripts/rate_campaign_manifest.py` — validation and generated JSON Schema; -- `docs/release/RATE_OF_CLOSURE_CAMPAIGN_MANIFEST.md` — update procedure; -- `docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md` — detailed history; -- `docs/specs/*.md` — scientific and interoperability contracts. - -The manifest is intentionally normalized: programs reference shared carrier -and test-evidence records. It fails on missing primary issues, undeclared -references, duplicate IDs, malformed SHAs, absent repository evidence, -placeholders, and contradictory release claims. - -## Carrier state - -The capability stack was collapsed top-down on 2026-08-09: - -1. #4294 Shot Optimizer UI merged into `feat/4197-capability-flight-evaluator`; -2. #4289 evaluator merged into `feat/4197-capability-observer`; -3. #4283 observer merged into `feat/4199-wind-workflow`. - -These were feature-parent merges, not protected releases. Current carrier -#4282 descends from #4281 → #4280 → #4279 → #4203 → #4202 → wedge and -variation parents. Exact published #4281 parent -`4a793c4c3f19aad43a3c215800b266be487ace49` is incorporated locally. Preserve -that dependency order and use normal merges only. - -Outer platform PR #4119 targets `main` and still needs reconciliation. PR #4133 -impact-interval dynamics merged into a historical feature parent after that -parent had already propagated, so its source and tests must be explicitly -reconciled before #4130 can close. - -## Implemented on the feature stack - -- PyQt6 and React variation workspaces: selectable input/contact/impact/shot - scatter, matrix, landing dispersion, every-trial 3D swing arcs, quiet zones, - linked selection, bounded raw rows, and lossless exports. -- Matched toolstrip/workspace controls, module visibility, independent plots, - legend placement, zoom/autofit, replay, loop, and granular playback rate. -- Launch-monitor convention, D-plane, spatial target, inverse flight, wind, - interactive flight playback, and capability-optimization contracts/workflows. -- Wedge kinematics, clearance, turf proxy, impact visualization, and - forgiveness-analysis slices. - -## Current limitations - -- No complete campaign program has a qualified `main` release SHA. -- Capability v1 is still-air carry to first ground crossing; it excludes wind, - bounce, roll, and total distance in that evaluator. -- Ground contracts and flight transfer are open carriers; qualified bounce, - skid, roll, profiles, total-distance optimization, UI, and Rust/WASM parity - remain. -- UpstreamDrift React has no native Rate route, and the Tools source pin and - resolver behavior are not a qualified immutable parity boundary. -- Camera tracking/snap views (#4284), complete persistence adapters, high-DPI, - keyboard, reduced-motion, and visual-regression matrices remain open. -- Local/rendered evidence is not protected CI or installed-package evidence. - -## Most recent evidence - -- Corrected-parent propagation: 62 focused wind/scalar/variation and - compatibility tests pass on Python 3.11 and real CPython 3.10.20; 8 React - files / 35 tests, TypeScript, and focused zero-warning ESLint pass. The real - 3.10 run found and now guards #4282's child-owned capability-observation - `StrEnum` boundary. Ruff check/format passes 15 focused files, pinned mypy - 1.13 passes 10 production modules, and nine campaign manifest/parity - contracts pass. -- Composed local continuation: 828 Rate Python/PyQt tests and 104 React files / - 642 tests passed; TypeScript, zero-warning ESLint, and the 188-module Vite - production build passed. The manifest, schema JSON, Ruff, targeted mypy, and - nine manifest/parity contracts pass on implementation head `2c1a77baa`. - Hosted CI has not run on this composition. -- Hosted quality-gate run `31340032608` subsequently found mypy 1.13 - `no-any-return` findings at the Pydantic loader and Qt elapsed-timer adapter - under `--follow-imports=skip`; both boundaries now narrow their return values - explicitly. The exact Python 3.12/mypy 1.13 delta is clean across 54 files; - Ruff, 62 focused regression tests, and eight campaign-manifest tests also - pass locally. -- Consolidated capability head `c1827bbdc`: 1,426 Python Rate/shared-swing - tests and 624 React tests passed locally. -- Variation continuation `d71b0ea01`: 890 Python/PyQt/shared-swing tests and - 545 React tests passed locally, with one optional Rust skip. -- Toolstrip head `c36ca36e9`: the same 890/545 local suite totals passed. -- Hosted #4282 head `3186a265b1`: `swing_core` built, but cached plugin loading - failed before parity collection; this is failed evidence, not a model pass. -- CI-isolation head `18fe89201`: focused workflow regression passes locally; - the hosted non-skipped parity run is still required. - -## Validation - -```powershell -python scripts/rate_campaign_manifest.py -python -m pytest tests/rate_of_closure/test_campaign_release_manifest.py -q -$env:QT_QPA_PLATFORM='offscreen' -$env:PYTHONPATH=(Resolve-Path 'src').Path -python -m pytest tests/rate_of_closure src/shared/python/swing_sim -q -cd src/rate_of_closure/web -npm test -- --run -npm run type-check -npm run lint -npm run build -``` - -## 2026-08-11 Wind workflow receives current scalar-adapter parent - -PR `#4282` remains on `feat/4199-wind-workflow`, based on -`feat/4199-wind-scalar-adapter`. Exact remote child -`29e15d6ff631f7f30afcc745be783f2e716d7dcf` normally merges exact published -parent `a7dce5f89b483303938f518b74b4028a1c68ba81` second, preserving child-first -history and the existing base. The responsive PyQt6/React workflow and -consolidated capability stack inherit the parent's split kinetics facade, -Ground/Tee parity, and 252-line public/213-line private wind-adapter repair. - -The only source conflict is an obsolete formatting-only edit to the pre-split -kinetics monolith and resolves wholly to the validated parent facade. Both -append-only documentation histories remain present. Seven surviving -child-owned paths receive only repository-pinned Ruff formatting. The exact -skipped-import MyPy profile also replaces one now-unused cache-return ignore -with an explicit `KineticsSeries | None` cast; the cached object and runtime -behavior are unchanged. Protected exact-head CI, independent review, -unresolved-thread checks, publication, and dependency order remain release -gates. - -Local evidence is 74 focused Python/PyQt wind, kinetics, and Ground/Tee tests; -29 focused React tests; and 8 campaign-manifest tests. TypeScript, focused -zero-warning ESLint, Ruff check/format, pinned MyPy 1.13, Bandit's medium/high -threshold, strict wind module/signature/function budgets, manifest, -documentation, policy, SPEC, and diff gates pass. - -## 2026-08-10 Final repaired workflow ancestry in strict ground contract - -Draft PR `#4285` remains on `feat/4268-ground-contract`, based on -`feat/4197-capability-observer`. Its original head -`e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` normally incorporates exact -quality-green #4282 head `1e82f15026786ea0b08f78f4c001590ddce9ff39` -second. Ground-contract source and tests had no conflict. Protected CI and -review must pass before the new exact head propagates normally into #4288. - -## 2026-08-10 Final repaired strict-contract ancestry in flight transfer - -Draft PR `#4288` remains on `feat/4269-flight-ground-transfer`, based on -`feat/4268-ground-contract`. Its original head -`108a841b1378c992defd3c7b7ee263d41a6c8b24` normally incorporates exact -quality-green #4285 head `a93edb4bfd6a8dc9334122cd2ae660983d5bf424` -second. Transfer source and tests had no conflict. Fresh protected CI and review -must pass before any release claim. - -## PR #4288 exact repaired-ground propagation - -Original child `247215422a6d4b677552955b4923bc609a553259` normally incorporates -exact repaired #4285 parent `e5bcbd1096d3be1f621a805c9d9f3fd321e375a5` -second in the merge on `feat/4269-flight-ground-transfer`. PR #4288 -keeps base `feat/4268-ground-contract`; neither branch was rebased, retargeted, -rewritten, or force-pushed. The child retains its qualified cross-runtime -terminal-state/contact transfer and inherits the corrected UTC parser, -canonical `swing_sim` import identity, hosted-mypy manifest repair, and the -complete variation, wind, capability, and campaign ancestry. - -This is ancestry propagation, not bounce, skid, roll, terrain response, total -distance, or UI delivery. Protected CI, independent review, and normal stack -collapse remain open. - -Exact composed-tree verification is 1,080 Python tests passed with six explicit -optional installed-`tools_core` wheel skips, 107 React files / 662 tests, -26 direct Rust transfer/wire tests, TypeScript, zero-warning ESLint, and the -189-module production build. Ruff check/format passes all 28 changed Python -files; pinned mypy 1.13 passes all 21 changed production files. Campaign -manifest, documentation governance, and diff checks pass. The missing local -wheel remains an explicit installed-package release boundary and is not -misreported as accelerated parity evidence. - -## 2026-08-10 Exact repaired #4282 propagation into PR #4285 - -Original child `788aa547651a3685a363ea401824a5d81477bafb` -normally incorporates exact repaired #4282 parent -`686016196a2f895058b8a566dff103a0fd32cd10` second on -`feat/4268-ground-contract`. PR #4285 keeps base -`feat/4197-capability-observer`; neither branch was rebased, retargeted, -rewritten, or force-pushed. The parent contains merged capability PR #4283, -its exact observer head, and the exact-hosted-mypy manifest repair. The child -retains its strict flight-to-ground contract while acquiring the latest -deterministic variation, workspace, wind, capability, and release ancestry. ## 2026-08-09 PR #4304 corrected implementation evidence @@ -1027,45 +603,6 @@ regions, changing normals, deformation/grass response, torsional spin damping, roll-to-skid, PyQt6/React UI, compiled runtimes, UpstreamDrift consumers, protected review, parent integration, and main release remain open. -## 2026-08-10 Exact repaired #4282 propagation into PR #4285 (continued) - -The inherited ground descendant passes 1,703 Python tests with two optional `build123d` -skips, 643 React tests across 105 files plus type-check/lint/build, 12 Rust -tests, and 77 real-CPython-3.10 ground and compatibility tests. Ruff/format pass -78 changed Python files; pinned mypy and Bandit pass 52 changed production -files. Manifest, docs, minimum-test, assertions, 500-LOC, changed-file secrets, -Python 3.10 compilation, and diff checks are clean. - -The repaired parent explicitly types the Pydantic manifest return. The composed -tree also normalizes contract-checked scalar plot values with `float`, replaces -the command-state `assert` with a runtime invariant error, and documents the -alias finder's intentional optional-probe `B112` security boundary. Protected -current-head CI and required review remain release gates. The exact repaired -ground head is now incorporated into #4288; normal propagation of the reviewed -#4288 head into #4298 is the next ancestry gate. - -## 2026-08-09 Ground parent reconciled with corrected wind carrier - -Draft PR #4285 keeps base `feat/4197-capability-observer` and normally -incorporates exact corrected wind carrier -`bb101cedd555d07d493aae998b46050c68660cdd`. No branch was rebased, -retargeted, force-pushed, or published. The strict ground contract remains -UI-neutral and fail closed; the merge adds no bounce, skid, roll, terrain -profile, total distance, or presentation claim. - -This branch is now the carrier-reconciled ground parent. PR #4288 must merge -the resulting exact #4285 head normally before its transfer logic is retested -or published. That descendant merge will carry both the ground contract and -the explicit observer-to-wind ancestry reconciliation without changing either -PR base. - -Focused evidence is 89 ground/compatibility/wind tests on Python 3.11 and 89 -on real CPython 3.10.20. Ruff check/format passes 34 focused files; pinned mypy -1.13 passes 23 production modules; the inherited campaign manifest validates -and its nine manifest/parity tests pass. Ground production modules remain -within the 400-line/50-line structural budgets and contain no placeholder -markers. - ## 2026-08-09 PR #4302 pinned-MyPy current-head correction Hosted quality-gate run `31350134551` exposed four deterministic MyPy 1.13 @@ -1879,1190 +1416,3 @@ Publish this as a normal follow-up commit on `feat/4270-ground-impact-bounce`, with the three handoffs in the same commit. Keep #4270 and #4267 open; do not bypass protected CI or propagate into child branches until the parent push is verified. -## Inherited current-parent handoff history - - Python/TypeScript SHA-256 parity digests as high-entropy strings. These are - expected deterministic test outputs, not secrets. Use only exact inline - `pragma: allowlist secret` annotations on the four digest constants; preserve - the repository baseline and scanner scope. Commit the annotations and this - handoff together on the parent capability-observer branch, then re-run the - protected stack without force-pushing or bypassing the gate. Parent commit - `49612946138b1021f80c9f8d2a4d06f1610825db` is now propagated into this child - by a normal merge commit. -## Inherited #4281 handoff history - -## 2026-08-11 Wind scalar adapter receives current variation parent - -PR `#4281` keeps branch `feat/4199-wind-scalar-adapter` and base -`feat/4144-variation-export-continuation`. Exact published child -`a7dce5f89b483303938f518b74b4028a1c68ba81` is merged first and exact current -parent `e6c7460a01082631565fb9ed48aa32538bd7772c` second. Implementation and test -paths merge automatically: Python/TypeScript scalar-ensemble provenance, -availability, deterministic-scenario, wind-strategy adapter, and strict -module-budget behavior remain intact while the parent contributes current -variation visualization/export, workspace, launch-monitor/D-plane ancestry, -split kinetics, and behavior-preserving Qt return narrowing. Only append-only -handoffs and SPEC conflict textually; both histories are preserved. All 77 -focused wind/variation Python tests and all 20 tests in the five focused React -wind/variation suites pass before the merge commit. Pinned Ruff checks/formats -all five changed Python files; pinned MyPy and Bandit accept all three production -files; both 500- and strict 400-LOC, docs, changed-Python policy, -test-contract/assertion, diff, React type-check/lint, and production-build gates -pass. The later campaign-manifest artifact/checker/test exist on neither side of -this pre-manifest stack and are not applicable. Review, ordinary publication, -protected exact-head CI, unresolved threads, dependency order, and release -remain open. - -## 2026-08-11 Wind scalar-adapter module-budget repair - -The 403-line `variation/wind_strategy_plot_adapter.py` exceeded the mandatory -400-line ceiling. Request/analysis validation now lives in the private -`variation/_wind_strategy_plot_validation.py` collaborator, leaving a 252-line -public adapter and a 213-line validator. A frozen, slotted scenario-expectation -object keeps the private scenario validator at two cohesive parameters; every -production function is at or below four parameters and 50 lines. The public -imports, dataset schema, -variable/stage/category/cohort order, composite row identities, row values, -typed availability, attributes, validation messages, and no-flight-rerun -boundary are unchanged. - -The existing 14-test Python adapter suite and 16 focused React wind tests cover -the behavior-preserving extraction; Ruff/format, pinned MyPy 1.13, Bandit, and -the explicit strict line budget pass locally. Protected exact-head CI, -independent review, unresolved-thread checks, ordinary publication, and stack -order remain release gates. - -## 2026-08-11 Wind scalar adapter receives reviewed variation parent - -PR `#4281` stays on `feat/4199-wind-scalar-adapter`, based on -`feat/4144-variation-export-continuation`. Exact remote child -`247046d55afcad3e6cd4f8029f854856c427f59c` normally merges exact reviewed -parent `3337945699966b63cb5cd8e52d7c3b194315e911` in child-first order, -preserving both histories and every commit. Python/TypeScript scalar-ensemble -provenance, typed availability, deterministic-scenario rules, and wind-strategy -plot-adapter behavior remain unchanged. The parent supplies selected-scatter -export, linked variation views, the kinetics split, Ground/Tee parity, -workspace/toolstrip behavior, and protected Ruff normalization. The only -feature-code conflict referenced obsolete monolithic kinetics and is resolved -to the validated parent `pendulum.sample(...)` facade. This local merge still -requires independent review, fresh exact-head protected CI, unresolved-thread -checks, dependency order, and ordinary publication. -## 2026-08-11 Variation export receives current workspace parent - -PR `#4280` keeps branch `feat/4144-variation-export-continuation` and base -`feat/4218-toolstrip-workspace`. Exact published child -`3337945699966b63cb5cd8e52d7c3b194315e911` is merged first and exact current -parent `efbca84095b617b4018732f7802c2da3f0525387` second. Implementation and test -paths merge automatically: selected-scatter CSV parity, typed unavailable -outcomes, bounded accessible tables, linked selection, and all-trial arc -analysis remain intact while the parent contributes current workspace, -launch-monitor/D-plane ancestry, split kinetics, and behavior-preserving Qt -return narrowing. Only append-only handoffs and SPEC conflict textually; both -histories are preserved. All 56 focused Python variation tests and all 10 tests -in the three focused React variation suites pass before the merge commit. -Pinned Ruff checks/formats all five changed Python files; pinned MyPy and Bandit -accept all four production files; docs, 500-LOC, changed-Python policy, -test-contract/assertion, diff, React type-check/lint, and production-build gates -pass. The later campaign-manifest artifact/checker/test exist on neither side of -this pre-manifest stack and are not applicable. Review, ordinary publication, -protected exact-head CI, unresolved threads, dependency order, and release -remain open. -## 2026-08-11 Variation export receives reviewed workspace parent - -PR `#4280` stays on `feat/4144-variation-export-continuation`, based on -`feat/4218-toolstrip-workspace`. Exact remote child -`668ba96746f79f7a12e8092161bd610054197f58` normally merges exact reviewed -parent `ccd0e026c580c93038fdf5c59d5d452a85ba27a0` in child-first order, -preserving both histories and every commit. Selected-scatter CSV parity, typed -unavailable outcomes, bounded accessible tables, linked selection, and -all-trial arc analysis remain unchanged. The parent supplies its validated -kinetics split, Ground/Tee parity contracts, protected Ruff normalization, and -workspace/toolstrip implementation. The only feature-code conflict referenced -obsolete monolithic kinetics source and is resolved to the current -`pendulum.sample(...)` façade. Seven duplicate child automation edits do not -match protected Ruff 0.14.10 output and are normalized to the exact reviewed -parent blobs while their commit remains in history. This local reconciliation -still requires independent review, exact-head protected CI, unresolved-thread -checks, dependency order, and ordinary publication. -## 2026-08-11 Workspace child receives current #4203 parent - -PR `#4279` keeps branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. Exact published child -`ccd0e026c580c93038fdf5c59d5d452a85ba27a0` is merged first and exact current -parent `7abce9ad767fe8311da66a1e5998b892ea3ca9de` second. Implementation and -test paths merge automatically: the child workspace/toolstrip, visibility, -navigation, playback, and independent-plot behavior remain intact while the -parent contributes current launch-monitor/D-plane ancestry, split kinetics, -and behavior-preserving Qt return narrowing. Only append-only handoffs and -SPEC conflict textually; both histories are preserved. All 142 exact -PR-delta Python tests and all 32 tests in the eight changed React suites pass -before the merge commit. Pinned Ruff checks/formats all 27 changed Python -files; pinned MyPy and Bandit accept all 18 production files; docs, 500-LOC, -changed-Python policy, test-contract/assertion, diff, React type-check/lint, and -production-build gates pass. The later campaign-manifest artifact/checker/test -exist on neither side of this pre-manifest stack and are not applicable. -Review, ordinary publication, protected exact-head CI, unresolved threads, -dependency order, -and release remain open. -## 2026-08-11 Remote workspace history reconciled locally - -PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. Exact local head -`0b22c401a26c31441a599d8d9b39de123706e7ea` ordinarily merges divergent -remote head `61fe2d556a5413e525d958612ccfd57e65b8d5a2`, preserving every commit in -both histories. The remote automation commit is formatting-only: 15 of 23 -paths were already identical through the parent, while its seven unique edits -are normalized back to protected Ruff 0.14.10 output. Its one content conflict -referenced the obsolete pre-split kinetics implementation. The reconciled tree -keeps the current `pendulum.sample(...)` façade path and therefore preserves -the kinetics split, physics, frames, units, imports, schemas, and UI behavior. Workspace/toolstrip, -visibility, navigation, playback, and independent plot behavior are unchanged. -Publication remains blocked on independent review, fresh exact-head protected -CI, unresolved-thread checks, and dependency order. - -## 2026-08-11 Workspace child receives hosted MyPy repair - -PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. Exact child -`7806a16f58e1c6999d32f0127a187fbb21f839a1` normally merges exact published -parent `3796b49e40b677fbac4e05739f8be49f905df2cb`. No feature-code conflict -exists: the inherited production delta is four static `numpy.ndarray` casts, -while workspace/toolstrip behavior and runtime arrays, physics, frames, units, -imports, and UI behavior remain unchanged. This local merge does not satisfy -fresh protected CI, required review, unresolved-thread, dependency, or release -gates. - -## 2026-08-11 workspace child receives latest repaired parent - -PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. A normal merge incorporates exact parent -`0216a547aa79727091a2939b96e779e8ddbd7304` into exact child -`61b7f48b5aeb7d57246b4963da3df086e79cbe15`. There are no feature-code -conflicts: workspace/toolstrip, visibility, navigation, playback, and plot -behavior remain unchanged while the parent kinetics façade/dynamics/series -split and pinned formatting are inherited. This local merge does not satisfy -fresh protected CI, required review, unresolved-thread, dependency, or release -gates. - -## 2026-08-11 Append-only SPEC preservation repair - -Independent review found that the local #4203 reconciliation omitted four -exact D-plane parent SPEC rows dated 2026-08-10 (versions 1.13.11, 1.13.9, -1.13.7, and 1.13.6). They are restored verbatim in a documentation-only -follow-up. Production behavior, tests, ordered parents, base, and local quality -evidence are unchanged; re-review, normal publication, and protected CI remain -open. - -## 2026-08-11 Current D-plane parent reconciliation - -PR #4203's published child `217e36dc93d30f79826847f958fbcd10805e58ed` -is being normally merged with exact current D-plane base -`f3363aa88868f6a5c7e9ccfc682a9eca014e86c1`. The base and source branch stay -unchanged. The only conflict is the parent's formatting of an older monolithic -kinetics expression: the split facade keeps its typed pendulum accessor and -inherits the parent's geometry explanation. No launch-monitor, D-plane, or -kinetics behavior is intentionally changed. Four Qt-stub `Any` returns exposed -by the exact MyPy 1.13 delta are also narrowed to their declared `bool`/`str` -contracts without changing values. Focused/full validation, independent -review, normal publication, and protected CI remain open. - -## 2026-08-11 Exact-head format completion - -Protected CI on #4203 head `7d69a545ae555679f0318940e67c1786626d6794` -failed only Ruff formatting. The pinned 0.14.10 reproduction found eleven -noncompliant changed Python files: four inherited files plus seven altered by -the automated pre-commit repair. The pending repair intentionally changes no -launch-monitor, kinetics, simulation, or UI behavior and requires independent -review plus fresh protected CI before integration. - -## 2026-08-11 Hosted MyPy NumPy-return repair - -CI Standard run `31477542889`, job `93734652129`, found four -`no-any-return` errors after the kinetics façade extraction at exact PR #4203 -head `0216a547aa79727091a2939b96e779e8ddbd7304`. The NumPy stubs widen -`linalg.norm`, `concatenate`, and matrix projection results to `Any` even -though the runtime operations return arrays. The private series/dynamics -modules and public façade now use explicit `cast(np.ndarray, ...)` boundaries. -These casts are static only: array identity, values, dtype, shape, physics, -frames, units, imports, and UI behavior are unchanged. Verification must cover -the complete PR changed-source MyPy set and both focused and full Rate tests. -Current local evidence is 102 changed-source MyPy files, 28 focused tests, and -all 701 Rate tests passing; complete-delta Ruff/format and Bandit are also -green. - -## 2026-08-11 Kinetics façade extraction - -The strict current-head delta reproduces a protected size failure that the -PR-base comparison hides: `kinetics.py` is changed versus `HEAD~1` and is 646 -LOC, above the ungrandfathered 500-LOC maximum. The public module is now a -222-LOC run adapter/facade; its pure double-pendulum dynamics are in the -205-LOC `_kinetics_dynamics.py`, and the immutable `KineticsSeries`/DbC -contract is in the 131-LOC `_kinetics_series.py`. Existing public imports and -the `_reaction_forces` seam are the same implementation objects. A RED-first -identity test plus the existing physics, energy, force, parity-fixture, -presentation, and PyQt tests protect behavior. No physics, frame, SI-unit, -schema, UI, or stack-order change is intended; the commit remains local only. -Focused kinetics/presentation/PyQt verification is 28 passing tests; the -complete Rate-of-Closure Python regression suite is 701 passing tests. - -## 2026-08-11 #4203 pinned-Ruff formatting repair - -No material handoff change: current-head CI Standard run `31468208320`, job -`93705508050`, identified eight files that differ from repository-pinned Ruff -0.14.10 output. This commit changes formatting only; Rate physics, behavior, -frames, persistence schemas, PyQt/React contracts, stack bases, and dependency -order remain unchanged. Fresh protected CI and review are still required. - -## 2026-08-10 Ground/Tee parity child receives repaired parent - -Ready PR `#4325` keeps branch `feat/4143-tee-parity-fixture` and base -`feat/4181-launch-monitor-registry`. It normally merges exact repaired parent -head `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` without any production/test -code conflict or history rewrite. Shared parity and rendered-evidence -contracts remain intact; fresh protected CI, review, dependency order, and -#4143 release remain open. - -## 2026-08-10 #4143 Python/React Golden Ball-Setup Parity - -The isolated `feat/4143-tee-parity-fixture` child begins at exact draft PR -#4203 head `31cbc007d4c85b5479b7cd0fb0969124eab2af67`. One versioned JSON fixture now -drives both Python and React ball-support tests with explicit SI units and the -ground-plane-to-ball-bottom height reference. The shared cases cover Driver -and non-Driver defaults, user overrides, Ground zero effective height, -derived ball-center geometry and serialization, negative/NaN/infinite height -rejection, and backward-compatible migration of a legacy run without -`ball_setup`. - -Evidence is 18 passing Python tee/parity tests and 24 passing React -tee/persistence/parity tests, plus green TypeScript, ESLint, Vite production -build, Ruff check, and Ruff format. Production model and UI code are unchanged. -Recorded visual evidence now adds 1600 x 1200 Playwright Driver/Tee and -rerun-Ground captures plus 1400 x 900 hidden-window PyQt captures. The browser -run asserts control state, diagram geometry, and zero console/page errors; the -desktop run asserts canonical center/artist state, nonblank output, and -different Ground/Tee digests without pixel absolutes. The exact artifacts and -versioned manifests are in -`C:\Users\diete\AppData\Local\Temp\rate-4143-visual-evidence-8050eeba`. -Do not close #4143: protected current-head CI/review and release to `main` -remain. This exact parent predates the strict campaign manifest on a divergent -branch, so no downstream manifest was copied into this bounded child. - -## 2026-08-10 Wind scalar child receives second repaired parent - -PR `#4281` retains branch `feat/4199-wind-scalar-adapter` and base -`feat/4144-variation-export-continuation`. It normally merges exact repaired -parent `b90e5021a59e2081415b51ef29fbed06377bc201` without scalar-adapter code -conflict or history rewrite. Fresh child CI, review, and dependency order -remain required. -Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs, -changed-file-size, and whitespace gates. - -## 2026-08-10 Variation export child receives exact workspace parent - -PR `#4280` retains branch `feat/4144-variation-export-continuation`, base -`feat/4218-toolstrip-workspace`, and original child first parent -`f90836e342efc8be624739802375af2876d11e5f`. Exact parent -`6717e9e09d507dbc24bedb36177f1cdf0b4fd90b` merges normally as the second -parent. All variation visualization/export source merged without conflict: -selected scatter CSV, typed unavailable rows, accessible bounded raw tables, -linked trials, focused PyQt widgets, and React parity remain additive with the -parent workspace/toolstrip/playback/plot/navigation repairs. SPEC 1.14.12 is -the unique combined child entry. Staged review exposed a stale linked-trial -selection when a smaller rerun replaced the active result. Corrected PyQt -views clear result-local selection before repopulating and validate all public -setter indices; React clears on result identity change and shares only bounded -selections with linked views. Thirty-seven focused variation tests and the -complete Rate/shared-swing/golf-club matrix pass 1,528 tests with two explicit -optional build123d skips; all 546 React tests across 90 files pass; -TypeScript, ESLint, and production build are green. Exact-parent -Ruff/Ruff-format/Black, pinned MyPy 1.13 across four Python production modules, -Bandit, file-size, docs, minimum-test, assertion, detect-secrets, diff, real -CPython 3.10.20 compilation, and 30 compatibility regressions pass. There is -no Rust delta from the exact parent. Independent staged re-review found no -actionable findings, including the first replacement-render React boundary. -Protected CI/review remain release gates after an ordinary guarded push. - -## 2026-08-10 Variation child receives second repaired workspace parent - -PR `#4280` retains branch `feat/4144-variation-export-continuation` and base -`feat/4218-toolstrip-workspace`. It normally merges exact repaired parent head -`61b7f48b5aeb7d57246b4963da3df086e79cbe15` without feature-code conflict or -history rewrite. Variation/export behavior remains unchanged; fresh child CI, -review, and dependency order remain required. -Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs, -changed-file-size, and whitespace gates. - -## 2026-08-10 Wind scalar child receives exact variation parent - -PR `#4281` keeps branch `feat/4199-wind-scalar-adapter`, base -`feat/4144-variation-export-continuation`, and original child first parent -`cf52529b1e68479321bb93b1be3d59c77f782008`. Exact parent -`8bcc49fc4e16e5e43be0b7f0f03c3017d5b79d0c` merges normally second. The -child's scalar-ensemble wire contract, provenance-preserving wind rows, -availability accounting, and plot adapter remain additive with the parent's -variation visualization/export and result-local selection repairs. Python and -TypeScript reject wind scenarios unless their per-trial provenance is exact, -shear/turbulence are zero, seed is zero, and gusts are empty. SPEC 1.14.13 is -the unique combined child entry. Twenty-seven focused Python tests, the -1,549-test complete Rate/shared-swing/golf-club matrix with two explicit -optional build123d skips, and all 556 React tests across 92 files pass. -TypeScript, ESLint, production build, Ruff/format, pinned MyPy, Bandit, size, -docs, minimum-test, assertions, detect-secrets, diff, and CPython 3.10 compile -gates pass. Independent re-review found no actionable findings after checking -the exact provenance derivation and all five deterministic-scenario -regressions; protected CI/review remain release gates. - -## 2026-08-10 Variation child timestamp propagation - -The #4280 continuation now carries exact parent -`05383d333b6fd87eaf5e37305476f50b505c2c2e` through a normal merge while -preserving its original base and complete variation export/accessibility -implementation. The inherited workspace parser now has one strict UTC grammar -and consistent zero- through six-digit fractional-second behavior across -Python 3.10-3.12. The child variation behavior is unchanged. - -SPEC 1.14.10 records the parent compatibility repair and 1.14.11 records the -child variation delta. Keep this handoff, the root and campaign handoffs, and -the reconciled SPEC in the merge commit. The combined evidence is `778 passed` -for the Rate suite, `27 passed` on real CPython 3.10.20, and `1 file / 8 tests` -for focused React variation, with TypeScript, focused ESLint, Ruff, format, and -pinned mypy 1.13 clean. Normal publication and dependency-ordered propagation -remain separate gates. - -## 2026-08-10 Workspace child receives second repaired parent - -PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. It normally merges exact repaired parent -head `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76`; there is no feature-code -conflict, rebase, retarget, or history rewrite. The inherited explicit ndarray -boundaries do not alter numerical behavior. Fresh child CI, review, and -dependency order remain required. -Verification after reconciliation is 25 focused D-plane/impact tests plus -docs-governance, changed-file-size, and whitespace gates. - -## 2026-08-10 Workspace child receives exact repaired parent - -PR `#4279` keeps branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. Its original head -`05383d333b6fd87eaf5e37305476f50b505c2c2e` normally merges exact parent -`31cbc007d4c85b5479b7cd0fb0969124eab2af67` in that order. The combined -shell retains the child's top toolstrip, persistent module visibility, -reorderable workspace, granular playback, path trail, and independent plot -controls. Parent repairs remain additive: the workspace mixin reuses the -canonical navigation constants, and the simulation controls reuse the single -persisted `ImpactLayerControls` checkbox map without duplicating UI state. - -Focused and broad verification is green: 1,339 Python tests pass with six -explicit optional/Rust-wheel skips; 545 React tests pass, as do type-check, -lint, and production build. Forty navigation/simulation GUI tests pass after -the final formatting change. Exact-parent Ruff/Ruff-format/Black, pinned MyPy -1.13 for 18 production modules, Bandit, file-size, docs, minimum-test, -assertion, detect-secrets, diff, CPython 3.10.20 compilation/import, and 30 -compatibility regressions pass. There is no Rust delta from the exact parent. -The merge commit must keep this file, the root handoff, campaign handoff, and -`SPEC.md` together. Independent staged review found no actionable findings -after 76 additional focused PyQt/navigation/workspace tests; exact-head -protected CI and required review remain release gates after a guarded ordinary -push. - -## 2026-08-10 Workspace fractional-timestamp compatibility repair - -The Python 3.10 lane on descendant PR #4281 revealed that the strict workspace -ordering test reached `datetime.fromisoformat` with a one-digit fractional -second. Python 3.10 rejects that spelling before comparing timestamps, although -newer supported interpreters accept it. PR #4279 is the earliest owning branch. -The workspace validator now enforces one anchored UTC grammar and parses every -losslessly representable zero- to six-digit fraction consistently, rejecting -greater precision rather than allowing interpreter-dependent truncation. It -does not modify the persisted spelling, UTC requirement, schema, or ordering -rule. - -Evidence is `778 passed` for the full Rate suite, `45 passed` across the -compatibility and workspace document tests on the local interpreter, and -`27 passed` under real CPython 3.10.20. Ruff, format, pinned mypy 1.13, docs -governance, and the 400-line budget pass. Keep this handoff, the root handoff, -campaign handoff, and SPEC entry in the same implementation commit; verify the -exact remote head before a normal push and propagate through later descendants. - -## 2026-08-09 Universal Variation Visualization Continuation - -Branch `feat/4144-variation-export-continuation` remains based on -`feat/4218-toolstrip-workspace` and now contains exact corrected parent -`3f67ed466fefc8991db9c4409f921f25e1c37142` through the normal merge containing -this handoff. The core PyQt6/React variation workspace has selectable -input/contact/impact/shot scatter, a scatter matrix with marginals, landing -dispersion, and an all-trial 3D swing-arc overlay with reference trace, -principal spread, RMS variability, quiet zones, filtering, and linked trial -selection. - -This continuation closes an export/accessibility parity gap: both clients now -export the complete selected scatter axes as CSV, including every trial, -typed outcome, and explicit unavailable values. PyQt now also exposes the raw -selected-axis rows in a bounded read-only table. Shared table population is -factored into `variation_trial_table.py`; the scalar scatter view is isolated -in `variation_scatter_view.py`. Changed production modules remain below 400 -lines and changed functions remain at or below 50 lines. - -The continuation is published as draft PR #4280. Current exact local evidence -on implementation commit `b3b09215e` is 890 -Python/PyQt/shared swing tests passed with one expected optional-Rust skip and -15 existing warnings, and 89 React test files / 545 tests passed. Ruff, -formatting, Black, targeted mypy, TypeScript, zero-warning ESLint, the 166-module -Vite build, and `git diff --check` pass. This is local evidence only; no PR, -protected CI, review, merge, or default-branch release has yet been established. - -The current local continuation normally incorporates exact corrected parent -`3f67ed466fefc8991db9c4409f921f25e1c37142` while preserving #4280's -`feat/4218-toolstrip-workspace` base. Its current focused evidence is `46` -Python 3.11 tests and `19` real-Python-3.10.20 tests with PyQt6 installed, -including the merged compatibility and variation widget contracts. React -passes `1 file / 8 tests`, TypeScript, and focused zero-warning ESLint. Ruff, -format, pinned mypy 1.13, documentation governance, ancestry/SPEC assertions, -and diff checks pass. SPEC 1.14.11 is the unique child entry for the -scatter-export and accessible-row-table source change. This propagation is -local only and has not been pushed. - -Literal audit of "every many-trial simulation" found two dependent gaps that -must remain explicit: - -- wind-strategy uncertainty retains paired per-strategy outcomes in both - runtimes but has no PyQt/React workflow and does not feed the universal - scalar plot facade; -- the capability optimizer stores aggregate statistics but discards the - individual evaluation rows needed for honest scatter plots. - -Issue #4199 already owns the wind UI/scatter requirement. Its adapter must use -composite row identity `(strategy_id, trial_index)`, retain completed, -nonconverged, and invalid cohorts, and report that impact variables are -unavailable because this runner begins at prescribed launch. Do not coerce it -into the impact-specific cohort enum or fabricate impact/landing values. - -Branch `feat/4199-wind-scalar-adapter` is published as -[draft PR #4281](https://github.com/D-sorganization/Tools/pull/4281), stacked -on exact corrected draft PR #4280 head -`38ed58cab96842a3007e76a855db83ee2452b8fd`. That parent is incorporated by a -normal local merge while preserving base -`feat/4144-variation-export-continuation`; no branch was rebased, retargeted, -force-pushed, or published by this continuation. -Implementation commit `4a28114aa` supplies that first UI-neutral model slice. -Python and React share the exact -snake-case `scalar-ensemble/v1` wire structure: structured provenance, -labeled stages/categories/cohorts, unit-bearing variables, RFC3986 composite -row identity, immutable nullable raw rows, and overall/per-cohort x/y/paired -availability. The wind adapter validates deterministic request/analysis trial -agreement, retains every actual and perfect-information status, and exposes -true/estimated wind, launch/aim, target, landing, miss, cost, and information -delta without invoking the flight solver. Impact variables remain honestly -absent because this analysis begins at launch. - -The original broad local gates remain green: 906 Python/PyQt/shared-swing tests -passed with one expected optional-Rust skip and 15 existing warnings; 91 React -files / 555 tests passed. After corrected-parent propagation, focused evidence -is `49 passed` on Python 3.11 and `49 passed` on real CPython 3.10.20 with -PyQt6/scientific dependencies present, plus `2 React files / 10 tests`, -TypeScript, and zero-warning focused ESLint. Ruff check/format passes all four -child Python files; pinned mypy 1.13 passes both production modules and the -wind-adapter test after its status helper received an exact `Literal` type. -The function budget passed at that historical head, but the 403-line wind -adapter did not satisfy the mandatory below-400 module ceiling; the 2026-08-11 -repair above is the first point at which that module claim is true. SPEC -1.14.11 uniquely records the child change above parent 1.14.10. This -contract/adapter does not complete #4199: the next slice still needs background -execution, progress and cancellation, PyQt/React scatter/strategy UI, -persistence, and export wiring. - -## 2026-08-07 Ground Model and Four-Surface Parity Revalidation - -The user's requested rolling-ground and site-wide parity programs already -exist as [epic #4267](https://github.com/D-sorganization/Tools/issues/4267) -with children #4268-#4276 and -[epic #4260](https://github.com/D-sorganization/Tools/issues/4260) with -children #4261-#4266. Do not create duplicate epics. A fresh repository and -live-GitHub audit was recorded in -[the ground comment](https://github.com/D-sorganization/Tools/issues/4267#issuecomment-5222725556) -and [the parity comment](https://github.com/D-sorganization/Tools/issues/4260#issuecomment-5222726010). - -There is no qualified landing/bounce/roll implementation yet. The current -airborne solvers stop at the relative launch plane and the shared -`TrajectoryPoint` omits terminal angular velocity. For a teed shot, translating -that relative trajectory into the course frame can leave the terminal ball -center at tee elevation. Complete #4268 and #4269 before implementing or -presenting bounce, roll, or total distance. - -Reuse the Tools `GroundModelResult` fail-closed boundary, putting skid/roll -limiting cases, and turf provenance/variation/cancellation patterns. Adapt -UpstreamDrift's split terrain material, elevation, normal, and region contracts -through a one-way versioned DTO. Do not qualify Upstream's scalar landing -helper, heuristic putting spin relaxation, legacy duplicate terrain model, or -Rust `(1-friction)` contact law as production high-speed landing physics. - -The parity matrix must keep Rate and Upstream's separate products distinct: -standalone Rate PyQt6/React, Upstream's Rate PyQt provider/React route, Shot -Tracer PyQt6/React, and the legacy ball-flight GUI. Current Upstream `main` -has no native Rate React route, and its Tools source resolvers disagree about -vendor-first versus sibling-first precedence. A launcher tile cannot satisfy a -calculation-parity row; #4261, #4262, and #4264 must make the runtime source, -exact Tools pin, and support state machine-verifiable. - -## 2026-08-09 Workspace Python 3.10 compatibility completion - -The #4279 continuation now contains exact corrected parent -`08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` through normal local merge -`a340fabefa443d47325c5538f342683b38c01ade`, without rebasing, retargeting, -force-pushing, or publication. The workspace command and view enums use the -shared `StrEnum` runtime compatibility contract with native enum typing kept -under `TYPE_CHECKING`; `_workspace_validation` uses the shared `UTC` value. -Stable identifiers, enum values, UTC serialization, schemas, and behavior are -unchanged. - -The combined regression inspects the runtime branch for all nine inherited -and child string-enum modules plus both UTC modules and directly executes the -three child workspace modules. Focused Python 3.11 evidence is `126 passed`. -Real CPython 3.10.20 evidence is `14 passed` plus successful dotted imports of -10 Rate/shared targets. Ruff check/format is clean, and pinned mypy 1.13 passes -all 11 affected production files under the changed-file CI contract. Keep the -root, tool, campaign handoffs and SPEC 1.14.9 entry in the implementation -commit; protected CI and review remain required after a normal push. - -## 2026-08-09 Workspace stack parent propagation - -Draft PR #4279 keeps base `feat/4181-launch-monitor-registry`. Exact published -parent head `08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` is carried by a normal -merge without rebasing, retargeting, force-pushing, or publishing this local -continuation. Source changes applied cleanly; overlapping handoff/specification -history was reconciled monotonically. The result retains the parent's facade -and Python 3.10 repairs plus the child's complete File/View/Tools registry, -strict workspace document, matched PyQt6/React toolstrips, module -visibility/order, playback, and independent plot controls. - -The reconciled ancestry passes `126` focused Python/PyQt tests and `8 React -files / 32 tests`. Ruff check/format passes all 28 relevant Python files, and -CI-pinned mypy 1.13 passes the 18 changed production files and both facade -tests. Mypy caught an untyped Qt `isChecked()` result in the child's -`legend_visible()` boundary; the method now returns an explicit `bool` without -changing runtime behavior. The affected simulation GUI rerun is `29 passed`; -documentation governance and diff checks pass. Keep this handoff, the root -handoff, the campaign handoff, and `SPEC.md` together in the merge commit. - -## 2026-08-10 Second D-Plane Parent Repair Propagation - -Draft PR `#4203` keeps base `feat/4189-dplane` and normally merges exact -repaired parent head `7d8d2f06dc797021d01939691e58f8425b652b33` without -rewriting either branch. The inherited change makes the two private D-plane -NumPy return boundaries explicit for pinned MyPy while preserving numerical -semantics, frames, schemas, and UI behavior. The parent quality gate is green; -child protected CI, review, dependency order, and #4189 closure remain open. -Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs, -changed-file-size, and whitespace gates. Local pinned-type evidence remains the -parent's green hosted quality gate: Windows MyPy 1.15 encounters incompatible -installed NumPy stub syntax and WSL is unavailable with `E_FAIL`, so neither -local attempt is represented as green. - -## 2026-08-10 Launch-Registry Child Propagation - -Draft PR `#4203` (`feat/4181-launch-monitor-registry`) retains its -`feat/4189-dplane` base and normally merges original child head -`08a2fdd8ce6bbc8fbb8f121927a677d4addb6b11` with exact parent head -`b443fdbed7064c5db0320106013c8413e3e24356`. - -The reconciliation preserves the child branch's responsive -`SimulationViewControlsMixin` and delegates its persisted D-plane layer -checkboxes to the parent's `ImpactLayerControls` helper. The compatibility -mapping and helper mapping are the same object, which prevents duplicate state -while retaining existing UI automation and persistence behavior. Both PyQt -modules remain below the 500-line limit. - -The original child already exceeded the protected budget in swing sources, -the plotting catalog, and the PyQt main window. Focused modules now own the -triple-pendulum model, immutable plotting-variable contract, and versioned tab -state. Compatibility imports remain the same objects, while the former -monoliths fall to 282, 459, and 494 lines. Focused evidence is green across 36 -PyQt simulation/layout tests, 38 plotting/navigation tests, and 21 simulation -source/export tests. Combined verification is green across 1,249 Python tests -with six explicit skips, 521 React tests and all web gates, 12 Rust tests, -real CPython 3.10 checks, scoped Ruff/Black/pinned MyPy, and repository -governance/security checks. The changed-file 500-line gate passes all 107 -candidate files. A full-tree audit still reports untouched `kinetics.py` and -`torque_profile_panel.py`; neither differs in this propagation. Independent -staged review found no actionable findings after 95 additional focused tests. -Current-head protected CI and required repository review remain release gates. - -## 2026-08-09 Python 3.10 enum import repair - -PR #4203 now owns the earliest fix for seven inherited Rate/shared swing -modules that imported Python 3.11's `enum.StrEnum` directly. Runtime code uses -the established shared compatibility helper while mypy sees the native enum -only inside `TYPE_CHECKING`. This preserves wire values and enum semantics on -supported interpreters and lets the repository's hosted Python 3.10 lane -collect the modules. The focused evidence is 64 tests, Ruff/format, pinned -mypy 1.13 across eight changed files, and a real CPython 3.10.20 source/runtime -probe. The exact published #4203 head is -`ab7de5a47977417e02926c3fbc7476002e82b690`; propagate it through the existing -stack without changing bases. - -A follow-up scan found the torque-profile controller importing -`datetime.UTC` directly. That parent-owned Python 3.11 boundary now uses -`shared.python.compatibility.UTC`; persisted timestamps and torque-profile -behavior are unchanged. Re-run the focused torque-profile UI tests and the -real Python 3.10 compatibility probe before propagation. - -## 2026-08-09 Launch-registry parent CI repair - -PR #4203 exact-head run `31199764932` reached the Python test lanes but failed -during Linux collection, before behavioral assertions. The two in-package -flight/solver facade tests were collected as `src.shared...` modules while -their absolute aliases crossed into the editable `shared...` namespace. They -now import their sibling facade package relatively, preserving the pinned -public API contract and production behavior. Reproduce with pytest -`--import-mode=importlib`; keep the separate Rust missing-`libpython3.11` -failure classified as runner infrastructure. Publish normally and propagate -the repaired parent through the existing stack without changing PR bases. -Verification is `12 passed` on Windows and `12 passed` on WSL Python 3.11 -under importlib collection; Ruff/format and exact mypy 1.13 pass for both -changed modules. The dataclass metadata assertion remains active behind an -explicit test-only `Any` introspection boundary. - -## 2026-08-10 PR #4202 D-plane ndarray typing repair - -On top of verified published head -`b443fdbed7064c5db0320106013c8413e3e24356`, the two private D-plane ndarray -helpers now bind NumPy results to explicit ndarray locals before returning -them. This closes the exact MyPy 1.13 `no-any-return` findings from CI Standard -run `31384810375`, job `93442745760`, without changing numerical operations, -DbC validation, reference frames, persistence, rendering, or public contracts. - -The exact MyPy failure was reproduced before editing and is green after the -repair. Twenty-four focused D-plane and impact integration tests pass, along -with seven metadata/pre-push contract tests, scoped Ruff, Ruff format, Black, -docs governance, minimum-test, module-size, changed-file-size, and diff checks. -Three unrelated CI-workflow contract tests still expect later toolcache/env -steps not present on this older branch; no workflow file is in scope. This -local commit does not push, retarget, change draft state, or claim issue -completion; protected CI, review, and parent-first release order remain -mandatory. - -## 2026-08-10 D-Plane Child Propagation - -Draft PR `#4202` (`feat/4189-dplane`) retains its -`feat/4162-wedge-impact-visualization` base and normally merges original child -head `b4abec03bccfbdd87ddf91427159c5c2332c21dd` with exact parent head -`6704a3e541a3e74c28b4a284530d1a21269dd340`. The inherited Python 3.10 UTC -repair and AST guard remain intact beside the frame-explicit D-plane contract. - -Persisted D-plane layer controls now live in a focused helper so -`simulation_view.py` again satisfies the protected 500-line budget while -retaining the existing UI-automation compatibility seam. Combined verification -is green: 93 focused and 825 scoped Python tests (two optional `build123d` -skips), 360 React tests and all web gates, real CPython 3.10.20 -compilation/UTC, scoped Ruff/Black/MyPy, and repository governance gates. The -exact parent's 12 unchanged `swing-core` tests remain applicable because this -child has no Rust delta. The 17-error broad MyPy Qt/NumPy baseline in 11 -untouched files remains separate. Protected CI and required review remain -release gates. - -## 2026-08-10 Impact-Visualization Child Propagation - -Draft PR `#4179` (`feat/4162-wedge-impact-visualization`) retains its -`feat/4166-wedge-turf-physics` base and normally merges original child head -`0eb804e70887c788421332369e42792411aff55a` with exact parent head -`bfa83aedc88ead380babc73a699377d98b971006`. The inherited Python 3.10 UTC -repair and AST guard remain intact beside the exact-event scene contract. - -Combined verification is green: 58 focused and 739 scoped Python tests (two -optional `build123d` skips), 347 React tests and all web gates, real CPython -3.10.20 compilation/UTC, scoped Ruff/Black/MyPy, and repository governance -gates. The exact parent's 12 unchanged `swing-core` tests remain applicable -because this child has no Rust delta. The 17-error broad MyPy Qt/NumPy baseline -in 11 untouched files remains separate. Protected CI and required review -remain release gates. - -## 2026-08-10 Turf-Physics Child Propagation - -Draft PR `#4178` (`feat/4166-wedge-turf-physics`) retains its -`feat/4161-wedge-ground-clearance` base and normally merges original child -head `aaae3f73e17dbfaad5cca1dc6f49559b3aebe9d5` with exact parent head -`9ea93e92563280ec34bca682ad44d7409edd7a02`. The inherited Python 3.10 UTC -repair and AST guard remain intact beside the provenance-gated turf model. - -Combined verification is green: 56 focused and 732 scoped Python tests (two -optional CAD-dependency skips), real CPython 3.10.20 checks, scoped -Ruff/Black/MyPy, and repository governance gates. The unchanged TypeScript and -Rust surfaces retain the exact parent's green 345 React and 12 Rust test -evidence. The 17-error broad MyPy Qt/NumPy baseline in 11 untouched files -remains separate. Protected CI and required review remain release gates. - -## 2026-08-10 Ground-Clearance Child Propagation - -Draft PR `#4174` (`feat/4161-wedge-ground-clearance`) keeps its -`feat/4163-impact-inspector` base and normally merges original child head -`880a6465fc872cf3d6650283db154ddc41793a31` with exact parent head -`9ddaff3b6bca542fd7a2befc7d7b0ae53910a60a`. The inherited Python 3.10 UTC -repair and AST guard remain intact beside the ground-clearance analysis. - -Combined verification is green: 56 focused and 703 scoped Python tests (two -optional `build123d` skips), 345 React tests and all web gates, 12 Rust tests, -real CPython 3.10.20 compile/UTC checks, scoped Ruff/Black/MyPy, and repository -governance checks. The existing 17-error broad MyPy Qt/NumPy baseline across -11 untouched files is documented, not expanded. Current-head protected CI and -required review remain pending. - -## 2026-08-10 Python 3.10 Repair Propagation - -Draft child PR `#4173` (`feat/4163-impact-inspector`) retains its -`feat/4144-variation-visualizations` base and normally merges original child -head `3c43955aaeb3964ff8c3ef2748d626baae518b76` with exact parent head -`22b66b560652b78de84141344c4ddd9a92a83b26`. This carries the shared -Python 3.10-compatible UTC export and the source-wide AST guard into the wedge -impact inspector without changing the persistence schema or user-visible -timestamp format. - -Combined-stack verification is green across 63 focused Python tests, all 562 -Rate tests, all 334 React tests, TypeScript/ESLint/Vite gates, 12 `swing-core` -tests, real CPython 3.10.20 compile/UTC checks, Ruff/Black, focused pinned MyPy -1.13, and repository governance checks. The broad MyPy sweep retains 17 -pre-existing Qt/NumPy typing findings in 11 untouched files. The PR must remain -draft until its exact-head protected checks complete and required review -approves. Do not retarget, rewrite, force-push, admin-merge, or count -infrastructure failures as passing evidence. - -## 2026-08-05 Advanced Wedge Impact Visualization - -Branch `feat/4162-wedge-impact-visualization` extends issue #4162 on top of the -validated turf stack. It corrects the impact adapter to evaluate pose, twist, -and articulated wrist geometry at the exact event time rather than silently -using the nearest retained sample. The new versioned -`rate-of-closure.impact-scene/v1` contract carries complete scene geometry, -velocity components, metric equations, frames, assumptions, availability, and -screw-axis data without placing physics in either UI. - -PyQt6 adds an exact-event Impact Inspector layer, locked physical axis scaling, -isometric/face-on/down-the-line cameras, and 300-DPI PNG, vector SVG, and strict -JSON export. React adds an orbitable and keyboard-controllable impact still, -the same named cameras and velocity toggles, visibly expandable engineering -metric definitions, and device-resolution PNG, true-primitive SVG, and JSON -exports. The web mirror now retains and shortest-arc interpolates the canonical -head rotation; the older limitation note saying it lacked full head pose is no -longer accurate for this branch. - -Scientific boundaries remain explicit: articulated sources do not yet have an -independent torsional head state; the scene is rigid-body instantaneous -kinematics; illustrative turf profiles cannot support optimal-bounce or -forgiveness claims; and turf force is not replayed into the retained swing. - -Current-head verification: all 576 Rate Python/PyQt tests passed (one existing -polynomial-generator legend warning); all 347 React/model tests passed; the -production Vite build, TypeScript, ESLint, Ruff, formatting, changed-module -strict mypy, and protected module-size budget passed. Headless Chrome visual QA -at 1600×1400 exercised named views, a vector toggle, keyboard orbit, and an -expanded metric definition with zero console exceptions/log errors. The new -web branch is running at `http://localhost:5260/`; the current PyQt process was -also launched successfully and remained responsive. - -## 2026-08-05 Wedge Impact Inspector Integration - -Draft PR #4173 (`feat/4163-impact-inspector`) integrates the draft variation -branch with the shared golf-club stack through wedge kinematics PR #4172. It -adds the first bounded implementation slice for wedge epic #4158 / -impact-inspector issue #4163: - -- Canonical inspection time and event label on every `SimulationRun`: impact - for hits, closest approach for misses. -- Exact `Jump to Impact` / `Jump to Closest Approach` controls in PyQt6 and - React, with playback paused before the jump. -- `simulation/impact_kinematics.py`, which adapts retained pose/twist/contact - data to `shared.python.golf_club.WedgeKinematicState` and preserves geometry - provenance and model limitations. -- Engineering readouts in both clients for contact/reference AoA, remove-shaft - counterfactual, shaft rotation and vertical velocity, face-normal rate, - leading-edge/arc rate where available, and screw-axis distance. -- Restored manual angular velocity in the React simulation path; the previous - hard-coded zero made all closure and shaft metrics false zeros. -- Deterministic midpoint tie-breaking for a flat maximum-speed plateau, so the - manual source's automatic event is its documented square pose at 30 ms. - -Physics boundary: articulated pendulum runs expose the measured wrist-to-head -shaft line but have no shaft-twist degree of freedom. The inspector reports -that absence rather than inventing torsional motion. The web mirror still does -not retain full head pose; its readout declares that limitation until WASM or a -canonical backend replaces the temporary TypeScript mirror. - -Current-head release evidence: 1,006 Python/PyQt/shared-swing tests passed with -five optional Rust-wheel parity skips; 334 React/model tests and 12 swing-core -Rust tests passed; Vite production build, TypeScript, ESLint, Ruff, formatting, -and mypy across 165 source files passed. A focused post-refactor PyQt run passed -46 tests. Browser QA verified the 1,307 deg/s manual fixture at 30 ms and a -1.430 s closest-approach miss with zero console warnings/errors. Native-window -QA confirmed the control and readout are visible in the standalone PyQt6 app. - -## Status Note - -`src/rate_of_closure` and `src/shared/python/swing_sim` do **not exist on -`main` yet** — they land with PR #4119. This doc describes the tool as it -exists on the in-flight branch stack (`feat/impact-simulation-platform` → -`feat/investigation-suite` → `feat/course-showcase`) so the next agent has -full context the moment #4119 merges. If you're reading this on a fresh -`main` checkout and don't see `src/rate_of_closure/`, check out one of those -branches or wait for #4119 to land. - -## Where This Tool Is Headed - -Rate of Closure started as a single-page "closure rate" calculator (twist -model: GC-path vs impact-point-path gap, °/ft). Epics #4103 → #4120 → #4125 → -#4130 are growing it into a full swing → impact → ball-flight simulator with -PyQt6 + web parity and eventual public GitHub Pages distribution. Read -`src/rate_of_closure/README.md` (frame conventions, Cheetham dossier sourcing, -run instructions) before touching physics code. - -## The #4119 → #4124 → #4129 PR Stack - -Each PR consolidates a whole epic's stacked feature branches into one PR to -keep self-hosted CI load down (see `CLAUDE.md` — these are big diffs). - -- **#4119** `feat/impact-simulation-platform` (epic #4103, open, auto-merge - armed). Base tool (twist model, PyQt6 + React/Vite web, Cheetham dossier - data) + STL clubheads/club library/inertial model + `swing_sim` shared - package (`src/shared/python/swing_sim/`: swing sources, impact model ported - from UpstreamDrift with 3 physics fixes, gear effect, 7 literature - ball-flight models, goal-driven multi-start solver) + `swing-core` Rust - crate (pyo3 + wasm) + app integration (simulation session, impact-time - scrubber, screw-axis overlay via the rotation_converter adapter, video - controls, CSV/JSON export, solver panel). 404 pytest + 72 vitest + 111 - cargo tests, all local gates green. Supersedes #4092/#4097/#4098/#4112-4118. - -- **#4124** `feat/investigation-suite` (epic #4120, open, **draft state — - do not merge yet**, stacked on #4119). Adds `rate_of_closure/plotting/` - (40-variable data catalog, `PlotSpec`, Plots tab + custom-plot wizard), - scale-separated Strike/Swing/Flight viewers + standalone Flight Explorer, - `swing_sim/variation/` (seeded Monte Carlo/NoiseSpec engine, dispersion + - Spearman sensitivity, Variation tab), and V4: glossary (60 terms), - cold-user help system, "Derivation & Traceability" → "Calculation - Description" rename, full-model derivations, hover-hint completeness sweep. - Supersedes draft PRs #4121/#4122/#4123. 566 pytest + 125 vitest passing. - -- **#4129** `feat/course-showcase` (epic #4125, open, **draft state — do - not merge yet**, stacked on #4124). Merges `feat/realistic-heads` (H1: - parametric club-type geometry, volumetric COG via divergence theorem), - `feat/swing-kinetics` (H2: joint torque/force plots + 3D overlays from - pendulum inverse dynamics), `feat/putting-vertical` (H3: `swing_sim` - putting module + app Putting tab), then adds on top: H7 course scene - (`ui/course.py` / `course_scene.py`) + target optimization - (`swing_sim/solver/targets.py`, `TargetRegion`, `ImpactGoal.target_region`), - and H6 showcase styling (`ui/pyqt6/app_style.py`, UpstreamDrift launcher - visual language) + yards-default distance units. 413 pytest + 309 swing_sim - - 174 vitest passing. H4 (AffineDrift putting research content) and H5 - (public release-management repo) are cross-repo and tracked in #4125 - directly, not in this PR. - -**Do not merge #4124 or #4129 before their base merges** — SPEC.md sections -were unioned assuming sequential merge order; merging out of order will -produce conflicting/duplicate changelog rows. - -## swing_sim Packages - -`src/shared/python/swing_sim/` (introduced by #4119, home for physics shared -with UpstreamDrift via the established shared-module arrow): - -- `swing_sim/flight/` — 7 literature ball-flight models (drag/lift/spin - decay), citations in registry metadata. -- `swing_sim/impact/` — impact model ported from UpstreamDrift (offset-drop - fix, opt-in 3×3 MOI tensor, inverted friction spin axis fix), gear effect, - `SpringDamperImpactModel` (Kelvin-Voigt contact force history, 1e-7s steps) - — this is the contact-force law epic #4130 will extend for the full - contact-interval integration rather than duplicate. -- `swing_sim/solver/` — goal-driven multi-start least-squares solver; - `targets.py` (added in #4129) adds `TargetRegion` for green/fairway - optimization goals. -- `swing_sim/variation/` (added in #4124) — namespaced variable registry, - `NoiseSpec`/`VariationPlan`, seeded parallel N-run Monte Carlo engine, - dispersion/OAT sensitivity/Spearman/landing-ellipse stats. - -Epic #4130 (Impact-Interval Club Dynamics) will add `impact_interval/` to -this same package — its home is explicitly `swing_sim` so UpstreamDrift -reaches it via vendor, per that epic's F2 phase description. Not started yet -(foundation-only epic, no PR). - -## How #4103/#4120/#4125/#4130 Relate to This Tool - -All four are rate_of_closure epics specifically (unlike the wider-monorepo -epics tracked in the root `AGENT_HANDOFF.md`, e.g. SCADA #4085-#4089). -#4103 is the foundation platform; #4120, #4125 are sequential feature waves -stacked directly on its PR; #4130 is a physics-depth epic that extends the -impact model #4103 introduced (contact-interval integration replacing the -instantaneous-impulse approximation) — foundation phase only so far. - -## Web Mirror + GitHub Pages - -The web mirror (`src/rate_of_closure/web/`, React/Vite/TS) is pinned -test-for-test against the PyQt6 model today (TS mirrors hand-written, not yet -WASM — that swap is explicitly deferred to Phase 7 of #4103). It builds to a -static bundle (`npm run build`) and carries Tauri scripts for desktop -packaging, same as other web tools in the repo. - -**There is no automated GitHub Pages CI deploy for this tool yet.** No -`.github/workflows/*.yml` references `rate_of_closure` or Pages deploy -actions as of this writing. The only Pages-publishing precedent in the repo -is `src/web_applications/unit_converter/unit-converter-app/DEPLOYMENT.md`'s -manual branch-folder publish (Settings → Pages → select branch/folder). -Phase 7 of #4103 ("GitHub Pages mirror updated (public share link), parity -tests as deploy gates") owns building a real workflow — do not improvise one -in an unrelated PR. - -## Must-Read Architecture Pointers - -1. `src/rate_of_closure/README.md` — frame conventions, unit conventions, - dossier sourcing, run/build instructions. -2. `src/rate_of_closure/model.py` (base twist physics, no Qt) once #4119 - lands. -3. `src/shared/python/swing_sim/impact/` — the contact-force law shared - with (and about to be extended by) epic #4130. -4. `rust_core/swing-core/` — pendulum EOM + plane projection, pyo3 + wasm - targets, follows the `tools-core` feature-contract pattern. -5. `.github/workflows/maturin-swing-core.yml` (added by #4119) — Rust wheel - build for this crate. - -## Gate Commands (this tool) - -```bash -python3 -m pytest tests/rate_of_closure src/shared/python/swing_sim -n auto --timeout=60 -cd src/rate_of_closure/web && npm run test && npm run build && npx tsc --noEmit && npx eslint . -cargo test -p swing-core -python3 -m ruff check src/rate_of_closure src/shared/python/swing_sim -python3 -m mypy src/rate_of_closure src/shared/python/swing_sim -``` - -Run Ruff format/check and pinned delta mypy on every changed Python file. Do not -rewrite parents, force-push, bypass checks, infer unavailable values, or close -#4201 until exact protected merge, installed package, downstream pin, science, -performance, accessibility, documentation, and rollback evidence all exist. - -## 2026-08-11 parent sections preserved during #4282 reconciliation - -## 2026-08-11 Workspace child receives hosted MyPy repair - -PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. Exact child -`7806a16f58e1c6999d32f0127a187fbb21f839a1` normally merges exact published -parent `3796b49e40b677fbac4e05739f8be49f905df2cb`. No feature-code conflict -exists: the inherited production delta is four static `numpy.ndarray` casts, -while workspace/toolstrip behavior and runtime arrays, physics, frames, units, -imports, and UI behavior remain unchanged. This local merge does not satisfy -fresh protected CI, required review, unresolved-thread, dependency, or release -gates. - -## 2026-08-11 workspace child receives latest repaired parent - -PR `#4279` retains branch `feat/4218-toolstrip-workspace` and base -`feat/4181-launch-monitor-registry`. A normal merge incorporates exact parent -`0216a547aa79727091a2939b96e779e8ddbd7304` into exact child -`61b7f48b5aeb7d57246b4963da3df086e79cbe15`. There are no feature-code -conflicts: workspace/toolstrip, visibility, navigation, playback, and plot -behavior remain unchanged while the parent kinetics façade/dynamics/series -split and pinned formatting are inherited. This local merge does not satisfy -fresh protected CI, required review, unresolved-thread, dependency, or release -gates. - -## 2026-08-11 Append-only SPEC preservation repair - -Independent review found that the local #4203 reconciliation omitted four -exact D-plane parent SPEC rows dated 2026-08-10 (versions 1.13.11, 1.13.9, -1.13.7, and 1.13.6). They are restored verbatim in a documentation-only -follow-up. Production behavior, tests, ordered parents, base, and local quality -evidence are unchanged; re-review, normal publication, and protected CI remain -open. - -## 2026-08-11 Current D-plane parent reconciliation - -PR #4203's published child `217e36dc93d30f79826847f958fbcd10805e58ed` -is being normally merged with exact current D-plane base -`f3363aa88868f6a5c7e9ccfc682a9eca014e86c1`. The base and source branch stay -unchanged. The only conflict is the parent's formatting of an older monolithic -kinetics expression: the split facade keeps its typed pendulum accessor and -inherits the parent's geometry explanation. No launch-monitor, D-plane, or -kinetics behavior is intentionally changed. Four Qt-stub `Any` returns exposed -by the exact MyPy 1.13 delta are also narrowed to their declared `bool`/`str` -contracts without changing values. Focused/full validation, independent -review, normal publication, and protected CI remain open. - -## 2026-08-11 Exact-head format completion - -Protected CI on #4203 head `7d69a545ae555679f0318940e67c1786626d6794` -failed only Ruff formatting. The pinned 0.14.10 reproduction found eleven -noncompliant changed Python files: four inherited files plus seven altered by -the automated pre-commit repair. The pending repair intentionally changes no -launch-monitor, kinetics, simulation, or UI behavior and requires independent -review plus fresh protected CI before integration. - -## 2026-08-11 Hosted MyPy NumPy-return repair - -CI Standard run `31477542889`, job `93734652129`, found four -`no-any-return` errors after the kinetics façade extraction at exact PR #4203 -head `0216a547aa79727091a2939b96e779e8ddbd7304`. The NumPy stubs widen -`linalg.norm`, `concatenate`, and matrix projection results to `Any` even -though the runtime operations return arrays. The private series/dynamics -modules and public façade now use explicit `cast(np.ndarray, ...)` boundaries. -These casts are static only: array identity, values, dtype, shape, physics, -frames, units, imports, and UI behavior are unchanged. Verification must cover -the complete PR changed-source MyPy set and both focused and full Rate tests. -Current local evidence is 102 changed-source MyPy files, 28 focused tests, and -all 701 Rate tests passing; complete-delta Ruff/format and Bandit are also -green. - -## 2026-08-11 Kinetics façade extraction - -The strict current-head delta reproduces a protected size failure that the -PR-base comparison hides: `kinetics.py` is changed versus `HEAD~1` and is 646 -LOC, above the ungrandfathered 500-LOC maximum. The public module is now a -222-LOC run adapter/facade; its pure double-pendulum dynamics are in the -205-LOC `_kinetics_dynamics.py`, and the immutable `KineticsSeries`/DbC -contract is in the 131-LOC `_kinetics_series.py`. Existing public imports and -the `_reaction_forces` seam are the same implementation objects. A RED-first -identity test plus the existing physics, energy, force, parity-fixture, -presentation, and PyQt tests protect behavior. No physics, frame, SI-unit, -schema, UI, or stack-order change is intended; the commit remains local only. -Focused kinetics/presentation/PyQt verification is 28 passing tests; the -complete Rate-of-Closure Python regression suite is 701 passing tests. - -## 2026-08-11 #4203 pinned-Ruff formatting repair - -No material handoff change: current-head CI Standard run `31468208320`, job -`93705508050`, identified eight files that differ from repository-pinned Ruff -0.14.10 output. This commit changes formatting only; Rate physics, behavior, -frames, persistence schemas, PyQt/React contracts, stack bases, and dependency -order remain unchanged. Fresh protected CI and review are still required. - -## 2026-08-10 Ground/Tee parity child receives repaired parent - -Ready PR `#4325` keeps branch `feat/4143-tee-parity-fixture` and base -`feat/4181-launch-monitor-registry`. It normally merges exact repaired parent -head `12dd76a8dbcc106c4683f2f2e53076f8dc6f1b76` without any production/test -code conflict or history rewrite. Shared parity and rendered-evidence -contracts remain intact; fresh protected CI, review, dependency order, and -#4143 release remain open. - -## 2026-08-10 #4143 Python/React Golden Ball-Setup Parity - -The isolated `feat/4143-tee-parity-fixture` child begins at exact draft PR -#4203 head `31cbc007d4c85b5479b7cd0fb0969124eab2af67`. One versioned JSON fixture now -drives both Python and React ball-support tests with explicit SI units and the -ground-plane-to-ball-bottom height reference. The shared cases cover Driver -and non-Driver defaults, user overrides, Ground zero effective height, -derived ball-center geometry and serialization, negative/NaN/infinite height -rejection, and backward-compatible migration of a legacy run without -`ball_setup`. - -Evidence is 18 passing Python tee/parity tests and 24 passing React -tee/persistence/parity tests, plus green TypeScript, ESLint, Vite production -build, Ruff check, and Ruff format. Production model and UI code are unchanged. -Recorded visual evidence now adds 1600 x 1200 Playwright Driver/Tee and -rerun-Ground captures plus 1400 x 900 hidden-window PyQt captures. The browser -run asserts control state, diagram geometry, and zero console/page errors; the -desktop run asserts canonical center/artist state, nonblank output, and -different Ground/Tee digests without pixel absolutes. The exact artifacts and -versioned manifests are in -`C:\Users\diete\AppData\Local\Temp\rate-4143-visual-evidence-8050eeba`. -Do not close #4143: protected current-head CI/review and release to `main` -remain. This exact parent predates the strict campaign manifest on a divergent -branch, so no downstream manifest was copied into this bounded child. - -## 2026-08-10 Wind scalar child receives second repaired parent - -PR `#4281` retains branch `feat/4199-wind-scalar-adapter` and base -`feat/4144-variation-export-continuation`. It normally merges exact repaired -parent `b90e5021a59e2081415b51ef29fbed06377bc201` without scalar-adapter code -conflict or history rewrite. Fresh child CI, review, and dependency order -remain required. -Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs, -changed-file-size, and whitespace gates. - -## 2026-08-10 Variation export child receives exact workspace parent - -PR `#4280` retains branch `feat/4144-variation-export-continuation`, base -`feat/4218-toolstrip-workspace`, and original child first parent -`f90836e342efc8be624739802375af2876d11e5f`. Exact parent -`6717e9e09d507dbc24bedb36177f1cdf0b4fd90b` merges normally as the second -parent. All variation visualization/export source merged without conflict: -selected scatter CSV, typed unavailable rows, accessible bounded raw tables, -linked trials, focused PyQt widgets, and React parity remain additive with the -parent workspace/toolstrip/playback/plot/navigation repairs. SPEC 1.14.12 is -the unique combined child entry. Staged review exposed a stale linked-trial -selection when a smaller rerun replaced the active result. Corrected PyQt -views clear result-local selection before repopulating and validate all public -setter indices; React clears on result identity change and shares only bounded -selections with linked views. Thirty-seven focused variation tests and the -complete Rate/shared-swing/golf-club matrix pass 1,528 tests with two explicit -optional build123d skips; all 546 React tests across 90 files pass; -TypeScript, ESLint, and production build are green. Exact-parent -Ruff/Ruff-format/Black, pinned MyPy 1.13 across four Python production modules, -Bandit, file-size, docs, minimum-test, assertion, detect-secrets, diff, real -CPython 3.10.20 compilation, and 30 compatibility regressions pass. There is -no Rust delta from the exact parent. Independent staged re-review found no -actionable findings, including the first replacement-render React boundary. -Protected CI/review remain release gates after an ordinary guarded push. - -## 2026-08-10 Variation child receives second repaired workspace parent - -PR `#4280` retains branch `feat/4144-variation-export-continuation` and base -`feat/4218-toolstrip-workspace`. It normally merges exact repaired parent head -`61b7f48b5aeb7d57246b4963da3df086e79cbe15` without feature-code conflict or -history rewrite. Variation/export behavior remains unchanged; fresh child CI, -review, and dependency order remain required. -Post-reconciliation evidence is 25 focused D-plane/impact tests plus docs, -changed-file-size, and whitespace gates. - -## 2026-08-10 Wind scalar child receives exact variation parent - -PR `#4281` keeps branch `feat/4199-wind-scalar-adapter`, base -`feat/4144-variation-export-continuation`, and original child first parent -`cf52529b1e68479321bb93b1be3d59c77f782008`. Exact parent -`8bcc49fc4e16e5e43be0b7f0f03c3017d5b79d0c` merges normally second. The -child's scalar-ensemble wire contract, provenance-preserving wind rows, -availability accounting, and plot adapter remain additive with the parent's -variation visualization/export and result-local selection repairs. Python and -TypeScript reject wind scenarios unless their per-trial provenance is exact, -shear/turbulence are zero, seed is zero, and gusts are empty. SPEC 1.14.13 is -the unique combined child entry. Twenty-seven focused Python tests, the -1,549-test complete Rate/shared-swing/golf-club matrix with two explicit -optional build123d skips, and all 556 React tests across 92 files pass. -TypeScript, ESLint, production build, Ruff/format, pinned MyPy, Bandit, size, -docs, minimum-test, assertions, detect-secrets, diff, and CPython 3.10 compile -gates pass. Independent re-review found no actionable findings after checking -the exact provenance derivation and all five deterministic-scenario -regressions; protected CI/review remain release gates. - -## 2026-08-10 Variation child timestamp propagation - -The #4280 continuation now carries exact parent -`05383d333b6fd87eaf5e37305476f50b505c2c2e` through a normal merge while -preserving its original base and complete variation export/accessibility -implementation. The inherit…4250 tokens truncated…7417e02926c3fbc7476002e82b690`; propagate it through the existing -stack without changing bases. - -A follow-up scan found the torque-profile controller importing -`datetime.UTC` directly. That parent-owned Python 3.11 boundary now uses -`shared.python.compatibility.UTC`; persisted timestamps and torque-profile -behavior are unchanged. Re-run the focused torque-profile UI tests and the -real Python 3.10 compatibility probe before propagation. - -## Do-Not List - -- Do not duplicate the Kelvin-Voigt contact-force law — #4130 requires - `SpringDamperImpactModel` and the new `impact_interval/` package to share - one implementation (DRY, explicit in the epic's binding standards). -- Do not exceed 500 LOC per file in `rate_of_closure`, `swing_sim`, or - `swing-core` — sub-package instead. -- Do not hand-mirror physics into the TS web layer once WASM lands (Phase 7) - — that's the whole point of the wasm-pack build; today's hand-written TS - mirrors are a stopgap, not the target architecture. -- Do not merge the stacked PRs out of order (see stack section above). -- Do not invent citations in derivation docstrings or the AffineDrift - putting research content (H4) — sourced/verifiable only, dossier - discipline per epic #4125. - -## Roadmap (ordered) - -1. Merge #4119, then #4124, then #4129 in order. -2. Start epic #4130 Phase F1 (formulation document) — six-DOF rigid-club - contact-interval derivation, validation program design. -3. Phase 7 of #4103: WASM swap + real Pages CI deploy workflow. -4. #4125 H4/H5: AffineDrift putting research content and the public - release-management repo (both cross-repo, not started). diff --git a/src/rate_of_closure/application/__init__.py b/src/rate_of_closure/application/__init__.py index 20fd60d88..cf3ca435d 100644 --- a/src/rate_of_closure/application/__init__.py +++ b/src/rate_of_closure/application/__init__.py @@ -6,6 +6,10 @@ CommandAvailability, CommandUnavailableError, ) +from .regional_surface_plan_files import ( + read_regional_surface_plan_request, + write_regional_surface_plan_request_atomic, +) from .workspace_document import ( WORKSPACE_SCHEMA, WORKSPACE_SCHEMA_VERSION, @@ -30,7 +34,9 @@ "WorkspaceLayout", "WorkspaceMetadata", "read_workspace", + "read_regional_surface_plan_request", "workspace_from_json", "workspace_to_json", "write_workspace_atomic", + "write_regional_surface_plan_request_atomic", ] diff --git a/src/rate_of_closure/application/atomic_text_files.py b/src/rate_of_closure/application/atomic_text_files.py new file mode 100644 index 000000000..852ce12b8 --- /dev/null +++ b/src/rate_of_closure/application/atomic_text_files.py @@ -0,0 +1,55 @@ +"""Small atomic UTF-8 text-file boundary shared by application documents.""" + +from __future__ import annotations + +import os +import tempfile +from pathlib import Path + + +def _destination_path(destination: str | Path, document_name: str) -> Path: + path = Path(destination) + if not path.name: + raise ValueError(f"{document_name} destination must name a file") + if not path.parent.is_dir(): + raise FileNotFoundError( + f"{document_name} parent directory does not exist: {path.parent}" + ) + if path.exists() and not path.is_file(): + raise IsADirectoryError(f"{document_name} destination is not a file: {path}") + return path + + +def write_utf8_text_atomic( + text: str, + destination: str | Path | None, + *, + document_name: str, +) -> bool: + """Flush and atomically replace one UTF-8 text file. + + ``None`` represents a cancelled chooser. Serialization must happen before + this function is called so a validation failure cannot touch the target. + """ + if destination is None: + return False + if not isinstance(text, str): + raise TypeError("atomic file content must be text") + path = _destination_path(destination, document_name) + descriptor, temporary_name = tempfile.mkstemp( + prefix=f".{path.name}.", suffix=".tmp", dir=path.parent + ) + temporary = Path(temporary_name) + try: + with os.fdopen(descriptor, "w", encoding="utf-8", newline="") as handle: + handle.write(text) + handle.flush() + os.fsync(handle.fileno()) + os.replace(temporary, path) + except Exception: + temporary.unlink(missing_ok=True) + raise + return True + + +__all__ = ["write_utf8_text_atomic"] diff --git a/src/rate_of_closure/application/regional_surface_plan.py b/src/rate_of_closure/application/regional_surface_plan.py index 34d5ecb89..1ffce376f 100644 --- a/src/rate_of_closure/application/regional_surface_plan.py +++ b/src/rate_of_closure/application/regional_surface_plan.py @@ -6,11 +6,13 @@ from dataclasses import asdict, dataclass from shared.python.swing_sim.canonical_numeric_json import canonical_numeric_json +from shared.python.swing_sim.ground.contract_types import GroundSurfaceProfile from shared.python.swing_sim.ground.regional_plan_records import ( REGIONAL_PLAN_GEOMETRY_MODEL, REGIONAL_PLAN_LIMITATIONS, REGIONAL_PLAN_REQUEST_SCHEMA_VERSION, GroundRegionalMaterialPlanRequest, + GroundRegionalMaterialRegion, ) from shared.python.swing_sim.ground.regional_plan_wire import ( regional_material_plan_request_from_dict, @@ -158,6 +160,99 @@ def _region_payload(region: RegionalOverlayDraft) -> dict[str, object]: } +def _surface_draft(surface: GroundSurfaceProfile) -> SurfaceMaterialDraft: + """Project one already-validated wire surface into editable SI values.""" + return SurfaceMaterialDraft( + surface.surface_id, + surface.normal_restitution, + surface.static_friction, + surface.kinetic_friction, + surface.rolling_resistance, + surface.firmness_pa, + surface.hardness_fraction, + surface.grass_height_m, + surface.compressibility_fraction, + surface.compression_damping_fraction, + surface.turf_density_kg_m3, + surface.moisture_fraction, + ) + + +def _assert_editor_surface(surface: GroundSurfaceProfile) -> None: + """Reject material evidence not authored under the editor v1 contract.""" + if ( + surface.provider_id != EDITOR_PROVIDER_ID + or surface.provider_version != EDITOR_PROVIDER_VERSION + ): + raise ValueError("surface is not qualified by the editor provider v1") + + +def _overlay_draft(region: GroundRegionalMaterialRegion) -> RegionalOverlayDraft: + return RegionalOverlayDraft( + region.region_id, + region.precedence, + region.lower_coordinate_m, + region.upper_coordinate_m, + _surface_draft(region.surface), + ) + + +def editor_draft_from_regional_surface_plan_request( + request: GroundRegionalMaterialPlanRequest, +) -> RegionalSurfacePlanDraft: + """Project one fully validated, editor-qualified v1 request into the editor. + + The editor provider v1 contract is explicitly unvalidated. Requests from a + different producer, material provider, axis qualification, or row capacity + are therefore rejected rather than relabelled or coerced. + """ + if type(request) is not GroundRegionalMaterialPlanRequest: + raise TypeError("request must be an exact GroundRegionalMaterialPlanRequest") + provenance = request.provenance + if ( + provenance.producer != EDITOR_PROVIDER_ID + or provenance.producer_version != EDITOR_PROVIDER_VERSION + ): + raise ValueError("request is not qualified by the editor producer v1") + if request.axis_origin_m != (0.0, 0.0, 0.0) or request.axis_unit != ( + 1.0, + 0.0, + 0.0, + ): + raise ValueError("request uses an unsupported editor axis qualification") + if len(request.regions) > MAX_EDITOR_REGIONS: + raise ValueError(f"editor supports one to at most {MAX_EDITOR_REGIONS} regions") + _assert_editor_surface(request.base_surface) + for region in request.regions: + _assert_editor_surface(region.surface) + draft = RegionalSurfacePlanDraft( + request.request_id, + request.lower_coordinate_m, + request.upper_coordinate_m, + provenance.source_revision, + "unvalidated", + _surface_draft(request.base_surface), + tuple(_overlay_draft(region) for region in request.regions), + ) + if provenance.input_sha256 != _source_digest(draft): + raise ValueError("editor provenance digest does not match the editable request") + return draft + + +def regional_surface_plan_request_for_draft( + draft: RegionalSurfacePlanDraft, + imported_request: GroundRegionalMaterialPlanRequest | None = None, +) -> GroundRegionalMaterialPlanRequest: + """Preserve an unchanged import exactly; otherwise bind fresh provenance.""" + if imported_request is not None: + imported_draft = editor_draft_from_regional_surface_plan_request( + imported_request + ) + if draft == imported_draft: + return imported_request + return validate_regional_surface_plan_draft(draft) + + def validate_regional_surface_plan_draft( draft: RegionalSurfacePlanDraft, ) -> GroundRegionalMaterialPlanRequest: @@ -191,10 +286,14 @@ def validate_regional_surface_plan_draft( __all__ = [ + "EDITOR_PROVIDER_ID", + "EDITOR_PROVIDER_VERSION", "MAX_EDITOR_REGIONS", "RegionalOverlayDraft", "RegionalSurfacePlanDraft", "SurfaceMaterialDraft", + "editor_draft_from_regional_surface_plan_request", "illustrative_regional_surface_plan_draft", + "regional_surface_plan_request_for_draft", "validate_regional_surface_plan_draft", ] diff --git a/src/rate_of_closure/application/regional_surface_plan_files.py b/src/rate_of_closure/application/regional_surface_plan_files.py new file mode 100644 index 000000000..14ff29643 --- /dev/null +++ b/src/rate_of_closure/application/regional_surface_plan_files.py @@ -0,0 +1,57 @@ +"""Strict native file adapter for canonical regional surface-plan requests.""" + +from __future__ import annotations + +from pathlib import Path + +from shared.python.swing_sim.ground.regional_plan_records import ( + MAX_REGIONAL_PLAN_WIRE_BYTES, + GroundRegionalMaterialPlanRequest, +) +from shared.python.swing_sim.ground.regional_plan_wire import ( + regional_material_plan_request_from_json, +) + +from .atomic_text_files import write_utf8_text_atomic + + +def _read_bounded_utf8(path: Path) -> str: + """Read one immutable handle snapshot without allocating beyond the cap.""" + with path.open("rb") as handle: + raw = handle.read(MAX_REGIONAL_PLAN_WIRE_BYTES + 1) + if len(raw) > MAX_REGIONAL_PLAN_WIRE_BYTES: + raise ValueError("regional material plan exceeds maximum wire size") + try: + return raw.decode("utf-8") + except UnicodeDecodeError as exc: + raise ValueError("regional material plan must be valid UTF-8") from exc + + +def read_regional_surface_plan_request( + source: str | Path, +) -> GroundRegionalMaterialPlanRequest: + """Read and completely validate one canonical request before returning it.""" + path = Path(source) + if not path.is_file(): + raise FileNotFoundError(f"regional surface plan does not exist: {path}") + return regional_material_plan_request_from_json(_read_bounded_utf8(path)) + + +def write_regional_surface_plan_request_atomic( + request: GroundRegionalMaterialPlanRequest, + destination: str | Path | None, +) -> bool: + """Write exact canonical request bytes, or return false after cancellation.""" + if destination is None: + return False + if type(request) is not GroundRegionalMaterialPlanRequest: + raise TypeError("request must be an exact GroundRegionalMaterialPlanRequest") + return write_utf8_text_atomic( + request.to_json(), destination, document_name="regional surface plan" + ) + + +__all__ = [ + "read_regional_surface_plan_request", + "write_regional_surface_plan_request_atomic", +] diff --git a/src/rate_of_closure/application/workspace_files.py b/src/rate_of_closure/application/workspace_files.py index 58b6f2ebb..fa627902d 100644 --- a/src/rate_of_closure/application/workspace_files.py +++ b/src/rate_of_closure/application/workspace_files.py @@ -2,10 +2,9 @@ from __future__ import annotations -import os -import tempfile from pathlib import Path +from .atomic_text_files import write_utf8_text_atomic from .workspace_document import ( WorkspaceDocument, workspace_from_json, @@ -13,18 +12,6 @@ ) -def _destination_path(destination: str | Path) -> Path: - path = Path(destination) - if not path.name: - raise ValueError("workspace destination must name a file") - parent = path.parent - if not parent.is_dir(): - raise FileNotFoundError(f"workspace parent directory does not exist: {parent}") - if path.exists() and not path.is_file(): - raise IsADirectoryError(f"workspace destination is not a file: {path}") - return path - - def read_workspace(source: str | Path) -> WorkspaceDocument: """Read and fully validate one workspace before returning it. @@ -59,21 +46,7 @@ def write_workspace_atomic( if destination is None: return False serialized = workspace_to_json(document) - path = _destination_path(destination) - descriptor, temporary_name = tempfile.mkstemp( - prefix=f".{path.name}.", suffix=".tmp", dir=path.parent - ) - temporary = Path(temporary_name) - try: - with os.fdopen(descriptor, "w", encoding="utf-8", newline="\n") as handle: - handle.write(serialized) - handle.flush() - os.fsync(handle.fileno()) - os.replace(temporary, path) - except Exception: - temporary.unlink(missing_ok=True) - raise - return True + return write_utf8_text_atomic(serialized, destination, document_name="workspace") __all__ = ["read_workspace", "write_workspace_atomic"] diff --git a/src/rate_of_closure/ui/pyqt6/engineering_number_input.py b/src/rate_of_closure/ui/pyqt6/engineering_number_input.py index ff0ed6d15..af130c734 100644 --- a/src/rate_of_closure/ui/pyqt6/engineering_number_input.py +++ b/src/rate_of_closure/ui/pyqt6/engineering_number_input.py @@ -16,6 +16,7 @@ class NumberInputSpec: step: float = 0.1 minimum: float = -1e9 maximum: float = 1e9 + decimals: int = 6 def __post_init__(self) -> None: """Reject unusable Qt ranges before a widget is constructed.""" @@ -25,6 +26,12 @@ def __post_init__(self) -> None: raise ValueError("minimum and maximum must be finite") if self.minimum > self.maximum: raise ValueError("minimum must not exceed maximum") + if ( + isinstance(self.decimals, bool) + or not isinstance(self.decimals, int) + or not 0 <= self.decimals <= 323 + ): + raise ValueError("decimals must be an integer from zero through 323") def engineering_number_input( @@ -35,7 +42,7 @@ def engineering_number_input( """Create one consistently configured accessible SI number input.""" field = QDoubleSpinBox() field.setAccessibleName(name) - field.setDecimals(6) + field.setDecimals(spec.decimals) field.setRange(spec.minimum, spec.maximum) field.setSingleStep(spec.step) field.setSuffix(spec.suffix) diff --git a/src/rate_of_closure/ui/pyqt6/regional_surface_plan_io.py b/src/rate_of_closure/ui/pyqt6/regional_surface_plan_io.py new file mode 100644 index 000000000..db39e5183 --- /dev/null +++ b/src/rate_of_closure/ui/pyqt6/regional_surface_plan_io.py @@ -0,0 +1,101 @@ +"""Native Open/Save As controller for the regional surface-plan editor.""" + +from __future__ import annotations + +from pathlib import Path +from typing import Protocol + +from PyQt6.QtWidgets import QFileDialog, QLabel, QPlainTextEdit, QWidget + +from rate_of_closure.application.regional_surface_plan_files import ( + read_regional_surface_plan_request, + write_regional_surface_plan_request_atomic, +) +from shared.python.swing_sim.ground.regional_plan_records import ( + GroundRegionalMaterialPlanRequest, +) + + +class RegionalSurfacePlanFileHost(Protocol): + """Minimal host surface needed by the native file controller.""" + + status_label: QLabel + readback: QPlainTextEdit + + def current_request(self) -> GroundRegionalMaterialPlanRequest: ... + + def apply_imported_request( + self, request: GroundRegionalMaterialPlanRequest + ) -> None: ... + + +class RegionalSurfacePlanFileActions: + """Transactional native file commands with one successful recent path.""" + + def __init__(self, host: RegionalSurfacePlanFileHost, parent: QWidget) -> None: + self._host = host + self._parent = parent + self.recent_path: Path | None = None + + def open(self) -> None: + """Choose, fully validate, and only then replace the editor draft.""" + selected, _filter = QFileDialog.getOpenFileName( + self._parent, + "Open Regional Surface Plan", + self._initial_location(), + "JSON files (*.json)", + ) + if not selected: + return + path = Path(selected) + try: + request = read_regional_surface_plan_request(path) + self._host.apply_imported_request(request) + except (OSError, TypeError, ValueError) as exc: + self._set_error(f"Open failed: {exc}") + return + self.recent_path = path + self._host.readback.setPlainText(request.to_json()) + self._set_success(f"Opened {path.name}. No physics executed.") + + def save_as(self) -> None: + """Validate before choosing a destination, then atomically replace it.""" + try: + request = self._host.current_request() + except (TypeError, ValueError) as exc: + self._set_error(f"Save failed: {exc}") + return + selected, _filter = QFileDialog.getSaveFileName( + self._parent, + "Save Regional Surface Plan As", + self._initial_location("regional-surface-plan.json"), + "JSON files (*.json)", + ) + if not selected: + return + path = Path(selected) + try: + write_regional_surface_plan_request_atomic(request, path) + except OSError as exc: + self._set_error(f"Save failed: {exc}") + return + self.recent_path = path + self._host.readback.setPlainText(request.to_json()) + self._set_success(f"Saved {path.name} atomically. No physics executed.") + + def _initial_location(self, filename: str = "") -> str: + if self.recent_path is None: + return filename + parent = self.recent_path.parent + return str(parent / filename) if filename else str(parent) + + def _set_error(self, message: str) -> None: + self._host.status_label.setText(message) + self._host.status_label.setAccessibleName("Regional surface plan file error") + + def _set_success(self, message: str) -> None: + self._host.status_label.setText(message) + self._host.status_label.setAccessibleName("Regional surface plan file success") + + +__all__ = ["QFileDialog", "RegionalSurfacePlanFileActions"] diff --git a/src/rate_of_closure/ui/pyqt6/regional_surface_plan_tab.py b/src/rate_of_closure/ui/pyqt6/regional_surface_plan_tab.py index 26d8e7406..bcdc38ef3 100644 --- a/src/rate_of_closure/ui/pyqt6/regional_surface_plan_tab.py +++ b/src/rate_of_closure/ui/pyqt6/regional_surface_plan_tab.py @@ -2,13 +2,10 @@ from __future__ import annotations -from collections.abc import Callable from dataclasses import replace -from PyQt6.QtCore import Qt from PyQt6.QtWidgets import ( QComboBox, - QDoubleSpinBox, QFormLayout, QGroupBox, QHBoxLayout, @@ -17,7 +14,6 @@ QPlainTextEdit, QPushButton, QScrollArea, - QSpinBox, QVBoxLayout, QWidget, ) @@ -26,124 +22,23 @@ MAX_EDITOR_REGIONS, RegionalOverlayDraft, RegionalSurfacePlanDraft, - SurfaceMaterialDraft, + editor_draft_from_regional_surface_plan_request, illustrative_regional_surface_plan_draft, - validate_regional_surface_plan_draft, + regional_surface_plan_request_for_draft, ) -from rate_of_closure.ui.pyqt6.engineering_number_input import ( - NumberInputSpec, +from rate_of_closure.ui.pyqt6.regional_surface_plan_io import ( + RegionalSurfacePlanFileActions, ) -from rate_of_closure.ui.pyqt6.engineering_number_input import ( - engineering_number_input as _number_input, +from rate_of_closure.ui.pyqt6.regional_surface_plan_widgets import ( + MaterialEditor, + RegionalOverlayRow, + coordinate_input, ) - -_MATERIAL_FIELDS = ( - ("normal_restitution", "Normal restitution", "", 0.01, 0.0, 1.0), - ("static_friction", "Static friction", "", 0.01, 0.0, 5.0), - ("kinetic_friction", "Kinetic friction", "", 0.01, 0.0, 5.0), - ("rolling_resistance", "Rolling resistance", "", 0.01, 0.0, 1.0), - ("firmness_pa", "Firmness", " Pa", 1_000.0, 0.001, 1e9), - ("hardness_fraction", "Hardness", " fraction", 0.01, 0.0, 1.0), - ("grass_height_m", "Grass height", " m", 0.001, 0.0, 1.0), - ("compressibility_fraction", "Compressibility", " fraction", 0.01, 0.0, 1.0), - ( - "compression_damping_fraction", - "Compression damping", - " fraction", - 0.01, - 0.0, - 1.0, - ), - ("turf_density_kg_m3", "Turf density", " kg/m³", 1.0, 0.0, 10_000.0), - ("moisture_fraction", "Moisture", " fraction", 0.01, 0.0, 1.0), +from shared.python.swing_sim.ground.regional_plan_records import ( + GroundRegionalMaterialPlanRequest, ) -class MaterialEditor(QGroupBox): - """Editable surface identity and full v1 material parameter collection.""" - - def __init__(self, title: str, value: SurfaceMaterialDraft) -> None: - super().__init__(title) - self.surface_id = QLineEdit(value.surface_id) - self.surface_id.setAccessibleName(f"{title} surface ID") - self.surface_id.setToolTip( - f"Stable identifier for {title.lower()}; included in validated readback." - ) - self.fields: dict[str, QDoubleSpinBox] = {} - layout = QFormLayout(self) - layout.addRow("Surface ID", self.surface_id) - for name, label, suffix, step, minimum, maximum in _MATERIAL_FIELDS: - field = _number_input( - f"{title} {label}", - getattr(value, name), - NumberInputSpec(suffix, step, minimum, maximum), - ) - self.fields[name] = field - layout.addRow(label, field) - - def draft(self) -> SurfaceMaterialDraft: - """Read the current widgets without applying separate UI validation.""" - values = {name: field.value() for name, field in self.fields.items()} - return SurfaceMaterialDraft(self.surface_id.text(), **values) - - -class RegionalOverlayRow(QGroupBox): - """One removable bounded regional overlay row.""" - - def __init__( - self, - ordinal: int, - value: RegionalOverlayDraft, - remove: Callable[[RegionalOverlayRow], None], - ) -> None: - super().__init__(f"Regional overlay {ordinal}") - self.region_id = QLineEdit(value.region_id) - self.region_id.setToolTip( - "Stable overlay identifier; it must be unique within the regional plan." - ) - self.precedence = QSpinBox() - self.precedence.setRange(0, 1_000_000) - self.precedence.setValue(value.precedence) - self.precedence.setToolTip( - "Overlay selection precedence. Higher values win when intervals overlap." - ) - self.lower_coordinate = _number_input( - f"Overlay {ordinal} lower coordinate", - value.lower_coordinate_m, - NumberInputSpec(suffix=" m"), - ) - self.upper_coordinate = _number_input( - f"Overlay {ordinal} upper coordinate", - value.upper_coordinate_m, - NumberInputSpec(suffix=" m"), - ) - self.material = MaterialEditor(f"Overlay {ordinal} material", value.surface) - self.remove_button = QPushButton(f"Remove overlay {ordinal}") - self.remove_button.setToolTip( - "Remove this overlay from the unvalidated draft; one overlay is required." - ) - self.remove_button.clicked.connect(lambda: remove(self)) - form = QFormLayout() - form.addRow("Region ID", self.region_id) - form.addRow("Precedence", self.precedence) - form.addRow("Lower coordinate", self.lower_coordinate) - form.addRow("Upper coordinate", self.upper_coordinate) - layout = QVBoxLayout(self) - layout.addLayout(form) - layout.addWidget(self.material) - layout.addWidget(self.remove_button, alignment=Qt.AlignmentFlag.AlignRight) - - def draft(self) -> RegionalOverlayDraft: - """Read one overlay for authoritative contract validation.""" - return RegionalOverlayDraft( - self.region_id.text(), - self.precedence.value(), - self.lower_coordinate.value(), - self.upper_coordinate.value(), - self.material.draft(), - ) - - class RegionalSurfacePlanTab(QWidget): """Session-only regional surface editor with strict canonical readback.""" @@ -151,6 +46,8 @@ def __init__(self, parent: QWidget | None = None) -> None: super().__init__(parent) self._rows: list[RegionalOverlayRow] = [] self._initial = illustrative_regional_surface_plan_draft() + self._imported_request: GroundRegionalMaterialPlanRequest | None = None + self.file_actions = RegionalSurfacePlanFileActions(self, self) self._build_ui() self._connect_static_changes() self._append_row(self._initial.regions[0]) @@ -173,7 +70,7 @@ def _connect_static_changes(self) -> None: def _connect_row_changes(self, row: RegionalOverlayRow) -> None: """Connect one dynamic overlay to the shared invalidation boundary.""" row.region_id.textChanged.connect(self._mark_dirty) - row.precedence.valueChanged.connect(self._mark_dirty) + row.precedence.textChanged.connect(self._mark_dirty) row.lower_coordinate.valueChanged.connect(self._mark_dirty) row.upper_coordinate.valueChanged.connect(self._mark_dirty) self._connect_material_changes(row.material) @@ -242,8 +139,8 @@ def _identity_box(self) -> QGroupBox: ) geometry.setWordWrap(True) session = QLabel( - "Session-only draft: current workspace file commands do not persist " - "model inputs." + "Open/Save As persists this canonical request only. Workspace " + "persistence remains a separate contract." ) session.setWordWrap(True) layout = QFormLayout(box) @@ -257,15 +154,13 @@ def _identity_box(self) -> QGroupBox: def _base_box(self) -> QGroupBox: """Create the base interval and complete base material editor.""" box = QGroupBox("Base surface and domain") - self.domain_lower = _number_input( + self.domain_lower = coordinate_input( "Base domain lower coordinate", self._initial.lower_coordinate_m, - NumberInputSpec(suffix=" m"), ) - self.domain_upper = _number_input( + self.domain_upper = coordinate_input( "Base domain upper coordinate", self._initial.upper_coordinate_m, - NumberInputSpec(suffix=" m"), ) self.base_material = MaterialEditor("Base material", self._initial.base_surface) layout = QVBoxLayout(box) @@ -291,7 +186,21 @@ def _action_row(self) -> QHBoxLayout: "Validate the complete draft and display its canonical SI request." ) self.validate_button.clicked.connect(self.validate_plan) + self.open_button = QPushButton("Open JSON") + self.open_button.setAccessibleName("Open regional surface plan JSON") + self.open_button.setToolTip( + "Open and fully validate an editor-qualified canonical request." + ) + self.open_button.clicked.connect(self.file_actions.open) + self.save_button = QPushButton("Save As JSON") + self.save_button.setAccessibleName("Save regional surface plan JSON as") + self.save_button.setToolTip( + "Atomically save the validated canonical request to a chosen file." + ) + self.save_button.clicked.connect(self.file_actions.save_as) layout.addWidget(self.add_button) + layout.addWidget(self.open_button) + layout.addWidget(self.save_button) layout.addStretch(1) layout.addWidget(self.validate_button) return layout @@ -362,10 +271,35 @@ def draft(self) -> RegionalSurfacePlanDraft: tuple(row.draft() for row in self._rows), ) + def current_request(self) -> GroundRegionalMaterialPlanRequest: + """Return exact imported evidence unless the visible draft has changed.""" + return regional_surface_plan_request_for_draft( + self.draft(), self._imported_request + ) + + def apply_imported_request( + self, request: GroundRegionalMaterialPlanRequest + ) -> None: + """Populate widgets only after complete strict editor qualification.""" + draft = editor_draft_from_regional_surface_plan_request(request) + self.request_id.setText(draft.request_id) + self.source_revision.setText(draft.source_revision) + self.domain_lower.setValue(draft.lower_coordinate_m) + self.domain_upper.setValue(draft.upper_coordinate_m) + self.base_material.set_draft(draft.base_surface) + for row in self._rows: + self.rows_layout.removeWidget(row) + row.deleteLater() + self._rows.clear() + for region in draft.regions: + self._append_row(region) + self._update_row_actions() + self._imported_request = request + def validate_plan(self) -> None: """Validate through the strict contract and render canonical readback.""" try: - request = validate_regional_surface_plan_draft(self.draft()) + request = self.current_request() except (TypeError, ValueError) as exc: self.status_label.setText(str(exc)) self.status_label.setAccessibleName( diff --git a/src/rate_of_closure/ui/pyqt6/regional_surface_plan_widgets.py b/src/rate_of_closure/ui/pyqt6/regional_surface_plan_widgets.py new file mode 100644 index 000000000..33cbb0aab --- /dev/null +++ b/src/rate_of_closure/ui/pyqt6/regional_surface_plan_widgets.py @@ -0,0 +1,231 @@ +"""Reusable PyQt6 inputs for the regional surface-plan editor.""" + +from __future__ import annotations + +from collections.abc import Callable + +from PyQt6.QtCore import Qt +from PyQt6.QtGui import QValidator +from PyQt6.QtWidgets import ( + QDoubleSpinBox, + QFormLayout, + QGroupBox, + QLineEdit, + QPushButton, + QVBoxLayout, +) + +from rate_of_closure.application.regional_surface_plan import ( + RegionalOverlayDraft, + SurfaceMaterialDraft, +) +from rate_of_closure.ui.pyqt6.engineering_number_input import ( + NumberInputSpec, + engineering_number_input, +) +from shared.python.swing_sim.canonical_numeric_json import ( + MAX_CANONICAL_SAFE_INTEGER, +) + +_MAX_SAFE_FLOAT = float(MAX_CANONICAL_SAFE_INTEGER) +_MAX_SAFE_INTEGER_TEXT = str(MAX_CANONICAL_SAFE_INTEGER) + +_MATERIAL_FIELDS = ( + ("normal_restitution", "Normal restitution", "", 0.01, 0.0, 1.0), + ("static_friction", "Static friction", "", 0.01, 0.0, 5.0), + ("kinetic_friction", "Kinetic friction", "", 0.01, 0.0, 5.0), + ("rolling_resistance", "Rolling resistance", "", 0.01, 0.0, 1.0), + ("firmness_pa", "Firmness", " Pa", 1_000.0, 1e-11, _MAX_SAFE_FLOAT), + ("hardness_fraction", "Hardness", " fraction", 0.01, 0.0, 1.0), + ("grass_height_m", "Grass height", " m", 0.001, 0.0, _MAX_SAFE_FLOAT), + ("compressibility_fraction", "Compressibility", " fraction", 0.01, 0.0, 1.0), + ( + "compression_damping_fraction", + "Compression damping", + " fraction", + 0.01, + 0.0, + 1.0, + ), + ( + "turf_density_kg_m3", + "Turf density", + " kg/m³", + 1.0, + 0.0, + _MAX_SAFE_FLOAT, + ), + ("moisture_fraction", "Moisture", " fraction", 0.01, 0.0, 1.0), +) + + +def number_input( + name: str, + value: float, + spec: NumberInputSpec | None = None, +) -> QDoubleSpinBox: + """Create one canonical-precision accessible SI number input.""" + resolved_spec = spec or NumberInputSpec( + minimum=-_MAX_SAFE_FLOAT, + maximum=_MAX_SAFE_FLOAT, + decimals=11, + ) + return engineering_number_input(name, value, resolved_spec) + + +def coordinate_input(name: str, value: float) -> QDoubleSpinBox: + """Create one canonical-precision coordinate editor.""" + return number_input( + name, + value, + NumberInputSpec( + suffix=" m", + minimum=-_MAX_SAFE_FLOAT, + maximum=_MAX_SAFE_FLOAT, + decimals=11, + ), + ) + + +class _SafeIntegerValidator(QValidator): + """Accept one decimal integer in the shared JSON-safe nonnegative range.""" + + def validate( + self, input_text: str | None, position: int + ) -> tuple[QValidator.State, str, int]: + input_text = input_text or "" + if input_text == "": + state = QValidator.State.Intermediate + elif not input_text.isascii() or not input_text.isdecimal(): + state = QValidator.State.Invalid + elif len(input_text) < len(_MAX_SAFE_INTEGER_TEXT): + state = QValidator.State.Acceptable + elif input_text <= _MAX_SAFE_INTEGER_TEXT: + state = QValidator.State.Acceptable + else: + state = QValidator.State.Invalid + return state, input_text, position + + +class SafeIntegerEdit(QLineEdit): + """Exact integer editor that does not narrow the v1 safe-integer contract.""" + + def __init__(self, name: str, value: int) -> None: + super().__init__() + self._name = name + self.setAccessibleName(name) + self.setMaxLength(len(_MAX_SAFE_INTEGER_TEXT)) + self.setValidator(_SafeIntegerValidator(self)) + self.set_value(value) + + def set_value(self, value: int) -> None: + """Set one already validated exact safe integer without float conversion.""" + if isinstance(value, bool) or not isinstance(value, int): + raise TypeError(f"{self._name} must be an integer") + if not 0 <= value <= MAX_CANONICAL_SAFE_INTEGER: + raise ValueError(f"{self._name} must lie within cross-runtime safe range") + self.setText(str(value)) + + def value(self) -> int: + """Return the exact integer or reject an incomplete editor value.""" + if not self.hasAcceptableInput(): + raise ValueError(f"{self._name} must lie within cross-runtime safe range") + return int(self.text()) + + +class MaterialEditor(QGroupBox): + """Editable surface identity and full v1 material parameter collection.""" + + def __init__(self, title: str, value: SurfaceMaterialDraft) -> None: + super().__init__(title) + self.surface_id = QLineEdit(value.surface_id) + self.surface_id.setAccessibleName(f"{title} surface ID") + self.surface_id.setToolTip( + f"Stable identifier for {title.lower()}; included in validated readback." + ) + self.fields: dict[str, QDoubleSpinBox] = {} + layout = QFormLayout(self) + layout.addRow("Surface ID", self.surface_id) + for name, label, suffix, step, minimum, maximum in _MATERIAL_FIELDS: + field = number_input( + f"{title} {label}", + getattr(value, name), + NumberInputSpec(suffix, step, minimum, maximum, decimals=11), + ) + self.fields[name] = field + layout.addRow(label, field) + + def draft(self) -> SurfaceMaterialDraft: + """Read the current widgets without applying separate UI validation.""" + values = {name: field.value() for name, field in self.fields.items()} + return SurfaceMaterialDraft(self.surface_id.text(), **values) + + def set_draft(self, value: SurfaceMaterialDraft) -> None: + """Replace all visible material values from one validated draft.""" + self.surface_id.setText(value.surface_id) + for name, field in self.fields.items(): + field.setValue(getattr(value, name)) + + +class RegionalOverlayRow(QGroupBox): + """One removable bounded regional overlay row.""" + + def __init__( + self, + ordinal: int, + value: RegionalOverlayDraft, + remove: Callable[[RegionalOverlayRow], None], + ) -> None: + super().__init__(f"Regional overlay {ordinal}") + self.region_id = QLineEdit(value.region_id) + self.region_id.setToolTip( + "Stable overlay identifier; it must be unique within the regional plan." + ) + self.precedence = SafeIntegerEdit( + f"Overlay {ordinal} precedence", value.precedence + ) + self.precedence.setToolTip( + "Overlay selection precedence. Higher values win when intervals overlap." + ) + self.lower_coordinate = coordinate_input( + f"Overlay {ordinal} lower coordinate", + value.lower_coordinate_m, + ) + self.upper_coordinate = coordinate_input( + f"Overlay {ordinal} upper coordinate", + value.upper_coordinate_m, + ) + self.material = MaterialEditor(f"Overlay {ordinal} material", value.surface) + self.remove_button = QPushButton(f"Remove overlay {ordinal}") + self.remove_button.setToolTip( + "Remove this overlay from the unvalidated draft; one overlay is required." + ) + self.remove_button.clicked.connect(lambda: remove(self)) + form = QFormLayout() + form.addRow("Region ID", self.region_id) + form.addRow("Precedence", self.precedence) + form.addRow("Lower coordinate", self.lower_coordinate) + form.addRow("Upper coordinate", self.upper_coordinate) + layout = QVBoxLayout(self) + layout.addLayout(form) + layout.addWidget(self.material) + layout.addWidget(self.remove_button, alignment=Qt.AlignmentFlag.AlignRight) + + def draft(self) -> RegionalOverlayDraft: + """Read one overlay for authoritative contract validation.""" + return RegionalOverlayDraft( + self.region_id.text(), + self.precedence.value(), + self.lower_coordinate.value(), + self.upper_coordinate.value(), + self.material.draft(), + ) + + +__all__ = [ + "MaterialEditor", + "RegionalOverlayRow", + "SafeIntegerEdit", + "coordinate_input", + "number_input", +] diff --git a/src/rate_of_closure/variation/canonical_numeric_json.py b/src/rate_of_closure/variation/canonical_numeric_json.py index b031cc6f8..a78b6a39e 100644 --- a/src/rate_of_closure/variation/canonical_numeric_json.py +++ b/src/rate_of_closure/variation/canonical_numeric_json.py @@ -1,5 +1,7 @@ -"""Compatibility import for the shared canonical numeric JSON encoder.""" +"""Capability-observation facade for canonical numeric JSON encoding.""" -from shared.python.swing_sim.canonical_numeric_json import canonical_numeric_json +from shared.python.swing_sim.canonical_numeric_json import ( + canonical_numeric_json_extended_floats as canonical_numeric_json, +) __all__ = ["canonical_numeric_json"] diff --git a/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.test.tsx b/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.test.tsx index 1356cb121..72d77dc51 100644 --- a/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.test.tsx +++ b/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.test.tsx @@ -1,13 +1,22 @@ -import { fireEvent, render, screen } from "@testing-library/react"; -import { describe, expect, it } from "vitest"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { MAX_REGIONAL_SURFACE_EDITOR_ROWS, buildGroundRegionalSurfacePlanRequest, + editorDraftFromGroundRegionalSurfacePlanRequest, illustrativeRegionalSurfacePlanDraft, + regionalSurfacePlanRequestForDraft, } from "../model/regionalSurfacePlan"; +import { + MAX_GROUND_REGIONAL_PLAN_WIRE_BYTES, + parseGroundRegionalMaterialPlanRequest, + stableGroundRegionalMaterialPlanJson, +} from "../model/groundRegionalPlan"; import { RegionalSurfacePlanPanel } from "./RegionalSurfacePlanPanel"; +afterEach(() => vi.restoreAllMocks()); + describe("RegionalSurfacePlanPanel", () => { it("matches Python provenance for the disclosed illustrative draft", () => { const request = buildGroundRegionalSurfacePlanRequest( @@ -49,6 +58,32 @@ describe("RegionalSurfacePlanPanel", () => { .not.toBeInTheDocument(); }); + it("accepts the exact cross-runtime maximum precedence", () => { + render(); + fireEvent.change(screen.getByLabelText("Overlay 1 precedence"), { + target: { value: String(Number.MAX_SAFE_INTEGER) }, + }); + + fireEvent.click(screen.getByRole("button", { name: "Validate surface plan" })); + + expect(screen.queryByRole("alert")).not.toBeInTheDocument(); + expect(screen.getByRole("status", { name: "Regional surface plan readback" })) + .toHaveTextContent("1 overlay(s)"); + }); + + it("rejects integer-valued material numbers beyond the cross-runtime safe range", () => { + render(); + fireEvent.change(screen.getByLabelText("Base Firmness (Pa)"), { + target: { value: "10000000000000000" }, + }); + + fireEvent.click(screen.getByRole("button", { name: "Validate surface plan" })); + + expect(screen.getByRole("alert")).toHaveTextContent(/cross-runtime safe range/i); + expect(screen.queryByRole("status", { name: "Regional surface plan readback" })) + .not.toBeInTheDocument(); + }); + it("links invalid interval fields to an accessible error without clearing input", () => { render(); const lower = screen.getByLabelText("Overlay 1 lower coordinate (m)"); @@ -84,6 +119,123 @@ describe("RegionalSurfacePlanPanel", () => { .toHaveLength(MAX_REGIONAL_SURFACE_EDITOR_ROWS); expect(add).toBeDisabled(); expect(screen.queryByRole("button", { name: /run|play/i })).not.toBeInTheDocument(); - expect(screen.getByText(/session-only draft/i)).toBeInTheDocument(); + expect(screen.getByText(/workspace persistence remains separate/i)).toBeInTheDocument(); + }); + + it("preserves an unchanged imported editor request exactly", () => { + const request = buildGroundRegionalSurfacePlanRequest({ + ...illustrativeRegionalSurfacePlanDraft(), request_id: "imported-plan", + }); + + const imported = editorDraftFromGroundRegionalSurfacePlanRequest(request); + + expect(regionalSurfacePlanRequestForDraft(imported, request)).toBe(request); + expect(stableGroundRegionalMaterialPlanJson( + regionalSurfacePlanRequestForDraft(imported, request), + )).toBe(stableGroundRegionalMaterialPlanJson(request)); + + const payload = JSON.parse(stableGroundRegionalMaterialPlanJson(request)); + payload.provenance.input_sha256 = "0".repeat(64); + const mismatched = parseGroundRegionalMaterialPlanRequest(payload); + expect(() => editorDraftFromGroundRegionalSurfacePlanRequest(mismatched)) + .toThrow(/digest does not match/i); + }); + + it("imports only after complete validation and retains the prior draft on error", async () => { + render(); + const request = buildGroundRegionalSurfacePlanRequest({ + ...illustrativeRegionalSurfacePlanDraft(), request_id: "browser-opened-plan", + }); + const input = screen.getByLabelText("Import regional surface plan JSON file"); + const validText = stableGroundRegionalMaterialPlanJson(request); + const valid = { + name: "valid.json", + size: new TextEncoder().encode(validText).byteLength, + text: vi.fn().mockResolvedValue(validText), + }; + + fireEvent.change(input, { target: { files: [valid] } }); + await waitFor(() => expect(screen.getByLabelText("Regional plan request ID")) + .toHaveValue("browser-opened-plan")); + + const corrupt = { + name: "corrupt.json", size: 47, + text: vi.fn().mockResolvedValue('{"request_id":"one","request_id":"two"}'), + }; + fireEvent.change(input, { target: { files: [corrupt] } }); + await waitFor(() => expect(screen.getByRole("alert")).toHaveTextContent(/duplicate/i)); + expect(screen.getByLabelText("Regional plan request ID")) + .toHaveValue("browser-opened-plan"); + + const invalidSyntax = { + name: "syntax.json", size: 9, + text: vi.fn().mockResolvedValue("{not-json"), + }; + fireEvent.change(input, { target: { files: [invalidSyntax] } }); + await waitFor(() => expect(screen.getByRole("alert")).toHaveTextContent(/invalid profile json/i)); + expect(screen.getByLabelText("Regional plan request ID")) + .toHaveValue("browser-opened-plan"); + }); + + it("rejects non-editor qualification without populating the editor", async () => { + render(); + const request = buildGroundRegionalSurfacePlanRequest( + illustrativeRegionalSurfacePlanDraft(), + ); + const payload = JSON.parse(stableGroundRegionalMaterialPlanJson(request)); + payload.provenance.producer = "external.course.authority"; + const input = screen.getByLabelText("Import regional surface plan JSON file"); + const file = { + name: "external.json", size: 100, + text: vi.fn().mockResolvedValue(JSON.stringify(payload)), + }; + + fireEvent.change(input, { target: { files: [file] } }); + + await waitFor(() => expect(screen.getByRole("alert")).toHaveTextContent(/editor producer/i)); + expect(screen.getByLabelText("Regional plan request ID")) + .toHaveValue("illustrative-regional-plan"); + }); + + it("rejects oversized browser files before allocating their text", async () => { + render(); + const input = screen.getByLabelText("Import regional surface plan JSON file"); + const text = vi.fn().mockResolvedValue("{}"); + const file = { + name: "oversize.json", size: MAX_GROUND_REGIONAL_PLAN_WIRE_BYTES + 1, text, + }; + + fireEvent.change(input, { target: { files: [file] } }); + + await waitFor(() => expect(screen.getByRole("alert")).toHaveTextContent(/maximum wire size/i)); + expect(text).not.toHaveBeenCalled(); + expect(screen.getByLabelText("Regional plan request ID")) + .toHaveValue("illustrative-regional-plan"); + }); + + it("downloads canonical bytes and revokes its object URL", () => { + const createUrl = vi.fn(() => "blob:regional-plan"); + const revokeUrl = vi.fn(); + Object.defineProperty(URL, "createObjectURL", { configurable: true, value: createUrl }); + Object.defineProperty(URL, "revokeObjectURL", { configurable: true, value: revokeUrl }); + const click = vi.spyOn(HTMLAnchorElement.prototype, "click").mockImplementation(() => {}); + render(); + + fireEvent.click(screen.getByRole("button", { name: "Download regional surface plan JSON" })); + + expect(createUrl).toHaveBeenCalledOnce(); + expect(click).toHaveBeenCalledOnce(); + expect(revokeUrl).toHaveBeenCalledWith("blob:regional-plan"); + }); + + it("treats an empty browser chooser as cancellation", () => { + render(); + const input = screen.getByLabelText("Import regional surface plan JSON file"); + + fireEvent.change(input, { target: { files: [] } }); + + expect(screen.queryByRole("alert")).not.toBeInTheDocument(); + expect(screen.getByLabelText("Regional plan request ID")) + .toHaveValue("illustrative-regional-plan"); }); }); diff --git a/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.tsx b/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.tsx index 068fff039..6e8fc544c 100644 --- a/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.tsx +++ b/src/rate_of_closure/web/src/components/RegionalSurfacePlanPanel.tsx @@ -1,13 +1,19 @@ -import { useState } from "react"; +import { type ChangeEvent, useRef, useState } from "react"; import { MAX_REGIONAL_SURFACE_EDITOR_ROWS, - buildGroundRegionalSurfacePlanRequest, + editorDraftFromGroundRegionalSurfacePlanRequest, illustrativeRegionalSurfacePlanDraft, + regionalSurfacePlanRequestForDraft, type RegionalOverlayDraft, type RegionalSurfacePlanDraft, type SurfaceMaterialDraft, } from "../model/regionalSurfacePlan"; +import { + downloadRegionalSurfacePlanRequest, + readRegionalSurfacePlanFile, +} from "../model/regionalSurfacePlanFiles"; +import type { GroundRegionalMaterialPlanRequest } from "../model/groundRegionalPlan"; type NumericMaterialKey = Exclude; @@ -133,15 +139,20 @@ function nextOverlay(draft: RegionalSurfacePlanDraft): RegionalOverlayDraft { export function RegionalSurfacePlanPanel() { const [draft, setDraft] = useState(illustrativeRegionalSurfacePlanDraft); + const [importedRequest, setImportedRequest] = + useState(null); const [error, setError] = useState(null); const [readback, setReadback] = useState(null); + const [fileStatus, setFileStatus] = useState(null); const [validationAttempted, setValidationAttempted] = useState(false); + const fileInput = useRef(null); const updateDraft = ( transform: (current: RegionalSurfacePlanDraft) => RegionalSurfacePlanDraft, ) => { setDraft(transform); setError(null); setReadback(null); + setFileStatus(null); setValidationAttempted(false); }; const updateRegion = (index: number, value: RegionalOverlayDraft) => @@ -152,7 +163,7 @@ export function RegionalSurfacePlanPanel() { const validate = () => { setValidationAttempted(true); try { - const request = buildGroundRegionalSurfacePlanRequest(draft); + const request = regionalSurfacePlanRequestForDraft(draft, importedRequest); setError(null); setReadback( `${request.schema_version} · ${request.unit_system} · ` + @@ -165,6 +176,35 @@ export function RegionalSurfacePlanPanel() { setError(caught instanceof Error ? caught.message : "Surface plan is invalid"); } }; + const importFile = async (event: ChangeEvent) => { + const file = event.currentTarget.files?.[0]; + event.currentTarget.value = ""; + if (file === undefined) return; + try { + const request = await readRegionalSurfacePlanFile(file); + const importedDraft = editorDraftFromGroundRegionalSurfacePlanRequest(request); + setDraft(importedDraft); + setImportedRequest(request); + setValidationAttempted(false); + setError(null); + setReadback(`${request.schema_version} · exact imported provenance ${request.provenance.input_sha256}`); + setFileStatus(`Imported ${file.name}. No physics executed.`); + } catch (caught) { + setError(caught instanceof Error ? caught.message : "Regional plan import failed"); + setFileStatus("Import failed; the editor and prior validated readback were preserved."); + } + }; + const download = () => { + try { + const request = regionalSurfacePlanRequestForDraft(draft, importedRequest); + downloadRegionalSurfacePlanRequest(request); + setError(null); + setFileStatus("Download prepared. Your browser controls the destination and overwrite behavior."); + } catch (caught) { + setError(caught instanceof Error ? caught.message : "Regional plan download failed"); + setFileStatus("Download failed; no browser filesystem state was changed."); + } + }; return (
@@ -181,7 +221,8 @@ export function RegionalSurfacePlanPanel() { This slice validates a material plan only; it does not run physics or playback.

- Session-only draft: the current web workspace adapter does not persist model inputs. + Import/download persists this canonical request only; workspace persistence remains separate. + Browser downloads cannot promise a native path, atomic replacement, or recent-file access.

Plan identity and provenance @@ -242,6 +283,9 @@ export function RegionalSurfacePlanPanel() { }))} /> ))}
+ { void importFile(event); }} /> + +
); } diff --git a/src/rate_of_closure/web/src/model/capabilityObservationEnsemble.test.ts b/src/rate_of_closure/web/src/model/capabilityObservationEnsemble.test.ts index eb5b1311d..b5f399327 100644 --- a/src/rate_of_closure/web/src/model/capabilityObservationEnsemble.test.ts +++ b/src/rate_of_closure/web/src/model/capabilityObservationEnsemble.test.ts @@ -294,6 +294,7 @@ describe("capability observation wire parity", () => { row.parameters = [ { parameterId: "half", unit: "1", nominalValue: 1.000000000005, perturbedValue: -1.000000000005 }, { parameterId: "tiny", unit: "1", nominalValue: -0, perturbedValue: 0.0000001 }, + { parameterId: "threshold", unit: "1", nominalValue: 1e20, perturbedValue: 1e-11 }, { parameterId: "large", unit: "1", nominalValue: 1e21, perturbedValue: 1e-12 }, ]; }); @@ -302,6 +303,8 @@ describe("capability observation wire parity", () => { expect(json).toContain('"perturbed.half":-1.00000000001'); expect(json).toContain('"nominal.tiny":0'); expect(json).toContain('"perturbed.tiny":0.0000001'); + expect(json).toContain('"nominal.threshold":100000000000000000000'); + expect(json).toContain('"perturbed.threshold":0.00000000001'); expect(json).toContain('"nominal.large":1000000000000000000000'); expect(json).toContain('"perturbed.large":0'); expect(json).not.toMatch(/"(?:nominal|perturbed)\.[^"]+":"/); diff --git a/src/rate_of_closure/web/src/model/regionalSurfacePlan.ts b/src/rate_of_closure/web/src/model/regionalSurfacePlan.ts index 33301feeb..a52cdc0d3 100644 --- a/src/rate_of_closure/web/src/model/regionalSurfacePlan.ts +++ b/src/rate_of_closure/web/src/model/regionalSurfacePlan.ts @@ -6,6 +6,7 @@ import { GROUND_REGIONAL_PLAN_REQUEST_VERSION, parseGroundRegionalMaterialPlanRequest, type GroundRegionalMaterialPlanRequest, + type GroundRegionalMaterialRegion, } from "./groundRegionalPlan"; import { GROUND_TARGET_FRAME, type GroundSurfaceProfile } from "./flightGroundTypes"; import { canonicalGroundJson } from "./flightGroundContract"; @@ -106,6 +107,70 @@ const surfacePayload = (surface: SurfaceMaterialDraft): GroundSurfaceProfile => surface_velocity_m_s: [0, 0, 0], }); +const surfaceDraft = (surface: GroundSurfaceProfile): SurfaceMaterialDraft => ({ + surface_id: surface.surface_id, + normal_restitution: surface.normal_restitution, + static_friction: surface.static_friction, + kinetic_friction: surface.kinetic_friction, + rolling_resistance: surface.rolling_resistance, + firmness_pa: surface.firmness_pa, + hardness_fraction: surface.hardness_fraction, + grass_height_m: surface.grass_height_m, + compressibility_fraction: surface.compressibility_fraction, + compression_damping_fraction: surface.compression_damping_fraction, + turf_density_kg_m3: surface.turf_density_kg_m3, + moisture_fraction: surface.moisture_fraction, +}); + +const assertEditorSurface = (surface: GroundSurfaceProfile): void => { + if (surface.provider_id !== REGIONAL_SURFACE_EDITOR_PROVIDER || + surface.provider_version !== REGIONAL_SURFACE_EDITOR_VERSION) { + throw new RangeError("surface is not qualified by the editor provider v1"); + } +}; + +const overlayDraft = (region: GroundRegionalMaterialRegion): RegionalOverlayDraft => ({ + region_id: region.region_id, + precedence: region.precedence, + lower_coordinate_m: region.lower_coordinate_m, + upper_coordinate_m: region.upper_coordinate_m, + surface: surfaceDraft(region.surface), +}); + +/** Project a fully validated editor-v1 request without relabelling evidence. */ +export const editorDraftFromGroundRegionalSurfacePlanRequest = ( + request: GroundRegionalMaterialPlanRequest, +): RegionalSurfacePlanDraft => { + if (request.provenance.producer !== REGIONAL_SURFACE_EDITOR_PROVIDER || + request.provenance.producer_version !== REGIONAL_SURFACE_EDITOR_VERSION) { + throw new RangeError("request is not qualified by the editor producer v1"); + } + if (canonicalGroundJson(request.axis_origin_m) !== "[0,0,0]" || + canonicalGroundJson(request.axis_unit) !== "[1,0,0]") { + throw new RangeError("request uses an unsupported editor axis qualification"); + } + if (request.regions.length > MAX_REGIONAL_SURFACE_EDITOR_ROWS) { + throw new RangeError( + `editor supports one to at most ${MAX_REGIONAL_SURFACE_EDITOR_ROWS} regions`, + ); + } + assertEditorSurface(request.base_surface); + request.regions.forEach((region) => assertEditorSurface(region.surface)); + const draft: RegionalSurfacePlanDraft = { + request_id: request.request_id, + lower_coordinate_m: request.lower_coordinate_m, + upper_coordinate_m: request.upper_coordinate_m, + source_revision: request.provenance.source_revision, + calibration_kind: "unvalidated", + base_surface: surfaceDraft(request.base_surface), + regions: request.regions.map(overlayDraft), + }; + if (request.provenance.input_sha256 !== sha256Text(canonicalGroundJson(draft))) { + throw new RangeError("editor provenance digest does not match the editable request"); + } + return draft; +}; + export const buildGroundRegionalSurfacePlanRequest = ( draft: RegionalSurfacePlanDraft, ): GroundRegionalMaterialPlanRequest => { @@ -145,3 +210,17 @@ export const buildGroundRegionalSurfacePlanRequest = ( schema_version: GROUND_REGIONAL_PLAN_REQUEST_VERSION, }); }; + +/** Keep untouched imported evidence exact; bind fresh provenance after edits. */ +export const regionalSurfacePlanRequestForDraft = ( + draft: RegionalSurfacePlanDraft, + importedRequest: GroundRegionalMaterialPlanRequest | null = null, +): GroundRegionalMaterialPlanRequest => { + if (importedRequest !== null) { + const importedDraft = editorDraftFromGroundRegionalSurfacePlanRequest(importedRequest); + if (canonicalGroundJson(draft) === canonicalGroundJson(importedDraft)) { + return importedRequest; + } + } + return buildGroundRegionalSurfacePlanRequest(draft); +}; diff --git a/src/rate_of_closure/web/src/model/regionalSurfacePlanFiles.ts b/src/rate_of_closure/web/src/model/regionalSurfacePlanFiles.ts new file mode 100644 index 000000000..2ed7359b7 --- /dev/null +++ b/src/rate_of_closure/web/src/model/regionalSurfacePlanFiles.ts @@ -0,0 +1,40 @@ +/** Browser-only strict import/download boundary for regional plan requests. */ + +import { + MAX_GROUND_REGIONAL_PLAN_WIRE_BYTES, + groundRegionalMaterialPlanRequestFromJson, + stableGroundRegionalMaterialPlanJson, + type GroundRegionalMaterialPlanRequest, +} from "./groundRegionalPlan"; + +export interface RegionalPlanFile { + readonly name: string; + readonly size: number; + text(): Promise; +} + +export const readRegionalSurfacePlanFile = async ( + file: RegionalPlanFile, +): Promise => { + if (file.size > MAX_GROUND_REGIONAL_PLAN_WIRE_BYTES) { + throw new RangeError("regional material plan exceeds maximum wire size"); + } + return groundRegionalMaterialPlanRequestFromJson(await file.text()); +}; + +export const downloadRegionalSurfacePlanRequest = ( + request: GroundRegionalMaterialPlanRequest, +): void => { + const text = stableGroundRegionalMaterialPlanJson(request); + const url = URL.createObjectURL( + new Blob([text], { type: "application/json;charset=utf-8" }), + ); + try { + const anchor = document.createElement("a"); + anchor.href = url; + anchor.download = "regional-surface-plan.json"; + anchor.click(); + } finally { + URL.revokeObjectURL(url); + } +}; diff --git a/src/shared/python/swing_sim/canonical_numeric_json.py b/src/shared/python/swing_sim/canonical_numeric_json.py index 9934a77c1..25d6e69a6 100644 --- a/src/shared/python/swing_sim/canonical_numeric_json.py +++ b/src/shared/python/swing_sim/canonical_numeric_json.py @@ -9,7 +9,7 @@ from typing import Any _FLOAT_QUANTUM = Decimal("0.00000000001") -_MAX_SAFE_INTEGER = 9_007_199_254_740_991 +MAX_CANONICAL_SAFE_INTEGER = 9_007_199_254_740_991 def _string_token(value: str) -> str: @@ -18,9 +18,11 @@ def _string_token(value: str) -> str: return json.dumps(value, ensure_ascii=False) -def _canonical_float_token(value: float) -> str: +def _canonical_float_token(value: float, *, allow_extended_finite: bool = False) -> str: if not math.isfinite(value): raise ValueError("canonical JSON requires finite floats") + if not allow_extended_finite and abs(value) > MAX_CANONICAL_SAFE_INTEGER: + raise ValueError("canonical JSON number exceeds cross-runtime safe range") if value == 0 or value.is_integer(): return "0" if value == 0 else str(int(value)) rounded = Decimal.from_float(value).quantize(_FLOAT_QUANTUM, rounding=ROUND_HALF_UP) @@ -34,16 +36,17 @@ def canonical_numeric_float(value: float) -> float: return float(_canonical_float_token(value)) -def canonical_numeric_json(value: Any) -> str: - """Serialize JSON-compatible data with stable fixed-point float tokens.""" +def _canonical_numeric_json(value: Any, *, allow_extended_finite: bool) -> str: if value is None: return "null" if isinstance(value, bool): return "true" if value else "false" if isinstance(value, float): - return _canonical_float_token(value) + return _canonical_float_token( + value, allow_extended_finite=allow_extended_finite + ) if isinstance(value, int): - if abs(value) > _MAX_SAFE_INTEGER: + if abs(value) > MAX_CANONICAL_SAFE_INTEGER: raise ValueError("canonical JSON integer exceeds cross-runtime safe range") return str(value) if isinstance(value, str): @@ -51,14 +54,37 @@ def canonical_numeric_json(value: Any) -> str: if isinstance(value, Mapping): if not all(isinstance(key, str) for key in value): raise TypeError("canonical JSON object keys must be strings") - items = ( - f"{_string_token(key)}:{canonical_numeric_json(value[key])}" - for key in sorted(value) - ) + + def item_token(key: str) -> str: + token = _canonical_numeric_json( + value[key], allow_extended_finite=allow_extended_finite + ) + return f"{_string_token(key)}:{token}" + + items = (item_token(key) for key in sorted(value)) return "{" + ",".join(items) + "}" if isinstance(value, (list, tuple)): - return "[" + ",".join(canonical_numeric_json(item) for item in value) + "]" + items = ( + _canonical_numeric_json(item, allow_extended_finite=allow_extended_finite) + for item in value + ) + return "[" + ",".join(items) + "]" raise TypeError(f"unsupported canonical JSON value: {type(value).__name__}") -__all__ = ["canonical_numeric_float", "canonical_numeric_json"] +def canonical_numeric_json(value: Any) -> str: + """Serialize JSON-compatible data within the shared runtime-safe range.""" + return _canonical_numeric_json(value, allow_extended_finite=False) + + +def canonical_numeric_json_extended_floats(value: Any) -> str: + """Serialize finite floats beyond the safe range while retaining safe integers.""" + return _canonical_numeric_json(value, allow_extended_finite=True) + + +__all__ = [ + "MAX_CANONICAL_SAFE_INTEGER", + "canonical_numeric_float", + "canonical_numeric_json", + "canonical_numeric_json_extended_floats", +] diff --git a/src/shared/python/swing_sim/ground/contract_types.py b/src/shared/python/swing_sim/ground/contract_types.py index 1844ddb68..deb2979e1 100644 --- a/src/shared/python/swing_sim/ground/contract_types.py +++ b/src/shared/python/swing_sim/ground/contract_types.py @@ -6,7 +6,10 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Any, TypeAlias -from shared.python.swing_sim.canonical_numeric_json import canonical_numeric_float +from shared.python.swing_sim.canonical_numeric_json import ( + MAX_CANONICAL_SAFE_INTEGER, + canonical_numeric_float, +) if TYPE_CHECKING: from enum import StrEnum @@ -18,7 +21,6 @@ UNIT_SYSTEM_SI = "SI" Vector3: TypeAlias = tuple[float, float, float] _UNIT_TOLERANCE = 1e-9 -_MAX_SAFE_INTEGER = 9_007_199_254_740_991 _MIN_CANONICAL_POSITIVE = 0.00000000001 _TEXT_EDGE_WHITESPACE = " \t\r\n\f\v" @@ -29,6 +31,8 @@ def _raw_finite(value: float, name: str) -> float: number = float(value) if not math.isfinite(number): raise ValueError(f"{name} must be finite") + if abs(number) > MAX_CANONICAL_SAFE_INTEGER: + raise ValueError(f"{name} must lie within the cross-runtime safe range") return number @@ -67,10 +71,10 @@ def _integer(value: int | float, name: str, minimum: int = 0) -> int: normalized = int(value) else: raise ValueError(f"{name} must be an integer") - if not minimum <= normalized <= _MAX_SAFE_INTEGER: + if not minimum <= normalized <= MAX_CANONICAL_SAFE_INTEGER: raise ValueError( f"{name} must lie within cross-runtime safe range " - f"[{minimum}, {_MAX_SAFE_INTEGER}]" + f"[{minimum}, {MAX_CANONICAL_SAFE_INTEGER}]" ) return normalized diff --git a/src/shared/python/swing_sim/ground/tests/test_contract_api.py b/src/shared/python/swing_sim/ground/tests/test_contract_api.py index 8c9815c96..fee25b250 100644 --- a/src/shared/python/swing_sim/ground/tests/test_contract_api.py +++ b/src/shared/python/swing_sim/ground/tests/test_contract_api.py @@ -178,6 +178,10 @@ def test_cross_runtime_integer_and_text_edges_fail_closed() -> None: replace(_request(), max_events=10**1000) with pytest.raises(ValueError, match="safe range"): canonical_numeric_json(unsafe_integer) + with pytest.raises(ValueError, match="safe range"): + canonical_numeric_json(float(unsafe_integer)) + with pytest.raises(ValueError, match="safe range"): + replace(_surface(), firmness_pa=float(unsafe_integer)) with pytest.raises(ValueError, match="surrogate"): replace(_request(), request_id="\ud800") with pytest.raises(ValueError, match="surrogate"): diff --git a/tests/rate_of_closure/test_capability_observation_adapter.py b/tests/rate_of_closure/test_capability_observation_adapter.py index 24c63c50c..440286866 100644 --- a/tests/rate_of_closure/test_capability_observation_adapter.py +++ b/tests/rate_of_closure/test_capability_observation_adapter.py @@ -262,6 +262,7 @@ def test_stable_wire_uses_canonical_numeric_tokens_for_every_float() -> None: CapabilitySampleParameter("positive_half", "1", 1.234567890125, 1e-12), CapabilitySampleParameter("negative_half", "1", -1.234567890125, -0.0), CapabilitySampleParameter("threshold", "1", 1e-11, 1e20), + CapabilitySampleParameter("large", "1", 1e21, 1e-12), CapabilitySampleParameter( "half_away", "1", 1.000000000005, -1.000000000005 ), @@ -278,6 +279,8 @@ def test_stable_wire_uses_canonical_numeric_tokens_for_every_float() -> None: assert row_values["perturbed.negative_half"] == 0 assert row_values["nominal.threshold"] == 0.00000000001 assert row_values["perturbed.threshold"] == 100000000000000000000 + assert row_values["nominal.large"] == 1000000000000000000000 + assert row_values["perturbed.large"] == 0 assert row_values["nominal.half_away"] == 1.00000000001 assert row_values["perturbed.half_away"] == -1.00000000001 assert all( @@ -287,6 +290,8 @@ def test_stable_wire_uses_canonical_numeric_tokens_for_every_float() -> None: ) assert '"nominal.threshold":0.00000000001' in payload assert '"perturbed.threshold":100000000000000000000' in payload + assert '"nominal.large":1000000000000000000000' in payload + assert "e+21" not in payload def test_parameter_labels_only_uppercase_initial_ascii_letters() -> None: @@ -321,3 +326,8 @@ def test_parameter_labels_only_uppercase_initial_ascii_letters() -> None: def test_canonical_numeric_json_rejects_nonfinite_values(value: float) -> None: with pytest.raises(ValueError, match="finite floats"): canonical_numeric_json({"value": value}) + + +def test_capability_extended_float_policy_keeps_integer_safe_range() -> None: + with pytest.raises(ValueError, match="integer.*safe range"): + canonical_numeric_json({"value": 9_007_199_254_740_992}) diff --git a/tests/rate_of_closure/test_regional_surface_plan.py b/tests/rate_of_closure/test_regional_surface_plan.py index 966ea2eb6..814c52eaa 100644 --- a/tests/rate_of_closure/test_regional_surface_plan.py +++ b/tests/rate_of_closure/test_regional_surface_plan.py @@ -4,6 +4,7 @@ from dataclasses import replace from inspect import signature +from pathlib import Path import pytest @@ -12,10 +13,55 @@ illustrative_regional_surface_plan_draft, validate_regional_surface_plan_draft, ) +from shared.python.swing_sim.canonical_numeric_json import ( + MAX_CANONICAL_SAFE_INTEGER, +) pytestmark = [pytest.mark.unit, pytest.mark.headless_safe] +def test_pyqt_number_input_spec_preserves_behavior_and_structural_bound(qtbot) -> None: # type: ignore[no-untyped-def] + pytest.importorskip("PyQt6") + pytest.importorskip("pytestqt") + from rate_of_closure.ui.pyqt6.engineering_number_input import ( + NumberInputSpec, + engineering_number_input, + ) + + spec = NumberInputSpec( + suffix=" m", + step=0.25, + minimum=-2.0, + maximum=3.0, + decimals=11, + ) + field = engineering_number_input("Test coordinate", 1.5, spec) + qtbot.addWidget(field) + + assert NumberInputSpec.__dataclass_params__.frozen is True + assert len(signature(engineering_number_input).parameters) <= 4 + assert field.accessibleName() == "Test coordinate" + assert field.value() == pytest.approx(1.5) + assert field.suffix() == " m" + assert field.singleStep() == pytest.approx(0.25) + assert field.minimum() == pytest.approx(-2.0) + assert field.maximum() == pytest.approx(3.0) + assert field.decimals() == 11 + assert "Test coordinate" in field.toolTip() + + +def test_pyqt_number_input_spec_rejects_invalid_configuration() -> None: + pytest.importorskip("PyQt6") + from rate_of_closure.ui.pyqt6.engineering_number_input import NumberInputSpec + + with pytest.raises(ValueError, match="step must be finite and positive"): + NumberInputSpec(suffix="", step=0.0, minimum=0.0, maximum=1.0) + with pytest.raises(ValueError, match="minimum must not exceed maximum"): + NumberInputSpec(suffix="", step=0.1, minimum=2.0, maximum=1.0) + with pytest.raises(ValueError, match="decimals must be an integer"): + NumberInputSpec(decimals=True) + + def test_illustrative_draft_delegates_to_regional_wire_contract() -> None: draft = illustrative_regional_surface_plan_draft() @@ -64,39 +110,6 @@ def test_editor_region_limit_fails_before_wire_construction() -> None: validate_regional_surface_plan_draft(replace(draft, regions=repeated)) -def test_pyqt_number_input_spec_preserves_behavior_and_structural_bound(qtbot) -> None: # type: ignore[no-untyped-def] - pytest.importorskip("PyQt6") - pytest.importorskip("pytestqt") - from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import ( - NumberInputSpec, - _number_input, - ) - - spec = NumberInputSpec(suffix=" m", step=0.25, minimum=-2.0, maximum=3.0) - field = _number_input("Test coordinate", 1.5, spec) - qtbot.addWidget(field) - - assert NumberInputSpec.__dataclass_params__.frozen is True - assert len(signature(_number_input).parameters) <= 4 - assert field.accessibleName() == "Test coordinate" - assert field.value() == pytest.approx(1.5) - assert field.suffix() == " m" - assert field.singleStep() == pytest.approx(0.25) - assert field.minimum() == pytest.approx(-2.0) - assert field.maximum() == pytest.approx(3.0) - assert "Test coordinate" in field.toolTip() - - -def test_pyqt_number_input_spec_rejects_invalid_configuration() -> None: - pytest.importorskip("PyQt6") - from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import NumberInputSpec - - with pytest.raises(ValueError, match="step must be finite and positive"): - NumberInputSpec(suffix="", step=0.0, minimum=0.0, maximum=1.0) - with pytest.raises(ValueError, match="minimum must not exceed maximum"): - NumberInputSpec(suffix="", step=0.1, minimum=2.0, maximum=1.0) - - def test_pyqt_editor_exposes_warnings_units_and_validated_readback(qtbot) -> None: # type: ignore[no-untyped-def] pytest.importorskip("PyQt6") pytest.importorskip("pytestqt") @@ -155,3 +168,162 @@ def test_pyqt_editor_invalidates_validated_readback_after_draft_change(qtbot) -> assert tab.readback.toPlainText() == "" assert tab.status_label.text() == "Changes not validated" + + +def test_pyqt_open_applies_only_a_fully_valid_editor_request( + qtbot, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: # type: ignore[no-untyped-def] + pytest.importorskip("PyQt6") + from rate_of_closure.ui.pyqt6 import regional_surface_plan_io + from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import ( + RegionalSurfacePlanTab, + ) + + request = validate_regional_surface_plan_draft( + replace(illustrative_regional_surface_plan_draft(), request_id="opened-plan") + ) + target = tmp_path / "opened.json" + target.write_text(request.to_json(), encoding="utf-8") + monkeypatch.setattr( + regional_surface_plan_io.QFileDialog, + "getOpenFileName", + lambda *_args: (str(target), "JSON files (*.json)"), + ) + tab = RegionalSurfacePlanTab() + qtbot.addWidget(tab) + + tab.open_button.click() + + assert tab.request_id.text() == "opened-plan" + assert tab.file_actions.recent_path == target + assert "opened" in tab.status_label.text().lower() + assert tab.readback.toPlainText() == request.to_json() + + +def test_pyqt_failed_open_rolls_back_editor_and_recent_path( + qtbot, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: # type: ignore[no-untyped-def] + pytest.importorskip("PyQt6") + from rate_of_closure.ui.pyqt6 import regional_surface_plan_io + from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import ( + RegionalSurfacePlanTab, + ) + + target = tmp_path / "corrupt.json" + target.write_text('{"request_id":"one","request_id":"two"}', encoding="utf-8") + monkeypatch.setattr( + regional_surface_plan_io.QFileDialog, + "getOpenFileName", + lambda *_args: (str(target), "JSON files (*.json)"), + ) + tab = RegionalSurfacePlanTab() + qtbot.addWidget(tab) + before = tab.draft() + + tab.open_button.click() + + assert tab.draft() == before + assert tab.file_actions.recent_path is None + assert "open failed" in tab.status_label.text().lower() + assert tab.status_label.accessibleName() == "Regional surface plan file error" + + +def test_pyqt_save_as_preserves_imported_request_bytes( + qtbot, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: # type: ignore[no-untyped-def] + pytest.importorskip("PyQt6") + from rate_of_closure.ui.pyqt6 import regional_surface_plan_io + from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import ( + RegionalSurfacePlanTab, + ) + + draft = illustrative_regional_surface_plan_draft() + request = validate_regional_surface_plan_draft( + replace( + draft, + request_id="saved-plan", + regions=(replace(draft.regions[0], precedence=MAX_CANONICAL_SAFE_INTEGER),), + ) + ) + source = tmp_path / "source.json" + destination = tmp_path / "copy.json" + source.write_text(request.to_json(), encoding="utf-8") + choices = iter(((str(source), "JSON files (*.json)"),)) + monkeypatch.setattr( + regional_surface_plan_io.QFileDialog, + "getOpenFileName", + lambda *_args: next(choices), + ) + monkeypatch.setattr( + regional_surface_plan_io.QFileDialog, + "getSaveFileName", + lambda *_args: (str(destination), "JSON files (*.json)"), + ) + tab = RegionalSurfacePlanTab() + qtbot.addWidget(tab) + + tab.open_button.click() + tab.save_button.click() + + assert destination.read_bytes() == source.read_bytes() + assert tab.file_actions.recent_path == destination + assert tab.current_request() == request + + +def test_pyqt_import_preserves_canonical_precision_and_large_si_values( + qtbot, +) -> None: # type: ignore[no-untyped-def] + pytest.importorskip("PyQt6") + from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import ( + RegionalSurfacePlanTab, + ) + + draft = illustrative_regional_surface_plan_draft() + request = validate_regional_surface_plan_draft( + replace( + draft, + upper_coordinate_m=1_000_000_000_000.0, + base_surface=replace( + draft.base_surface, + firmness_pa=0.00000000001, + grass_height_m=123.12345678901, + turf_density_kg_m3=20_000.12345678901, + ), + ) + ) + tab = RegionalSurfacePlanTab() + qtbot.addWidget(tab) + + tab.apply_imported_request(request) + + assert tab.current_request() is request + + +def test_pyqt_cancelled_open_and_save_leave_status_and_recent_unchanged( + qtbot, monkeypatch: pytest.MonkeyPatch +) -> None: # type: ignore[no-untyped-def] + pytest.importorskip("PyQt6") + from rate_of_closure.ui.pyqt6 import regional_surface_plan_io + from rate_of_closure.ui.pyqt6.regional_surface_plan_tab import ( + RegionalSurfacePlanTab, + ) + + monkeypatch.setattr( + regional_surface_plan_io.QFileDialog, + "getOpenFileName", + lambda *_args: ("", ""), + ) + monkeypatch.setattr( + regional_surface_plan_io.QFileDialog, + "getSaveFileName", + lambda *_args: ("", ""), + ) + tab = RegionalSurfacePlanTab() + qtbot.addWidget(tab) + status = tab.status_label.text() + + tab.open_button.click() + tab.save_button.click() + + assert tab.status_label.text() == status + assert tab.file_actions.recent_path is None diff --git a/tests/rate_of_closure/test_regional_surface_plan_io.py b/tests/rate_of_closure/test_regional_surface_plan_io.py new file mode 100644 index 000000000..0beb0c557 --- /dev/null +++ b/tests/rate_of_closure/test_regional_surface_plan_io.py @@ -0,0 +1,190 @@ +"""Canonical regional surface-plan import/export boundary tests.""" + +from __future__ import annotations + +from dataclasses import replace +from pathlib import Path + +import pytest + +from rate_of_closure.application.regional_surface_plan import ( + EDITOR_PROVIDER_ID, + editor_draft_from_regional_surface_plan_request, + illustrative_regional_surface_plan_draft, + regional_surface_plan_request_for_draft, + validate_regional_surface_plan_draft, +) +from rate_of_closure.application.regional_surface_plan_files import ( + read_regional_surface_plan_request, + write_regional_surface_plan_request_atomic, +) +from shared.python.swing_sim.ground.regional_plan_records import ( + MAX_REGIONAL_PLAN_WIRE_BYTES, +) +from shared.python.swing_sim.ground.regional_plan_wire import ( + regional_material_plan_request_from_dict, +) + +pytestmark = [pytest.mark.unit, pytest.mark.headless_safe] + + +def test_editor_request_file_round_trip_is_exact_and_deterministic( + tmp_path: Path, +) -> None: + request = validate_regional_surface_plan_draft( + illustrative_regional_surface_plan_draft() + ) + target = tmp_path / "regional-plan.json" + + assert write_regional_surface_plan_request_atomic(request, target) + + assert target.read_bytes() == request.to_json().encode("utf-8") + loaded = read_regional_surface_plan_request(target) + assert loaded == request + imported = editor_draft_from_regional_surface_plan_request(loaded) + assert regional_surface_plan_request_for_draft(imported, loaded) == request + + +def test_cancelled_request_write_is_a_no_op(tmp_path: Path) -> None: + request = validate_regional_surface_plan_draft( + illustrative_regional_surface_plan_draft() + ) + + assert write_regional_surface_plan_request_atomic(request, None) is False + assert list(tmp_path.iterdir()) == [] + + +def test_request_replace_failure_preserves_last_known_good( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + from rate_of_closure.application import atomic_text_files + + request = validate_regional_surface_plan_draft( + illustrative_regional_surface_plan_draft() + ) + target = tmp_path / "regional-plan.json" + target.write_text("last-known-good", encoding="utf-8") + monkeypatch.setattr( + atomic_text_files.os, + "replace", + lambda _source, _target: (_ for _ in ()).throw(OSError("replace failed")), + ) + + with pytest.raises(OSError, match="replace failed"): + write_regional_surface_plan_request_atomic(request, target) + + assert target.read_text(encoding="utf-8") == "last-known-good" + assert not list(tmp_path.glob(".*.tmp")) + + +@pytest.mark.parametrize( + "text, message", + [ + ("{not-json", "JSON"), + ('{"request_id":"one","request_id":"two"}', "[Dd]uplicate"), + (" " * (MAX_REGIONAL_PLAN_WIRE_BYTES + 1), "maximum wire size"), + ], + ids=("corrupt", "duplicate", "oversize"), +) +def test_request_read_rejects_corruption_duplicates_and_oversize( + tmp_path: Path, text: str, message: str +) -> None: + target = tmp_path / "invalid.json" + target.write_text(text, encoding="utf-8") + + with pytest.raises((TypeError, ValueError), match=message): + read_regional_surface_plan_request(target) + + +def test_request_read_bounds_a_file_that_grows_after_metadata_check( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + target = tmp_path / "growing.json" + target.write_bytes(b"{}") + requested_sizes: list[int] = [] + + class GrowingBinaryFile: + def __enter__(self) -> GrowingBinaryFile: + return self + + def __exit__(self, *_args: object) -> None: + return None + + def read(self, size: int) -> bytes: + requested_sizes.append(size) + return b" " * size + + monkeypatch.setattr( + Path, + "read_text", + lambda *_args, **_kwargs: pytest.fail("unbounded read_text used"), + ) + monkeypatch.setattr(Path, "open", lambda *_args, **_kwargs: GrowingBinaryFile()) + + with pytest.raises(ValueError, match="maximum wire size"): + read_regional_surface_plan_request(target) + + assert requested_sizes == [MAX_REGIONAL_PLAN_WIRE_BYTES + 1] + + +def test_request_read_rejects_invalid_utf8(tmp_path: Path) -> None: + target = tmp_path / "invalid-utf8.json" + target.write_bytes(b"\xff") + + with pytest.raises(ValueError, match="UTF-8"): + read_regional_surface_plan_request(target) + + +def test_import_rejects_non_editor_provenance_without_coercion() -> None: + request = validate_regional_surface_plan_draft( + illustrative_regional_surface_plan_draft() + ) + payload = request.to_dict() + payload["provenance"]["producer"] = "external.course.authority" + external = regional_material_plan_request_from_dict(payload) + + with pytest.raises(ValueError, match="editor producer"): + editor_draft_from_regional_surface_plan_request(external) + + payload = request.to_dict() + payload["provenance"]["input_sha256"] = "0" * 64 + mismatched = regional_material_plan_request_from_dict(payload) + with pytest.raises(ValueError, match="digest does not match"): + editor_draft_from_regional_surface_plan_request(mismatched) + + +def test_import_rejects_editor_provider_with_unsupported_axis() -> None: + request = validate_regional_surface_plan_draft( + illustrative_regional_surface_plan_draft() + ) + payload = request.to_dict() + payload["axis_unit"] = [0.0, 0.0, 1.0] + rotated = regional_material_plan_request_from_dict(payload) + + with pytest.raises(ValueError, match="axis qualification"): + editor_draft_from_regional_surface_plan_request(rotated) + + +def test_edited_import_rebinds_provenance_instead_of_reusing_stale_digest() -> None: + request = validate_regional_surface_plan_draft( + illustrative_regional_surface_plan_draft() + ) + imported = editor_draft_from_regional_surface_plan_request(request) + edited = replace(imported, request_id="edited-plan") + + rebound = regional_surface_plan_request_for_draft(edited, request) + + assert rebound.request_id == "edited-plan" + assert rebound.provenance.producer == EDITOR_PROVIDER_ID + assert rebound.provenance.input_sha256 != request.provenance.input_sha256 + + +def test_editor_rejects_unsafe_integer_valued_number() -> None: + draft = illustrative_regional_surface_plan_draft() + unsafe = replace( + draft, + base_surface=replace(draft.base_surface, firmness_pa=10_000_000_000_000_000.0), + ) + + with pytest.raises(ValueError, match="cross-runtime safe range"): + validate_regional_surface_plan_draft(unsafe) diff --git a/tests/rate_of_closure/test_workspace_files.py b/tests/rate_of_closure/test_workspace_files.py index a7dcd85d3..5e260af4a 100644 --- a/tests/rate_of_closure/test_workspace_files.py +++ b/tests/rate_of_closure/test_workspace_files.py @@ -70,13 +70,15 @@ def fail_serialization(_document: WorkspaceDocument) -> str: def test_replace_failure_preserves_existing_and_removes_temporary_file( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: + from rate_of_closure.application import atomic_text_files + target = tmp_path / "showcase.json" target.write_text("last-known-good", encoding="utf-8") def fail_replace(_source: str | Path, _target: str | Path) -> None: raise OSError("replace failed") - monkeypatch.setattr(workspace_files.os, "replace", fail_replace) + monkeypatch.setattr(atomic_text_files.os, "replace", fail_replace) with pytest.raises(OSError, match="replace failed"): workspace_files.write_workspace_atomic(_document("New"), target)