Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions AGENT_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,52 @@
# AGENT_HANDOFF — Tools

## 2026-08-11 Capability-request workspace continuation

Draft PR [#4348](https://github.com/D-sorganization/Tools/pull/4348) publishes
this bounded child from independently approved implementation head
`5730e74752ffb84ab3560bed6318b7d97b6e627d`, with base
`feat/4144-workspace-variation-study` unchanged. Protected current-head CI,
review, parent landing, integration, and release remain required.

The remaining independent no-publish blocker on local head `68692bbcb` is
repaired in this child. Interactive projection now accepts only
the exact ordered `ball_speed` (`m/s`), `launch_angle` (`deg`), and
`launch_direction` (`deg`) basis with one 3-by-3 correlation matrix, one club,
and one spin default. `mph`, covariance, reordered parameters, and unsupported
shapes fail closed before projection, panel/tab apply, or whole-File mutation;
there is no implicit conversion or covariance rescaling.

The prior repair makes both clients retain the complete validated workflow
and overlay only editable controls, preserving accepted evidence and advanced
request policy. Unsupported interactive shapes fail closed. PyQt worker
identity plus generation gates reject late success from cancelled replaced
runs. The shared hostile fixture caps numeric wire magnitude at `1e300`, and
Python overflow follows the normal validation and File/Open rollback path.

Branch `feat/4197-workspace-capability-request` starts from exact published PR
#4343 head `4ff103d9a6ef886099c180da560e8458d5e20b49`.
Explorer-session v5 embeds the existing strict
`capability-optimization-workflow/v1` input document in PyQt6 and React. It
persists the user-authored profile/club, capability bounds and distributions,
objective, target, fixed-spin evaluator assumptions, integration settings,
budgets, and deterministic seed. It stores no computed result, observation
ensemble, worker/runtime object, or identity beyond user-authored stable IDs.

Both clients validate the complete file before live mutation. PyQt6 applies
inside the existing rollback boundary; React lifts the full workflow document
to app workspace authority and invalidates stale results when a workspace
replaces it. Legacy v1-v4 sessions require an explicit current capability
fallback,
so migration cannot invent an optimizer request. This is bounded #4197/#4225
input-specification parity only: it does not claim optimizer execution parity,
wind-aware optimization, saved results, UpstreamDrift qualification, protected
CI/review, integration, or issue completion. The branch must remain local until
the parent stack explicitly authorizes publication. Local qualification passes
71 focused Python workflow/workspace/File/PyQt/manifest tests and 70 focused React
contract/File/UI tests; pinned MyPy, Ruff check/format, TypeScript,
zero-warning ESLint, the 211-module production build, 11 campaign-manifest
tests, docs governance, and manifest-layout validation also pass.

## 2026-08-11 variation-study workspace protected publication

Branch `feat/4144-workspace-variation-study` is published normally as draft PR
Expand Down
42 changes: 42 additions & 0 deletions docs/development/RATE_OF_CLOSURE_CAMPAIGN_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
# Rate of Closure Ball-Flight Campaign Handoff

## 2026-08-11 Capability input specification in whole workspaces

- Draft PR [#4348](https://github.com/D-sorganization/Tools/pull/4348)
publishes this bounded child from independently approved implementation head
`5730e74752ffb84ab3560bed6318b7d97b6e627d`, preserving base
`feat/4144-workspace-variation-study`. Protected current-head CI, review,
parent landing, integration, and release remain required.

- The remaining no-publish finding against local head `68692bbcb` is repaired
locally. Interactive projection requires the exact ordered `ball_speed`
(`m/s`), `launch_angle` (`deg`), and `launch_direction` (`deg`) basis with a
3-by-3 correlation matrix, one club, and one spin default. Alternate units,
covariance, reordered parameters, and unsupported shapes fail closed before
projection, UI apply, or File/Open mutation; no conversion/rescaling occurs.
- Earlier findings are also repaired: full-document authority plus editable overlays preserve accepted
evidence and advanced policy; unsupported interactive documents fail closed.
Native identity/generation gates reject stale success, and both parsers cap
numeric wire magnitude at `1e300` through the native File/Open error path.

- Branch `feat/4197-workspace-capability-request` starts from exact draft
PR #4343 head `4ff103d9a6ef886099c180da560e8458d5e20b49`; it does not modify
or publish the parent branch.
- Explorer-session v5 embeds the established cross-runtime
`capability-optimization-workflow/v1` request. PyQt6 and React round-trip the
editable profile/club, capability ranges/distributions, objective, target,
fixed-spin evaluator assumptions, integration policy, budgets, and seed.
- Full parsing precedes application. Both clients retain the full validated
document while controls overlay only represented fields. Legacy v1-v4 files
require an explicit current capability fallback. Native apply is rollback-safe,
and both clients
invalidate computed results when restored inputs replace the live request.
- Results, observation ensembles, runtime objects, inferred identity, and
optimizer-execution claims remain excluded. Wind-aware optimizer inputs are
not yet user-editable in this workflow and therefore are not fabricated.
#4197/#4225, UpstreamDrift parity, protected CI/review, integration, and
release remain open.
- Local qualification passes 71 focused Python workflow/workspace/File/PyQt/
manifest tests and 70 focused React contract/File/UI tests; pinned MyPy, Ruff,
TypeScript, zero-warning ESLint, the 211-module production build, 11
campaign-manifest tests, docs governance, and manifest-layout validation
also pass.

## 2026-08-11 variation-study workspace protected publication

- Branch `feat/4144-workspace-variation-study` is published normally as draft
Expand Down
10 changes: 9 additions & 1 deletion docs/release/rate_of_closure_campaign.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,14 @@
"kind": "repository_path",
"value": "src/rate_of_closure/web/src/model/workspaceVariationSession.ts"
},
{
"kind": "repository_path",
"value": "src/rate_of_closure/application/capability_workflow.py"
},
{
"kind": "repository_path",
"value": "src/rate_of_closure/web/src/model/capabilityWorkflow.ts"
},
{
"kind": "repository_path",
"value": "src/rate_of_closure/view_workspace.py"
Expand Down Expand Up @@ -1045,7 +1053,7 @@
"Unavailable persistence actions remain disabled rather than simulating success.",
"The explorer-session v2 child persists ball support/default provenance and the full canonical spatial target on Tools PyQt6 and React, while legacy v1 migration requires an explicit current-state fallback; protected integration remains open.",
"The explorer-session v3 child locally persists the canonical torque-profile library, source-derived active selection, passive/prescribed run contract, and joint locks on Tools PyQt6 and React; legacy v1/v2 migration is explicit and conflict-safe, while protected integration remains open.",
"The explorer-session v4 child locally persists authored variation inputs, execution policy, deterministic run specification, and selected output focus on Tools PyQt6 and React; browser Open rechecks latest dirty/fallback state, binds parser mode, rejects stale out-of-order reads, and is superseded by confirmed New/Close operations, while native focus controls retain one valid selection and the focus derives from the complete executor output registry without filtering canonical results; results persistence, optimizer outputs, UpstreamDrift consumers, and protected integration remain open.",
"The explorer-session v5 child locally persists authored variation inputs plus the strict capability optimizer input specification on Tools PyQt6 and React. Full-document authority preserves accepted evidence and advanced policy while controls overlay represented fields; interactive projection requires the exact ordered canonical units and a 3-by-3 correlation basis, rejecting alternate units, covariance, and unsupported shapes before mutation without conversion. Stale native workers cannot publish across generations, and oversized numeric wire values fail closed. Capability results, observation ensembles, runtime objects, wind-aware optimizer inputs, UpstreamDrift consumers, and protected integration remain open.",
"Camera tracking, canonical snap views, frame stepping, and Playwright coverage are published through evidence commit 2095e748ddca2d7036bbd49a731528f5634daff9 on draft PR 4298; protected integration remains open.",
"Draft PR 4301 publishes issue 4300 constrained toolstrip-popover containment at immutable evidence commit ebd804ff24e7ce5ca58c7d1495c438ab1dcd83b5 as a child of epic 4218; protected integration remains open.",
"The bounded issue 4224 default-legend rail slice has immutable local evidence at 83b4baa3be7424777db4dd50883b7a9e45c8ca91 on a child of exact PR 4301 head 5c8efcbe5fcd6f993ef947a85e39852d268780a6; installed React qualification passes while persistence/export qualification, native review, and protected integration remain open."
Expand Down
38 changes: 35 additions & 3 deletions docs/specs/CAPABILITY_OPTIMIZATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,54 @@ deterministic search basis. The default document is explicitly representative
and user-authored; it is not presented as measured player data.

The persisted v1 wire contract is strict at every nested primitive. Numeric
fields accept only finite JSON numbers (and integer fields require an integral
number); text fields accept only nonempty JSON strings. Numeric strings,
fields accept only finite JSON numbers with magnitude at most `1e300` (and
integer fields require an integral number); text fields accept only nonempty
JSON strings. Numeric strings,
booleans used as numbers, fractional integer values, and numeric identifiers or
provenance values are rejected in both runtimes. Python and TypeScript execute
one shared versioned accept/reject fixture to prevent parser drift.

Optimization runs outside the UI thread. Progress is based on attempted model
evaluations, cancellation publishes no partial optimization result, and input
changes invalidate captured output. Every attempted sample is retained in
changes invalidate captured output. Native publication also requires matching
worker identity and generation, so a cancelled pre-replacement worker cannot
publish a late success. Every attempted sample is retained in
`scalar-ensemble/v1` with complete, no-impact, or failed cohort identity. The
clients present ranked alternatives, selectable scalar axes, paired-finite and
unavailable counts, managed zoom/autofit, a bounded paged raw table,
spreadsheet-safe lossless CSV, and stable JSON. Duplicate evaluator and target
diagnostic labels are stage-qualified in selectors without changing their
contract keys.

### Whole-Workspace Input Persistence

Explorer-session v5 embeds the exact `capability-optimization-workflow/v1`
document as `model_session.data.capability_request`. The nested document is the
sole cross-runtime schema for this input specification; the workspace does not
duplicate individual optimizer fields. It contains only the profile, request,
target, evaluator configuration, search budgets, and deterministic seed needed
to reproduce a request.

Whole-workspace parsing completes before either UI mutates. PyQt6 applies the
validated request inside the window's rollback boundary, while React retains
the same full document as app-owned state. Both clients overlay only fields
represented by editable controls; accepted provenance, confidence,
correlation, bias, bounds, custom problem policy, target geometry, and spin
provenance survive apply, edit, recapture, save, and reopen exactly. Documents
outside the supported single-club/three-parameter interactive projection fail
closed. Specifically, the interactive basis is exactly `ball_speed` in `m/s`,
`launch_angle` in `deg`, and `launch_direction` in `deg`, in that order, with
one matching 3-by-3 correlation matrix, one club, and one spin default.
Covariance matrices, alternate units such as `mph`, reordered parameters, and
other shapes are rejected before UI mutation; this slice performs no implicit
unit conversion or covariance rescaling. Both clients invalidate previous
computed output. Explorer-session v1-v4 migration requires an explicit current
capability fallback and never invents an optimizer request.
Ranked alternatives, observation ensembles, progress, cancellation/runtime
objects, and inferred player identity are excluded. The current interactive
workflow declares still air and has no editable wind input; workspace restore
must not fabricate wind-aware optimization or execution parity.

## Interpretation And Limitations

- Results are conditional model recommendations, not measured launch-monitor results or guarantees.
Expand Down
45 changes: 45 additions & 0 deletions src/rate_of_closure/AGENT_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
# AGENT_HANDOFF — rate_of_closure

## 2026-08-11 Explorer-session v5 capability-request mapper

Draft PR [#4348](https://github.com/D-sorganization/Tools/pull/4348) publishes
this bounded child from independently approved implementation head
`5730e74752ffb84ab3560bed6318b7d97b6e627d`, preserving base
`feat/4144-workspace-variation-study`. Protected current-head CI, review,
parent landing, integration, and release remain required.

The remaining independent no-publish blocker on local head `68692bbcb` is
repaired locally. PyQt6 and React interactive projection accepts only the exact
ordered `ball_speed` (`m/s`), `launch_angle` (`deg`), and `launch_direction`
(`deg`) basis with one 3-by-3 correlation matrix, one club, and one spin
default. `mph`, covariance, reordered parameters, and unsupported shapes fail
closed before projection, UI apply, or File/Open mutation. No unit conversion
or covariance rescaling is attempted.

The prior repair retains the full validated workflow as live authority
and overlay only editable fields, preserving accepted evidence and advanced
request policy. Unsupported interactive shapes fail closed. Native result
publication now requires matching worker identity and generation. A shared
hostile fixture caps numeric wire magnitude at `1e300`; Python overflow is a
normal validation error covered through whole-window File/Open rollback.

The local child `feat/4197-workspace-capability-request` is based on exact
published PR #4343 head `4ff103d9a6ef886099c180da560e8458d5e20b49`.
PyQt6 and React now persist the same existing
`capability-optimization-workflow/v1` input document through explorer-session
v5: profile/club IDs, the three launch capability bounds and distributions,
objective, target, fixed total-spin/spin-axis assumptions, evaluator time
settings, candidate/trial/alternative budgets, and deterministic seed.

The workspace owns only reproducible request inputs. It deliberately excludes
ranked results, observations, progress, workers, cancellation handles, and
inferred identity. Parsing is strict and precedes mutation. PyQt6 uses the
whole-window rollback boundary and clears result widgets; React moves the full
document to app-owned state and clears stale output after external replacement.
Legacy v1-v4 files require an explicit current capability fallback instead of a
fabricated default. This bounded slice does not claim optimizer execution
parity, wind-aware optimization, result persistence, UpstreamDrift parity,
protected release, or completion of #4197/#4225.
Local qualification passes 71 focused Python workflow/workspace/File/PyQt/
manifest tests and 70 focused React contract/File/UI tests, plus pinned MyPy, Ruff
check/format, TypeScript, zero-warning ESLint, the 211-module production build,
11 campaign-manifest tests, docs governance, and manifest-layout validation.

## 2026-08-11 variation-study workspace protected publication

Branch `feat/4144-workspace-variation-study` is published normally as draft PR
Expand Down
32 changes: 32 additions & 0 deletions src/rate_of_closure/application/capability_interactive_basis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Exact capability basis supported by the current interactive controls."""

from shared.python.swing_sim.flight.capability_contract import ClubCapability

CANONICAL_INTERACTIVE_PARAMETERS = (
("ball_speed", "m/s"),
("launch_angle", "deg"),
("launch_direction", "deg"),
)
_INTERACTIVE_DIMENSION = len(CANONICAL_INTERACTIVE_PARAMETERS)


def validate_capability_interactive_basis(club: ClubCapability) -> None:
"""Reject any basis the controls cannot edit without transformation."""
if club.matrix_kind != "correlation":
raise ValueError("interactive workflow requires a correlation matrix")
actual = tuple((item.parameter_id, item.unit) for item in club.parameters)
if actual != CANONICAL_INTERACTIVE_PARAMETERS:
raise ValueError(
"interactive workflow requires canonical parameter order and units: "
"ball_speed m/s, launch_angle deg, launch_direction deg"
)
if len(club.matrix) != _INTERACTIVE_DIMENSION or any(
len(row) != _INTERACTIVE_DIMENSION for row in club.matrix
):
raise ValueError("interactive workflow requires a 3x3 correlation matrix")


__all__ = [
"CANONICAL_INTERACTIVE_PARAMETERS",
"validate_capability_interactive_basis",
]
26 changes: 25 additions & 1 deletion src/rate_of_closure/application/capability_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@

import json
import math
from collections.abc import Mapping
from dataclasses import dataclass
from typing import Any

from rate_of_closure.application.capability_interactive_basis import (
validate_capability_interactive_basis,
)
from rate_of_closure.application.capability_workflow_wire import (
validate_capability_workflow_wire,
)
Expand Down Expand Up @@ -310,7 +314,16 @@ def capability_workflow_json(document: CapabilityWorkflowDocument) -> str:

def capability_workflow_from_json(source: str) -> CapabilityWorkflowDocument:
"""Parse one exact workflow document and reject unknown fields."""
payload = validate_capability_workflow_wire(json.loads(source))
return capability_workflow_from_wire(json.loads(source))


def capability_workflow_from_wire(
source: Mapping[str, object],
) -> CapabilityWorkflowDocument:
"""Parse one exact in-memory workflow payload without JSON round-tripping."""
if not isinstance(source, Mapping):
raise TypeError("capability workflow must be an object")
payload = validate_capability_workflow_wire(_mutable_wire_value(source))
return CapabilityWorkflowDocument(
PlayerCapabilityProfile.from_dict(payload["profile"]),
OptimizationRequest.from_dict(payload["request"]),
Expand All @@ -319,6 +332,15 @@ def capability_workflow_from_json(source: str) -> CapabilityWorkflowDocument:
)


def _mutable_wire_value(value: object) -> Any:
"""Detach recursively frozen workspace JSON for strict domain validation."""
if isinstance(value, Mapping):
return {key: _mutable_wire_value(item) for key, item in value.items()}
if isinstance(value, tuple):
return [_mutable_wire_value(item) for item in value]
return value


def capability_workflow_inputs(
document: CapabilityWorkflowDocument,
) -> CapabilityWorkflowInputs:
Expand All @@ -331,6 +353,7 @@ def capability_workflow_inputs(
"interactive workflow supports exactly one club and spin default"
)
club = document.profile.clubs[0]
validate_capability_interactive_basis(club)
parameters = {item.parameter_id: item for item in club.parameters}
if set(parameters) != {"ball_speed", "launch_angle", "launch_direction"}:
raise ValueError("interactive workflow requires the three launch parameters")
Expand Down Expand Up @@ -368,6 +391,7 @@ def capability_workflow_inputs(
"CapabilityWorkflowInputs",
"build_capability_workflow",
"capability_workflow_from_json",
"capability_workflow_from_wire",
"capability_workflow_inputs",
"capability_workflow_json",
]
Loading
Loading