Class: KairosMcp::Daemon::WalPhaseRecorder

Inherits:
Object
  • Object
show all
Defined in:
lib/kairos_mcp/daemon/wal_phase_recorder.rb

Overview

WalPhaseRecorder — around_phase callback for CognitiveLoop.

Design (v0.2 P3.0):

CognitiveLoop exposes an `around_phase` callback hook. This
recorder records the executing→completed transition in the WAL
around each phase, so a crash anywhere inside the phase leaves
the WAL with a recoverable "executing" marker.

Ordering invariant:

wal.mark_executing(step_id, pre_hash:)        # before phase body
result = yield                                # phase body
wal.mark_completed(step_id, post_hash:,       # after phase body
                   result_hash:)

On exception, the phase is recorded as failed (error_class, error_msg), and the exception is re-raised. Recovery treats failed steps as final (no retry) — a higher-level retry policy is CognitiveLoop’s concern, not the recorder’s.

Step id derivation:

format('%s_%03d', phase, cycle)  — mirrors Planner.step_id_for.
Kept duplicated here (not require'd from Planner) to avoid a
runtime dep between recorder and planner: each can be exercised
alone in tests.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(wal:, cycle: 1) ⇒ WalPhaseRecorder

Returns a new instance of WalPhaseRecorder.

Raises:

  • (ArgumentError)


32
33
34
35
36
37
# File 'lib/kairos_mcp/daemon/wal_phase_recorder.rb', line 32

def initialize(wal:, cycle: 1)
  raise ArgumentError, 'wal is required' if wal.nil?

  @wal   = wal
  @cycle = Integer(cycle)
end

Instance Attribute Details

#cycleObject (readonly)

Returns the value of attribute cycle.



39
40
41
# File 'lib/kairos_mcp/daemon/wal_phase_recorder.rb', line 39

def cycle
  @cycle
end

Instance Method Details

#around_phase(phase) ⇒ Object

Wrap a phase body. ‘phase` is a Symbol or String (:observe/:orient/:decide/:act/:reflect). Returns the block’s return value on success; re-raises on failure.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/kairos_mcp/daemon/wal_phase_recorder.rb', line 44

def around_phase(phase)
  step_id  = step_id_for(phase)
  pre_hash = Canonical.sha256_json(marker(phase, 'pre'))
  @wal.mark_executing(step_id, pre_hash: pre_hash)

  begin
    result = block_given? ? yield : nil
  rescue StandardError => e
    @wal.mark_failed(step_id,
                     error_class: e.class.name,
                     error_msg:   e.message.to_s)
    raise
  end

  post_hash   = Canonical.sha256_json(marker(phase, 'post'))
  result_hash = Canonical.sha256_json(safe_result(result))
  @wal.mark_completed(step_id,
                      post_hash:   post_hash,
                      result_hash: result_hash)
  result
end

#step_id_for(phase) ⇒ Object

Expose step-id derivation so tests can verify recorded ids.



67
68
69
# File 'lib/kairos_mcp/daemon/wal_phase_recorder.rb', line 67

def step_id_for(phase)
  format('%s_%03d', phase.to_s, @cycle)
end