Enforce held-object geometry and explicit reconciliation - #47
Merged
Merged
Conversation
This was referenced Sep 8, 2026
…ams with ERROR set_shapes checked all eight slots of the homed array, but the firmware byte only carries six joints, so every attachment declaration was refused on hardware (the fake serial path fills all eight, which is why tests were green). While the attachment context is stale, every fire-and-forget jog or servo datagram was answered with an ERROR nobody awaited; the client dequeued those replies on its next unrelated request and raised for a command the server never refused. Streamed datagrams are now dropped (and logged once per epoch); acked commands are still refused explicitly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d-object-geometry # Conflicts: # parol6/client/async_client.py
…d-object-geometry
…d-object-geometry
…d-object-geometry # Conflicts: # parol6/client/async_client.py # parol6/commands/query_commands.py # parol6/server/controller.py
…eply The attachment gate test set a part on the flange in the process-wide collision world and left it there, so every later test's arm stood in collision at home. The completion readback test handed the query's struct to the message decoder; it now packs it as the controller does. The formatter's and type checker's remaining findings on this branch go with them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8zt66KjkzgZLtQuSfJd9r
…sults The dry-run client keeps one chunk per submitted command at the control tick — a planned trajectory, a delay's held pose, a tool action's jaw ramp over its estimated duration, or nothing with the refusal on it — and `plan()` assembles them into a waldoctl `TickIndex` at the record's row rate, one block per command with its move type. `simulate()` is the same record: this backend has no plant. Motion and queued methods answer with their program index, as the live client does; `delay`, `checkpoint`, `wait_command` and `flush` are real methods; and the client carries the backend `Robot` it stands in for. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8zt66KjkzgZLtQuSfJd9r
The skills contract on this branch still reads them off every client, preview clients included. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8zt66KjkzgZLtQuSfJd9r
…metry # Conflicts: # parol6/client/async_client.py # parol6/client/dry_run_client.py
Jepson2k
marked this pull request as ready for review
September 18, 2026 03:20
Every arm-moving command, home included, is refused while the attachment context is stale, from one ARM_MOTION_CMD_TYPES set shared by the controller and the dry run. Attaching a part is refused by one gate in the state that also sees a plan still in the planner: the controller records the highest submitted command index and the player the highest one a returned segment accounts for. A hardware E-stop keeps its own error while pressed; the stale-attachment error latches on release. wait_command is paced by the status stream, re-asking the completion query when a frame reports the command done or an error standing, or after 250 ms without one. Query replies are matched by request id alone; the broadcaster reads the session id the state already owns; the dry run's ack folds to one expression; the wire's Attachment import is at module level; the fake serial's E-stop input is driven through press_estop. The in-process controller fixture is shared from conftest, and the blend test keeps only the pause half of a case the record test already covers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N8zt66KjkzgZLtQuSfJd9r
…metry # Conflicts: # parol6/client/dry_run_client.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Track held geometry under the PAROL6 flange and exempt only declared contact pairs. Attach/detach requires confirmed whole-world application; invalid contact names preserve the previous geometry. Reference or controller-context changes invalidate declarations and gate arm motion until explicit reconciliation or removal. Live and dry-run clients expose the same readback and capability. These declarations neither operate the gripper nor confirm a grasp or estimate payload.
Completion waits now query the exact command result. A tool can finish independently while arm motion is paused; finishing that tool cannot falsely complete the paused or cancelled arm command. The controller retains 1024 successful indices, including every command consumed by a blend. Unknown, cancelled, and expired results remain unconfirmed, and a controller session change during a wait raises
ConnectionError. Client and controller must both support the new query. Replies to timed-out queries are filtered by response type so they cannot satisfy a different query.Depends on #46 and the companion waldoctl attachment contract.
Validation: real fake-serial regressions reproduced false completion of paused or cancelled arm work, late-response confusion, and missed controller restarts. Restart detection also watches independent status broadcasts when the command socket stops receiving after a peer reset. The latest change passes 16 controller/tool/lifecycle/error checks and 13 Commander pause, nested-skill, blended-stepping, recording, restart, and project-import workflows. Formatting and type checks pass. Query and acknowledgement receives preserve caller cancellation when a controller reply arrives concurrently, avoiding the Python 3.11 wait_for cancellation race observed in CI. The integration workflow cancels a query on arrival of a real controller reply and confirms subsequent queries still work. The latest CI run passes all twelve combinations of Linux, macOS, Windows and Python 3.11–3.14, plus lint. Each primary suite contains 314 cases (306 passed and eight separately executed examples skipped on Linux/macOS; 305 passed and the additional SIGKILL-only test skipped on Windows). All eight examples also pass in their separate job step on every combination.
Companion PRs: waldoctl, par6, Waldo-Commander.