diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b97713..e76cc11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/examples/demo_authority_gate.py b/examples/demo_authority_gate.py index 0450f7f..f8b221f 100644 --- a/examples/demo_authority_gate.py +++ b/examples/demo_authority_gate.py @@ -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 diff --git a/examples/demo_stop_machine.py b/examples/demo_stop_machine.py index 5316531..c3a5690 100644 --- a/examples/demo_stop_machine.py +++ b/examples/demo_stop_machine.py @@ -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 diff --git a/primitives/authority-gate/README.md b/primitives/authority-gate-v0/README.md similarity index 100% rename from primitives/authority-gate/README.md rename to primitives/authority-gate-v0/README.md diff --git a/primitives/authority-gate/gate.py b/primitives/authority-gate-v0/gate.py similarity index 100% rename from primitives/authority-gate/gate.py rename to primitives/authority-gate-v0/gate.py diff --git a/primitives/authority-gate/test_gate.py b/primitives/authority-gate-v0/test_gate.py similarity index 100% rename from primitives/authority-gate/test_gate.py rename to primitives/authority-gate-v0/test_gate.py diff --git a/primitives/stop-machine/README.md b/primitives/stop-machine-v0/README.md similarity index 100% rename from primitives/stop-machine/README.md rename to primitives/stop-machine-v0/README.md diff --git a/primitives/stop-machine/stop_machine.py b/primitives/stop-machine-v0/stop_machine.py similarity index 100% rename from primitives/stop-machine/stop_machine.py rename to primitives/stop-machine-v0/stop_machine.py diff --git a/primitives/stop-machine/test_stop_machine.py b/primitives/stop-machine-v0/test_stop_machine.py similarity index 100% rename from primitives/stop-machine/test_stop_machine.py rename to primitives/stop-machine-v0/test_stop_machine.py diff --git a/stop_machine.py b/stop_machine.py index 3872443..c66369e 100644 --- a/stop_machine.py +++ b/stop_machine.py @@ -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 @@ -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 diff --git a/test_stop_machine.py b/test_stop_machine.py index 773324b..bea8fa6 100644 --- a/test_stop_machine.py +++ b/test_stop_machine.py @@ -134,10 +134,8 @@ 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(): @@ -145,10 +143,8 @@ def test_reset_then_advance(): 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 ---