Class: Harnex::Waiter

Inherits:
Object
  • Object
show all
Defined in:
lib/harnex/commands/wait.rb

Constant Summary collapse

POLL_INTERVAL =
0.5
EVENT_POLL_INTERVAL =
0.1
EXIT_STATUS_GRACE_SECONDS_DEFAULT =
5.0
EXIT_STATUS_GRACE_POLL_INTERVAL =
0.05
FINAL_EVENT_GRACE_SECONDS =
5.0
EVENT_PREDICATES =
%w[task_complete task_failed].freeze
LEGACY_EVENT_TYPES =
%w[agent_state exited task_complete task_failed].freeze
DONE_EXIT_DONE =

Exit-code contract for --until done (documented in guides/04_monitoring.md).

0
DONE_EXIT_FAILED =
1
DONE_EXIT_REJECTED_PROOF =
2
DONE_EXIT_NO_SESSION =
3
DONE_EXIT_TIMEOUT =
124
REJECTED_PROOF_CLASSES =

Outcome classes where the process completed but the work was not accepted: proof was missing, invalid, rejected, or nothing happened.

%w[
  completed_no_activity report_missing report_invalid report_rejected
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv) ⇒ Waiter

Returns a new instance of Waiter.



77
78
79
80
81
82
83
84
85
86
# File 'lib/harnex/commands/wait.rb', line 77

def initialize(argv)
  @argv = argv.dup
  @options = {
    id: nil,
    until_state: nil,
    repo_path: Dir.pwd,
    timeout: nil,
    help: false
  }
end

Class Method Details

.usage(program_name = "harnex wait") ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/harnex/commands/wait.rb', line 30

def self.usage(program_name = "harnex wait")
  <<~TEXT
    Usage: #{program_name} [options]

    Options:
      --id ID         Session ID to wait for (required)
      --until STATE   Wait until session reaches STATE. Supported:
                        done            (work fence — task_complete,
                                         task_failed, or terminal exit,
                                         whichever comes first)
                        task_complete   (events JSONL — fires on
                                         successful turn completion)
                        task_failed     (events JSONL — fires on
                                         failed turn completion)
                        <other>         (agent_state HTTP poll, e.g.
                                         "prompt", "busy")
                      Without --until, waits for session exit (default).
      --repo PATH     Resolve session using PATH's repo root (default: current repo)
      --timeout SECS  Maximum time to wait in seconds (default: unlimited)
      -h, --help      Show this help

    Common patterns:
      #{program_name} --id cx-i-42 --until done --timeout 900
      #{program_name} --id cx-i-42 --until task_complete --timeout 900
      #{program_name} --id cx-i-42 --until prompt --timeout 120
      #{program_name} --id cx-i-42

    Exit codes for --until done:
      0    completed with accepted work
      1    failed (work failed, process failed, or killed)
      2    completed but proof rejected (completed_no_activity,
           report_missing, report_invalid, report_rejected)
      3    no such session (no live, start, event, or terminal signal)
      124  --timeout elapsed while the session was still running

    Gotchas:
      done is the safest work-level fence for monitors.
      While the session's pid is alive, --until done blocks (up to
      --timeout); "no signal yet" from a live worker is never terminal.
      task_complete/task_failed are event predicates; prompt/busy are live state polls.
      Prompt state alone does not prove work acceptance. Verify artifacts/tests.
      Exit waits can resolve from terminal summary rows when live registry/
      exit-status files are already gone.
      Without --timeout, wait can block indefinitely.
  TEXT
end

Instance Method Details

#runObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/harnex/commands/wait.rb', line 88

def run
  parser.parse!(@argv)
  if @options[:help]
    puts self.class.usage
    return 0
  end

  raise "--id is required for harnex wait" unless @options[:id]

  if @options[:until_state]
    case @options[:until_state]
    when "done"
      wait_until_done
    when *EVENT_PREDICATES
      wait_until_event(@options[:until_state])
    else
      wait_until_state
    end
  else
    wait_until_exit
  end
end