fix(#812): direction-aware signal display for DynamicRailSemaphore - #813
Merged
Merged
Conversation
Copilot
AI
changed the title
[WIP] Fix DynamicRailSemaphore signal display for direction sensitivity
fix(#812): direction-aware signal display for DynamicRailSemaphore
Jul 27, 2026
Add isAllowingFor(from, to) to DynamicRailSemaphore, update PerceptionMapping.separatorAspect, SemaphoreReading, DefaultNetworkPerceptionPort, and AnimationStateCapture to use direction-aware signal checks. - DynamicRailSemaphore.isAllowingFor(from, to): new method that returns true only when signal is allowing AND from/to match the canonical forward direction (anti(direction()) → direction()). Prevents consumers from treating another train's forward-direction grant as a proceed for the reverse direction. - PerceptionMapping.separatorAspect: updated to call isAllowingFor(anti(d), d) for both DynamicRailSemaphore and DynamicInOut instead of reading raw signal. - SemaphoreReading: added authorizedFrom/authorizedTo nullable fields (default null) so the LLM dispatcher's all_signal_aspects tool exposes direction context alongside the signal aspect. - DefaultNetworkPerceptionPort.toReading(): populates authorizedFrom/authorizedTo from direction() when signal is allowing; null otherwise. - AnimationStateCapture.captureSignalState(): uses isAllowingFor to only report proceed aspects authorized for the forward direction. - DynamicRailSemaphoreTest: 6 new tests for isAllowingFor covering STOP signal, forward direction, reverse direction, after cancel, null segments, and second orientation. - DefaultNetworkPerceptionPortTest: updated semaphore() helper to mock direction() = Cell.Segment.A and isAllowingFor(any(), any()), updated 6 SemaphoreReading assertions to include authorizedFrom/authorizedTo.
bedaHovorka
force-pushed
the
copilot/fix-dynamic-rail-semaphore-display
branch
from
July 28, 2026 16:05
9c81093 to
50330d7
Compare
bedaHovorka
marked this pull request as ready for review
July 28, 2026 18:12
…play Address PR #813 review findings (C1 + I1/I2/I3). The PR's isAllowingFor guard was a no-op: it queried the static orientation, which always matched the static forward, so separatorAspect/captureSignalState were unchanged and toReading always reported the static forward direction — a lit semaphore cleared for the reverse direction still read "proceed" to a forward-facing observer. A static-orientation query cannot distinguish reserved-forward from reserved-reverse; the semaphore must store the actual direction. DynamicRailSemaphore now records the reservation direction in setUpSpeed (cleared on STOP). authorizedDirection() returns the stored pair, defaulting to the canonical forward when unknown (direct signal writes that bypass setUpSpeed — entry/facing signals cleared outside the reservation flow). isAllowingFor compares against the stored direction, so a forward query against a reverse-reserved proceed aspect correctly returns false. - DynamicRailSemaphore: authorizedFrom/authorizedTo + authorizedDirection(); isAllowingFor rewritten against the stored direction. - PerceptionMapping.separatorAspect: revert to raw signal. This is the train's own next-separator perception (the holder is always authorized), so a guard would wrongly show STOP to a reverse-travelling holder at its own semaphore. - DefaultNetworkPerceptionPort.toReading: report authorizedDirection() so the LLM dispatcher's all_signal_aspects learns the actual reserved direction. - SimulationCellRenderer: direction-aware canvas color — the forward-facing view shows STOP (RED) for a reverse-reserved aspect. AnimationStateCapture KDoc updated (its guard is now meaningful). - Tests: reverse-reservation isAllowingFor/authorizedDirection coverage, new PerceptionMappingTest (commonTest), tightened DefaultNetworkPerceptionPortTest stub to drive toReading via authorizedDirection. Co-Authored-By: Claude <noreply@anthropic.com>
|
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.



DynamicRailSemaphore.signalis a single field — not keyed by direction or train. Once any train's forward-direction reservation lights a semaphore FREE, all consumers (canvas renderers, LLM dispatcher'sall_signal_aspects) see proceed regardless of which direction they're asking about. The movement-safety gap was closed in 28e3389 via ownership-checked wakeup inTrain.kt; this PR fixes the perception/rendering truthfulness side.Core change
New
isAllowingFor(from, to)onDynamicRailSemaphore:Returns
trueonly when the signal is allowing and the queried direction matches the canonical forward direction (anti(direction()) → direction()).Consumer updates
PerceptionMapping.separatorAspect— replaces rawsignalread withisAllowingFor(anti(d), d). Train reactive decisions now seeSTOPwhen the semaphore is lit for the opposite direction.AnimationStateCapture.captureSignalState— same guard; canvas animation no longer paints proceed for a semaphore authorized by an opposite-direction reservation.DefaultNetworkPerceptionPort— adds privateDynamicRailSemaphore.toReading()extension that populates two newSemaphoreReadingfields.LLM dispatcher perception
SemaphoreReadinggains two nullable direction fields (backward-compatible defaultsnull):allSignalAspects/signalAspectnow include which direction the proceed is authorized for, so the LLM dispatcher can distinguish "clear for me" from "clear for the other train."Tests
isAllowingFortests inDynamicRailSemaphoreTest(STOP, forward, reverse, after cancel, null segments, second orientation).DefaultNetworkPerceptionPortTestsemaphore mock updated to stubdirection()andisAllowingFor; 6SemaphoreReadingassertions updated to expect the new direction fields.