Class: Ace::Hitl::Molecules::LabProjectionObserver
- Inherits:
-
Object
- Object
- Ace::Hitl::Molecules::LabProjectionObserver
- Defined in:
- lib/ace/hitl/molecules/lab_projection_observer.rb
Overview
Observes the Lab request public projection
(<public-dir>/<request-id>.json) so waiters can surface lab-side
states instead of hanging blind. Read-only; consumption of the
answer relay remains the caller's choice.
Projection schema (deployed lab relay, lab-config 8wl.t.ga9): the
lifecycle field state carries created / answer-delivered /
consumed / cancelled, while effect-callback outcomes live in the
SEPARATE effect_state field (callback-pending-with-answer /
callback-ok / callback-escalated). Both fields are observed here.
Defined Under Namespace
Classes: Snapshot
Constant Summary collapse
- DEFAULT_PUBLIC_DIR =
"/run/lab/hitl/public"- PUBLIC_DIR_ENV =
Read-side override for waiters. The lifecycle store writes the projection under ACE_HITL_STORE_ROOT/public — the same deployed default directory. The two env vars overlap by default: the store root owns the WRITE side (and the store's other directories), this one only redirects WHERE WAITERS READ the public projection from (e.g. a host that mounts the projection read-only). Keep them pointing at the same directory unless a projection relay is deliberately placed in between.
"ACE_HITL_LAB_PUBLIC_DIR"- LIFECYCLE_TERMINAL_STATES =
Lifecycle (
state) terminal values: the answer was delivered to the relay, consumed, or the request was cancelled. %w[answer-delivered consumed cancelled].freeze
- EFFECT_TERMINAL_STATES =
Effect (
effect_state) terminal values: the callback reached a verdict.callback-pending-with-answerkeeps a waiter holding. %w[callback-ok callback-escalated].freeze
Instance Method Summary collapse
-
#effective_state(snapshot) ⇒ Object
The state a waiter should report: the effect outcome when one exists (so
lab_request_statenever claims plainanswer-deliveredwhile an effect outcome is present), the lifecycle state otherwise. -
#initialize(public_dir: nil) ⇒ LabProjectionObserver
constructor
A new instance of LabProjectionObserver.
- #projection_path(request_id) ⇒ Object
-
#snapshot_for(request_id) ⇒ Object
Reads the projection and returns a Snapshot with the lifecycle
stateand the separateeffect_state, or nil when the projection is missing or unreadable. -
#terminal?(snapshot, effect_declared: false) ⇒ Boolean
Terminality depends on whether the request declared an effect callback: effect-declaring requests terminate only on an effect verdict (callback-ok / callback-escalated), never at answer delivery; other requests terminate on lifecycle terminal states.
Constructor Details
#initialize(public_dir: nil) ⇒ LabProjectionObserver
Returns a new instance of LabProjectionObserver.
41 42 43 |
# File 'lib/ace/hitl/molecules/lab_projection_observer.rb', line 41 def initialize(public_dir: nil) @public_dir = public_dir end |
Instance Method Details
#effective_state(snapshot) ⇒ Object
The state a waiter should report: the effect outcome when one
exists (so lab_request_state never claims plain
answer-delivered while an effect outcome is present), the
lifecycle state otherwise.
65 66 67 68 69 |
# File 'lib/ace/hitl/molecules/lab_projection_observer.rb', line 65 def effective_state(snapshot) return nil unless snapshot snapshot.effect_state || snapshot.state end |
#projection_path(request_id) ⇒ Object
85 86 87 |
# File 'lib/ace/hitl/molecules/lab_projection_observer.rb', line 85 def projection_path(request_id) File.join(public_dir, "#{request_id}.json") end |
#snapshot_for(request_id) ⇒ Object
Reads the projection and returns a Snapshot with the lifecycle
state and the separate effect_state, or nil when the
projection is missing or unreadable.
48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/ace/hitl/molecules/lab_projection_observer.rb', line 48 def snapshot_for(request_id) path = projection_path(request_id) return nil unless File.file?(path) projection = JSON.parse(File.read(path)) Snapshot.new( state: projection["state"], effect_state: projection["effect_state"] ) rescue nil end |
#terminal?(snapshot, effect_declared: false) ⇒ Boolean
Terminality depends on whether the request declared an effect callback: effect-declaring requests terminate only on an effect verdict (callback-ok / callback-escalated), never at answer delivery; other requests terminate on lifecycle terminal states.
75 76 77 78 79 80 81 82 83 |
# File 'lib/ace/hitl/molecules/lab_projection_observer.rb', line 75 def terminal?(snapshot, effect_declared: false) return false unless snapshot if effect_declared EFFECT_TERMINAL_STATES.include?(snapshot.effect_state) else LIFECYCLE_TERMINAL_STATES.include?(snapshot.state) end end |