Class: KairosMcp::Daemon::CodeGenAct
- Inherits:
-
Object
- Object
- KairosMcp::Daemon::CodeGenAct
- Defined in:
- lib/kairos_mcp/daemon/code_gen_act.rb
Overview
CodeGenAct — code generation pipeline for daemon ACT phase.
Design (P3.2 v0.2 §9):
1. plan_edit: LLM generates {old_string, new_string} via invoker
2. simulate: EditKernel computes pre/post hash without I/O
3. classify: ScopeClassifier determines scope
4. gate: ApprovalGate stages proposal or auto-approves
5. apply: CAS + EditKernel + atomic write (with elevation if L0/L1)
6. record: chain_record for L0/L1
Defined Under Namespace
Classes: LlmContentPolicyViolation, PauseForApproval, PostHashMismatch, PreHashMismatch, ProposalTampered, ScopeDrift
Instance Method Summary collapse
-
#initialize(workspace_root:, safety:, invoker:, approval_gate:, chain_recorder: nil, logger: nil) ⇒ CodeGenAct
constructor
A new instance of CodeGenAct.
-
#resume(proposal_id) ⇒ Hash, :still_pending
Re-entry after pause.
-
#run(decision, mandate) ⇒ Hash
Run the code-gen pipeline for a single edit.
Constructor Details
#initialize(workspace_root:, safety:, invoker:, approval_gate:, chain_recorder: nil, logger: nil) ⇒ CodeGenAct
Returns a new instance of CodeGenAct.
38 39 40 41 42 43 44 45 46 |
# File 'lib/kairos_mcp/daemon/code_gen_act.rb', line 38 def initialize(workspace_root:, safety:, invoker:, approval_gate:, chain_recorder: nil, logger: nil) @ws = workspace_root @safety = safety @invoker = invoker @gate = approval_gate @chain = chain_recorder @logger = logger end |
Instance Method Details
#resume(proposal_id) ⇒ Hash, :still_pending
Re-entry after pause.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/kairos_mcp/daemon/code_gen_act.rb', line 104 def resume(proposal_id) status = @gate.status_of(proposal_id) return :rejected if status == :rejected return :expired if status == :expired return :not_found if status == :not_found grant = @gate.consume_grant(proposal_id) return :still_pending if grant.nil? # Verify proposal integrity only after approval (decision exists) unless @gate.verify_proposal_integrity(proposal_id) raise ProposalTampered, "integrity check failed: #{proposal_id}" end proposal = symbolize_proposal(grant.proposal) abs = File.(proposal[:target][:path], @ws) apply_with_grant(proposal, grant, abs) end |
#run(decision, mandate) ⇒ Hash
Run the code-gen pipeline for a single edit.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/kairos_mcp/daemon/code_gen_act.rb', line 53 def run(decision, mandate) target_path = decision[:target] || decision['target'] abs = File.(target_path, @ws) # Scope classification scope_info = ScopeClassifier.classify(abs, workspace_root: @ws) # LLM content policy check check_llm_content_policy!(scope_info, mandate) # Read file and simulate content = File.binread(abs) plan = extract_edit_plan(decision) result = EditKernel.compute(content, old_string: plan[:old_string], new_string: plan[:new_string], replace_all: plan[:replace_all]) # Build proposal proposal_id = "prop_#{SecureRandom.hex(8)}" proposal = { proposal_id: proposal_id, mandate_id: mandate[:id] || mandate['id'], target: { path: target_path, pre_hash: result[:pre_hash] }, edit: { old_string: plan[:old_string], new_string: plan[:new_string], replace_all: plan[:replace_all], proposed_post_hash: result[:post_hash] }, scope: scope_info } # Gate if scope_info[:auto_approve] @gate.auto_approve(proposal) grant = @gate.consume_grant(proposal_id) apply_with_grant(proposal, grant, abs) else @gate.stage(proposal) grant = @gate.consume_grant(proposal_id) raise PauseForApproval, proposal_id if grant.nil? apply_with_grant(proposal, grant, abs) end end |