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
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions docs/M1Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions src/context_compiler/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
35 changes: 30 additions & 5 deletions tests/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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,
}

Expand All @@ -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},
Expand Down
Loading