Skip to content
Merged
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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ jobs:
- name: Install dependencies
run: pip install pytest

- name: Run tests
- name: Run primitive tests
run: python -m pytest primitives -v
- name: Run root tests
run: python -m pytest test_stop_machine.py -v
2 changes: 1 addition & 1 deletion examples/demo_authority_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "primitives" / "authority-gate"))
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "primitives" / "authority-gate-v0"))

from gate import Authority, AuthorityGate # noqa: E402

Expand Down
2 changes: 1 addition & 1 deletion examples/demo_stop_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "primitives" / "stop-machine"))
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "primitives" / "stop-machine-v0"))

from stop_machine import Event, StopMachine # noqa: E402

Expand Down
File renamed without changes.
File renamed without changes.
13 changes: 9 additions & 4 deletions stop_machine.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# CANONICAL SOURCE: LalaSkye/constraint-workshop/stop_machine.py
# PINNED COMMIT: 8d04cbc1e8e6576641962d5d3c866b0517ad596e
# Semantics aligned to canonical: RED is terminal, reset() blocked from RED.

"""A deterministic three-state stop controller.

States: GREEN -> AMBER -> RED
Expand Down Expand Up @@ -87,10 +91,11 @@ def transition_to(self, target: State) -> State:
return self._state

def reset(self) -> State:
"""Reset the machine to GREEN.

Returns the new state (always GREEN).
"""
"""Reset the machine to GREEN. Forbidden once RED is reached."""
if self.is_terminal:
raise TerminalStateError(
f"Cannot reset: {self._state.value} is terminal."
)
self._state = State.GREEN
return self._state

Expand Down
12 changes: 4 additions & 8 deletions test_stop_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,21 +134,17 @@ def test_reset_from_amber():

def test_reset_from_red():
m = StopMachine(State.RED)
result = m.reset()
assert result == State.GREEN
assert m.state == State.GREEN
assert not m.is_terminal
with pytest.raises(TerminalStateError):
m.reset()


def test_reset_then_advance():
m = StopMachine()
m.advance()
m.advance()
assert m.is_terminal
m.reset()
assert m.state == State.GREEN
m.advance()
assert m.state == State.AMBER
with pytest.raises(TerminalStateError):
m.reset()


# --- repr ---
Expand Down