diff --git a/agent/react.py b/agent/react.py index 9dece69..9cea8da 100644 --- a/agent/react.py +++ b/agent/react.py @@ -1,5 +1,5 @@ """ -ReAct runner: a real LLM (Grok) driving the spend tools in a loop. +ReAct runner: a real LLM driving the spend tools in a loop. The LLM reasons in THOUGHT lines, acts with ACTION + ARGS lines, reads OBSERVATION lines, and finishes with ANSWER. The runner executes only @@ -107,7 +107,7 @@ def parse_action(text: str): def _grok_cli() -> str: - """Resolve the Grok runner path from PERMIT_GROK_CLI at call time. + """Resolve the LLM runner path from PERMIT_GROK_CLI at call time. Raises RuntimeError with setup guidance when the variable is unset. """ @@ -196,7 +196,7 @@ def _learn_ids(recorded_text: str, fresh_text: str, def llm_turn(system: str, history: str) -> str: - """One Grok call. Returns the raw text (receipt stripped).""" + """One LLM call. Returns the raw text (receipt stripped).""" proc = subprocess.run( [sys.executable, _grok_cli(), "chat", history, "--system", system, "--temperature", "0.3", diff --git a/demos/demo_six_beat.py b/demos/demo_six_beat.py index 358e131..a8b02c5 100644 --- a/demos/demo_six_beat.py +++ b/demos/demo_six_beat.py @@ -1,8 +1,8 @@ """ Permit six-beat demo (mock PayPal rail: no PayPal credentials, no PayPal network). -The human principal grants the permit; a REAL LLM agent (Grok, ReAct loop) -decides what to spend — the agent's reasoning needs the Grok CLI (network +The human principal grants the permit; a REAL LLM agent (ReAct loop) +decides what to spend — the agent's reasoning needs the LLM CLI (network + credential) unless --replay is given. The fully offline, deterministic camera path is --replay demo_transcript.jsonl: the recorded reasoning is replayed verbatim and the recorded actions are re-executed against the diff --git a/docs/sandbox-runbook.md b/docs/sandbox-runbook.md index f8f132d..3b8fbbe 100644 --- a/docs/sandbox-runbook.md +++ b/docs/sandbox-runbook.md @@ -2,7 +2,7 @@ Status: documented procedure. The automated, camera-ready beats (demos/demo_six_beat.py) run in **mock mode** (mock PayPal rail: no PayPal network, no PayPal -credentials). The agent's reasoning is live (Grok CLI) unless +credentials). The agent's reasoning is live (LLM CLI) unless `--replay demo_transcript.jsonl` is used — that is the fully offline, deterministic camera path. This document is the scripted procedure for the integrated SANDBOX run: every beat executed against diff --git a/permit/durability.py b/permit/durability.py index 0a94e9b..4b13a8d 100644 --- a/permit/durability.py +++ b/permit/durability.py @@ -10,7 +10,7 @@ Atomic write: write to *.tmp + fsync + os.rename + fsync dir. -Integrity (REA R2): +Integrity (review R2): - Exclusive writer flock for the process lifetime; a second opener fails closed. - ledger.head binding records committed length/hash; truncation fails closed. - permits.json is bound to the ledger head (hash + HMAC); rewind fails closed. diff --git a/permit/ledger.py b/permit/ledger.py index a9bcf6b..ffc67a4 100644 --- a/permit/ledger.py +++ b/permit/ledger.py @@ -9,7 +9,7 @@ a reordered sequence, or a tampered payload breaks the chain, and the settlement verifier refuses to proceed on a broken chain. -No external format dependency (Interlock cut 2026-10-02, Grok review). +No external format dependency (Interlock cut 2026-10-02, agent review). Demo keys are hardcoded and labeled as such — no key-management scope. """ diff --git a/permit/permit.py b/permit/permit.py index 7a9b55f..7f24f68 100644 --- a/permit/permit.py +++ b/permit/permit.py @@ -1,7 +1,7 @@ """ Permit: the authorization layer. Decides what an agent is ALLOWED to spend. -Authority check (Grok review fix — cumulative reservation): +Authority check (agent review fix — cumulative reservation): amount(a) <= remaining(P) AND merchant(a) IN allowlist(P) AND now < expiry(P) diff --git a/settlement/verifier.py b/settlement/verifier.py index 6a67eb2..c562db6 100644 --- a/settlement/verifier.py +++ b/settlement/verifier.py @@ -204,7 +204,7 @@ def _original_refusal_id(self, escrow_id: str) -> str | None: return original_refused or original_voided def _append_retry_denial(self, escrow_id: str, reason: str) -> Receipt: - """REA F6: unique denial receipt for a refused retry; never captures.""" + """Review F6: unique denial receipt for a refused retry; never captures.""" original = self._original_refusal_id(escrow_id) return self.ledger.append( "REFUSED", @@ -305,7 +305,7 @@ def _verify_and_capture( if escrow.state == "CAPTURED": return VerifyResult(True, "already_captured") if escrow.state in ("VOIDED", "REFUSED"): - # REA F6: every refused retry writes a unique denial receipt + # Review F6: every refused retry writes a unique denial receipt # referencing the original refusal; money is never captured. reason = f"already_{escrow.state.lower()}" self._append_retry_denial(escrow_id, reason) diff --git a/tests/test_agent.py b/tests/test_agent.py index de82618..97e968b 100644 --- a/tests/test_agent.py +++ b/tests/test_agent.py @@ -97,7 +97,7 @@ def test_system_prompt_lists_catalog(): def test_llm_preflight_fails_with_guidance_when_cli_missing(monkeypatch): - """A missing Grok runner fails fast with setup guidance — not mid-demo.""" + """A missing LLM runner fails fast with setup guidance — not mid-demo.""" monkeypatch.setenv("PERMIT_GROK_CLI", "/nonexistent-xyz/grok.py") with pytest.raises(RuntimeError) as exc: llm_preflight() diff --git a/tests/test_rea_r2_pr26_attack.py b/tests/test_rea_r2_pr26_attack.py index 8608a01..e2f0d44 100644 --- a/tests/test_rea_r2_pr26_attack.py +++ b/tests/test_rea_r2_pr26_attack.py @@ -1,6 +1,6 @@ -"""REA R2 attack suite vs Permit PR #26 durability (file-backed). +"""Review R2 attack suite vs Permit PR #26 durability (file-backed). -Ports the axes from the REA R2 review onto permit/durability.py. +Ports the axes from the R2 review onto permit/durability.py. Each test that previously ACCEPTed a bypass must now REJECT (fail closed) or retain the reservation (axis E). """ diff --git a/tests/test_settlement.py b/tests/test_settlement.py index eebe27a..ae1ad4e 100644 --- a/tests/test_settlement.py +++ b/tests/test_settlement.py @@ -183,7 +183,7 @@ def _original_refusal_hash(ledger, escrow_id: str) -> str | None: def test_retry_on_refused_or_voided_writes_denial_receipt(): - """REA F6: every refused retry on an already REFUSED/VOIDED escrow must + """Review F6: every refused retry on an already REFUSED/VOIDED escrow must append a denial receipt with a unique receipt_id referencing the original refusal; capture must never run; hash chain stays valid.""" for terminal, expected_reason, first_release in ( @@ -229,7 +229,7 @@ def test_retry_on_refused_or_voided_writes_denial_receipt(): def test_retry_denial_receipts_serial_and_parallel(): - """REA F6 concurrency: 25 serial + 25 parallel refused retries each write a + """Review F6 concurrency: 25 serial + 25 parallel refused retries each write a unique denial receipt referencing the original refusal; none capture.""" import threading