Class: Insika::Commands::ResolveProposal
- Inherits:
-
Object
- Object
- Insika::Commands::ResolveProposal
- Defined in:
- lib/insika/commands/resolve_proposal.rb
Overview
the human's answer : approve (→ the
store, CAS, provenance distilled:<session_ref>), reject (with an
optional reason), dismiss (latches the tuple). Approval never silently
overwrites an operator edit (D5/E3): the CAS baseline captured at distill
time guards the write, and a lost race flips the proposal to :stale
carrying the fact's CURRENT value — both values visible on the wiki.
Synchronous control command — the Studio dispatches it; no task, no actor.
Constant Summary collapse
- DECISIONS =
%w[approved rejected dismissed].freeze
Instance Method Summary collapse
-
#call(command) ⇒ Object
payload: { proposal_id:, decision: "approved"|"rejected"|"dismissed", operator?, note? } operator from payload || command.meta || "operator" -> Proposal (the resolved record; a :stale one carries current_value).
-
#initialize(proposal_store:, memory_store:, event_stream:) ⇒ ResolveProposal
constructor
A new instance of ResolveProposal.
Constructor Details
#initialize(proposal_store:, memory_store:, event_stream:) ⇒ ResolveProposal
Returns a new instance of ResolveProposal.
15 16 17 18 19 |
# File 'lib/insika/commands/resolve_proposal.rb', line 15 def initialize(proposal_store:, memory_store:, event_stream:) @proposal_store = proposal_store @memory_store = memory_store @event_stream = event_stream end |
Instance Method Details
#call(command) ⇒ Object
payload: { proposal_id:, decision: "approved"|"rejected"|"dismissed", operator?, note? } operator from payload || command.meta || "operator" -> Proposal (the resolved record; a :stale one carries current_value)
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/insika/commands/resolve_proposal.rb', line 25 def call(command) proposal_id = Coercion.presence(command.payload[:proposal_id] || command.payload["proposal_id"]) raise ValidationError, "proposal_id is required" if proposal_id.nil? decision = Coercion.presence(command.payload[:decision] || command.payload["decision"]) raise ValidationError, "decision is required" unless DECISIONS.include?(decision) proposal = @proposal_store.find(proposal_id) raise Insika::NotFoundError, "proposal not found: #{proposal_id}" if proposal.nil? operator = operator_for(command) note = Coercion.presence(command.payload[:note] || command.payload["note"]) case decision when "approved" then approve(command, proposal, operator, note) when "rejected" resolved = @proposal_store.reject(id: proposal.id, operator: operator, note: note) emit(:proposal_rejected, resolved) resolved else # "dismissed" resolved = @proposal_store.dismiss(id: proposal.id, operator: operator, note: note) emit(:proposal_dismissed, resolved) resolved end end |