agentic examples

The Process Drill

The Process Drill: threads share a Mutex; PROCESSES share nothing but the file. The journal claims flock+fsync, which is a promise about processes - so this drill forks real ones, points them all at one journal, and lets the kernel referee. Then replay must find every event whole: no torn lines, no interleaved halves, no losses.

Testing & Verification exit 0

source on github

bundle exec ruby examples/process_drill.rb

a real captured run

PROCESS DRILL (4 forked writers x 250 events, one journal)

  processes exited cleanly:  yes
  lines on disk:             1000/1000
  torn lines:                0
  replay recovered per proc: 250, 250, 250, 250

  the flock claim is now a certificate, not a comment: four
  processes - separate GVLs, separate heaps, separate everything -
  interleaved a thousand writes into one file and the kernel's
  advisory lock kept every line whole. this is the half of the
  journal's promise the threads drill couldn't reach: a Mutex
  means nothing across fork(2); only the fd-level lock does.
  crash-recovery tooling stands on exactly this property.

source

# frozen_string_literal: true

# The Process Drill: threads share a Mutex; PROCESSES share nothing
# but the file. The journal claims flock+fsync, which is a promise
# about processes - so this drill forks real ones, points them all at
# one journal, and lets the kernel referee. Then replay must find
# every event whole: no torn lines, no interleaved halves, no losses.
#
#   bundle exec ruby examples/process_drill.rb
#
# Runs offline; exits 1 if any process's write was torn or lost.

require class="s">"bundler/setup"
require class="s">"agentic"
require class="s">"tmpdir"
require class="s">"json"

Agentic.logger.level = class="y">:fatal

PROCESSES = 4
EVENTS = 250
PATH = File.join(Dir.tmpdir, class="s">"agentic_process_drill.journal.jsonl")
File.delete(PATH) if File.exist?(PATH)

pids = PROCESSES.times.map do |p|
  fork do
    journal = Agentic:class="y">:ExecutionJournal.new(path: PATH)
    EVENTS.times do |i|
      journal.record(class="y">:task_succeeded,
        task_id: class="s">"p#{p}-#{i}", description: class="s">"p#{p}-#{i}",
        duration: 0.001, output: class="s">"payload-#{p}-" + (class="s">"x" * (50 + (i % 100))))
    end
    exit!(0)
  end
end
statuses = pids.map { |pid| Process.wait2(pid).last.exitstatus }

# --- the referee ----------------------------------------------------------------
lines = File.readlines(PATH)
torn = lines.reject do |line|
  JSON.parse(line)
  true
rescue JSON:class="y">:ParserError
  false
end
state = Agentic:class="y">:ExecutionJournal.replay(path: PATH)
expected = PROCESSES * EVENTS
per_process = PROCESSES.times.map { |p|
  state.completed_task_ids.count { |id| id.start_with?(class="s">"p#{p}-") }
}

puts class="s">"PROCESS DRILL (#{PROCESSES} forked writers x #{EVENTS} events, one journal)"
puts
puts format(class="s">"  processes exited cleanly:  %s", statuses.all?(&class="y">:zero?) ? class="s">"yes" : class="s">"NO")
puts format(class="s">"  lines on disk:             %d/%d", lines.size, expected)
puts format(class="s">"  torn lines:                %d", torn.size)
puts format(class="s">"  replay recovered per proc: %s", per_process.join(class="s">", "))
puts

ok = statuses.all?(&class="y">:zero?) && lines.size == expected && torn.empty? && per_process.all?(EVENTS)
if ok
  puts class="s">"  the flock claim is now a certificate, not a comment: four"
  puts class="s">"  processes - separate GVLs, separate heaps, separate everything -"
  puts class="s">"  interleaved a thousand writes into one file and the kernel's"
  puts class="s">"  advisory lock kept every line whole. this is the half of the"
  puts class="s">"  journal's promise the threads drill couldn't reach: a Mutex"
  puts class="s">"  means nothing across fork(2); only the fd-level lock does."
  puts class="s">"  crash-recovery tooling stands on exactly this property."
else
  puts class="s">"  DRILL FAILED - the promise about processes is broken."
end
exit(ok ? 0 : 1)