From 27671bb743befe8ed0bfebed4965d0833e4bc63a Mon Sep 17 00:00:00 2001 From: Robert Lippmann Date: Tue, 10 Mar 2026 01:38:49 -0400 Subject: [PATCH] feat: make reset policies clear only prohibitions - reset policies now clears policies.prohibit but preserves facts - remove clear constraints command - keep clear state as full reset - update tests and documentation - add tests for reset semantics and correction behavior --- README.md | 39 ++++++++++++++++++++++++++++++++++ docs/M1Design.md | 6 ++++-- src/context_compiler/engine.py | 5 ++--- tests/test_engine.py | 35 +++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b8c1c0f..86978b0 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,45 @@ Decision.kind = "clarify" No state mutation occurs until confirmation. +## Reset Commands + +Two explicit reset commands are supported: + +- `reset policies` clears `policies.prohibit` but preserves the current fact (`facts["focus.primary"]`) +- `clear state` resets the full state to initial values + +Example: + +Before: + +```json +{ + "facts": {"focus.primary": "oracle"}, + "policies": {"prohibit": ["stored procedures"]}, + "version": 1 +} +``` + +After `reset policies`: + +```json +{ + "facts": {"focus.primary": "oracle"}, + "policies": {"prohibit": []}, + "version": 1 +} +``` + +After `clear state`: + +```json +{ + "facts": {"focus.primary": null}, + "policies": {"prohibit": []}, + "version": 1 +} +``` + --- ## Examples diff --git a/docs/M1Design.md b/docs/M1Design.md index 1ccd052..c270188 100644 --- a/docs/M1Design.md +++ b/docs/M1Design.md @@ -259,12 +259,14 @@ Example: Explicit only: - "reset policies" -- "clear constraints" - "clear state" Produces: - state = initial_state + if command == "reset policies": + state.policies.prohibit = [] + elif command == "clear state": + state = initial_state Decision.kind = "update" ### 12. Non-Goals (M1) diff --git a/src/context_compiler/engine.py b/src/context_compiler/engine.py index c4d72ce..6cf1fd1 100644 --- a/src/context_compiler/engine.py +++ b/src/context_compiler/engine.py @@ -62,7 +62,7 @@ class NegativeDirectiveRule: strip_leading_use: bool -_RESET_POLICY = {"reset policies", "clear constraints"} +_RESET_POLICY = {"reset policies"} _CLEAR_STATE = {"clear state"} _CORRECTION_RE = re.compile(r"^\s*(actually|i meant|correction:|no,)\s*(.*?)\s*$", re.IGNORECASE) @@ -215,8 +215,7 @@ def _apply_event(self, event: PendingEvent) -> Decision: assert event.fact_value is not None return self._set_focus_primary(event.fact_value) if event.kind == "reset_policies": - self._state = _initial_state() - self._last_exclusive_fact_key = None + self._state[STATE_POLICIES][POLICY_PROHIBIT] = [] return _update_decision(self._state) self._state = _initial_state() diff --git a/tests/test_engine.py b/tests/test_engine.py index cccb787..8e08bfc 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -183,7 +183,7 @@ def test_reset_commands() -> None: decision1 = engine.step("reset policies") assert decision1["kind"] == "update" assert engine.state == { - "facts": {"focus.primary": None}, + "facts": {"focus.primary": "Nord Stage 4"}, "policies": {"prohibit": []}, "version": 1, } @@ -192,10 +192,10 @@ def test_reset_commands() -> None: engine.step("don't use parallel octaves") decision_constraints = engine.step("clear constraints") - assert decision_constraints["kind"] == "update" + assert decision_constraints["kind"] == "passthrough" assert engine.state == { - "facts": {"focus.primary": None}, - "policies": {"prohibit": []}, + "facts": {"focus.primary": "Nord Stage 4"}, + "policies": {"prohibit": ["parallel octaves"]}, "version": 1, } @@ -221,13 +221,38 @@ def test_passthrough_input_does_not_mutate_state() -> None: assert engine.state == before -def test_reset_policies_when_already_empty_resets_state() -> None: +def test_reset_policies_when_already_empty_preserves_existing_fact() -> None: engine = create_engine() engine.step("use Nord Stage 4") decision = engine.step("reset policies") + assert decision["kind"] == "update" + assert engine.state == { + "facts": {"focus.primary": "Nord Stage 4"}, + "policies": {"prohibit": []}, + "version": 1, + } + + +def test_reset_policies_keeps_last_exclusive_fact_correctable() -> None: + engine = create_engine() + + engine.step("use Nord Stage 4") + engine.step("don't use docker") + engine.step("reset policies") + + decision = engine.step("actually Nord Stage 3") + assert decision["kind"] == "update" + assert engine.state["facts"]["focus.primary"] == "Nord Stage 3" + + +def test_reset_policies_on_initial_state_is_update_and_noop() -> None: + engine = create_engine() + + decision = engine.step("reset policies") + assert decision["kind"] == "update" assert engine.state == { "facts": {"focus.primary": None},