tests/test_recorder.py
3.0 KB · 104 lines · python Raw
1 """Tests for ReasoningRecorder."""
2
3 from __future__ import annotations
4
5 import pytest
6
7 from pqc_reasoning_ledger import ReasoningRecorder, StepKind
8
9
10 def test_record_thought_appends_thought_step(
11 sample_trace_started: ReasoningRecorder,
12 ) -> None:
13 step = sample_trace_started.record_thought("I am thinking")
14 assert step.kind == StepKind.THOUGHT
15 assert step.content == "I am thinking"
16 assert sample_trace_started.trace is not None
17 assert sample_trace_started.trace.steps[-1] is step
18
19
20 def test_all_convenience_methods_work(
21 sample_trace_started: ReasoningRecorder,
22 ) -> None:
23 r = sample_trace_started
24 r.record_thought("t")
25 r.record_observation("o")
26 r.record_hypothesis("h")
27 r.record_deduction("d")
28 r.record_retrieval("r")
29 r.record_tool_call("tc")
30 r.record_tool_result("tr")
31 r.record_self_critique("sc")
32 r.record_refinement("rf")
33 r.record_decision("dec")
34 assert r.trace is not None
35 kinds = [s.kind for s in r.trace.steps]
36 assert kinds == [
37 StepKind.THOUGHT,
38 StepKind.OBSERVATION,
39 StepKind.HYPOTHESIS,
40 StepKind.DEDUCTION,
41 StepKind.RETRIEVAL,
42 StepKind.TOOL_CALL,
43 StepKind.TOOL_RESULT,
44 StepKind.SELF_CRITIQUE,
45 StepKind.REFINEMENT,
46 StepKind.DECISION,
47 ]
48
49
50 def test_record_auto_increments_step_number(
51 sample_trace_started: ReasoningRecorder,
52 ) -> None:
53 s1 = sample_trace_started.record_thought("one")
54 s2 = sample_trace_started.record_thought("two")
55 s3 = sample_trace_started.record_thought("three")
56 assert s1.step_number == 1
57 assert s2.step_number == 2
58 assert s3.step_number == 3
59
60
61 def test_steps_chain_via_previous_step_hash(
62 sample_trace_started: ReasoningRecorder,
63 ) -> None:
64 s1 = sample_trace_started.record_observation("first")
65 s2 = sample_trace_started.record_deduction("second")
66 s3 = sample_trace_started.record_decision("third")
67 assert s1.previous_step_hash == "0" * 64
68 assert s2.previous_step_hash == s1.step_hash
69 assert s3.previous_step_hash == s2.step_hash
70
71
72 def test_seal_produces_sealed_trace_with_merkle_root(
73 sample_trace_started: ReasoningRecorder,
74 ) -> None:
75 sample_trace_started.record_observation("a")
76 sample_trace_started.record_deduction("b")
77 sealed = sample_trace_started.seal()
78 assert sealed.step_count == 2
79 assert len(sealed.merkle_root) == 64
80 assert sealed.final_chain_hash == sealed.steps[-1].step_hash
81
82
83 def test_seal_signs_the_trace(
84 sample_trace_started: ReasoningRecorder,
85 ) -> None:
86 sample_trace_started.record_decision("x")
87 sealed = sample_trace_started.seal()
88 assert sealed.signer_did
89 assert sealed.algorithm
90 assert sealed.signature
91 assert sealed.public_key
92 assert sealed.signer_did == sample_trace_started.identity.did
93 assert (
94 sealed.algorithm
95 == sample_trace_started.identity.signing_keypair.algorithm.value
96 )
97
98
99 def test_seal_empty_trace_raises(
100 sample_trace_started: ReasoningRecorder,
101 ) -> None:
102 with pytest.raises(Exception):
103 sample_trace_started.seal()
104