agentic examples

The Invariant Sentinel

The Invariant Sentinel: domain invariants checked after EVERY task, from a lifecycle hook. When a task leaves the world in an illegal state, the sentinel names the task, names the broken law, and stops the plan before the corruption compounds. One of the pickers below has an off-by-one; watch how far it gets.

Plans & Graphs Round 4 Jeremy Evans exit 0

source on github

bundle exec ruby examples/invariant_sentinel.rb

a real captured run

INVARIANT SENTINEL: 2 laws watching 4 jobs

plan status: canceled
jobs completed before the stop: 3 of 4

LAW BROKEN: "stock equals initial + received - picked"
  by: pick 2 widgets (buggy picker)
  world state at the moment of arrest:
    stock:    {"widget"=>12, "gadget"=>5}
    received: {"widget"=>5}
    picked:   {"gadget"=>3, "widget"=>2}

the plan stopped at the FIRST broken law - 'receive 4 gadgets'
never ran. corruption caught at the task that caused it is a
bug report; corruption found at month-end close is an incident.

source

# frozen_string_literal: true

# The Invariant Sentinel: domain invariants checked after EVERY task,
# from a lifecycle hook. When a task leaves the world in an illegal
# state, the sentinel names the task, names the broken law, and stops
# the plan before the corruption compounds. One of the pickers below
# has an off-by-one; watch how far it gets.
#
#   bundle exec ruby examples/invariant_sentinel.rb
#
# Runs offline and deterministically.

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

WAREHOUSE = {stock: {class="s">"widget" => 10, class="s">"gadget" => 8}, received: {}, picked: {}}

INVARIANTS = {
  class="s">"stock is never negative" => -> {
    WAREHOUSE[class="y">:stock].values.all? { |count| count >= 0 }
  },
  class="s">"stock equals initial + received - picked" => -> {
    WAREHOUSE[class="y">:stock].all? do |sku, count|
      initial = {class="s">"widget" => 10, class="s">"gadget" => 8}.fetch(sku)
      count == initial + WAREHOUSE[class="y">:received].fetch(sku, 0) - WAREHOUSE[class="y">:picked].fetch(sku, 0)
    end
  }
}.freeze

JOBS = [
  {name: class="s">"receive 5 widgets", work: -> {
    WAREHOUSE[class="y">:stock][class="s">"widget"] += 5
    WAREHOUSE[class="y">:received][class="s">"widget"] = WAREHOUSE[class="y">:received].fetch(class="s">"widget", 0) + 5
  }},
  {name: class="s">"pick 3 gadgets", work: -> {
    WAREHOUSE[class="y">:stock][class="s">"gadget"] -= 3
    WAREHOUSE[class="y">:picked][class="s">"gadget"] = WAREHOUSE[class="y">:picked].fetch(class="s">"gadget", 0) + 3
  }},
  {name: class="s">"pick 2 widgets (buggy picker)", work: -> {
    WAREHOUSE[class="y">:stock][class="s">"widget"] -= 3 # decrements 3, records 2: the bug
    WAREHOUSE[class="y">:picked][class="s">"widget"] = WAREHOUSE[class="y">:picked].fetch(class="s">"widget", 0) + 2
  }},
  {name: class="s">"receive 4 gadgets", work: -> {
    WAREHOUSE[class="y">:stock][class="s">"gadget"] += 4
    WAREHOUSE[class="y">:received][class="s">"gadget"] = WAREHOUSE[class="y">:received].fetch(class="s">"gadget", 0) + 4
  }}
].freeze

violations = []
orchestrator = nil

sentinel = lambda do |task_id:, task:, result:, duration:|
  INVARIANTS.each do |law, check|
    next if check.call

    violations << {task: task.description, law: law, state: Marshal.load(Marshal.dump(WAREHOUSE))}
    orchestrator.cancel_plan
  end
end

orchestrator = Agentic:class="y">:PlanOrchestrator.new(
  concurrency_limit: 1, # deterministic order so the culprit is unambiguous
  lifecycle_hooks: {after_task_success: sentinel}
)

previous = nil
JOBS.each do |job|
  task = Agentic:class="y">:Task.new(
    description: job[class="y">:name],
    agent_spec: {class="s">"name" => class="s">"warehouse", class="s">"instructions" => class="s">"do the job"},
    payload: job[class="y">:work]
  )
  orchestrator.add_task(task, previous ? [previous] : [], agent: ->(t) { t.payload.call || class="y">:done })
  previous = task
end

result = orchestrator.execute_plan

puts class="s">"INVARIANT SENTINEL: #{INVARIANTS.size} laws watching #{JOBS.size} jobs"
puts
puts class="s">"plan status: #{result.status}"
completed = result.results.values.count(&class="y">:successful?)
puts class="s">"jobs completed before the stop: #{completed} of #{JOBS.size}"
puts

if violations.empty?
  puts class="s">"every law held. suspiciously well-behaved."
else
  violations.each do |violation|
    puts class="s">"LAW BROKEN: \"#{violation[class="y">:law]}\class="s">""
    puts class="s">"  by: #{violation[class="y">:task]}"
    puts class="s">"  world state at the moment of arrest:"
    puts class="s">"    stock:    #{violation[class="y">:state][class="y">:stock]}"
    puts class="s">"    received: #{violation[class="y">:state][class="y">:received]}"
    puts class="s">"    picked:   #{violation[class="y">:state][class="y">:picked]}"
  end
  puts
  puts class="s">"the plan stopped at the FIRST broken law - 'receive 4 gadgets'"
  puts class="s">"never ran. corruption caught at the task that caused it is a"
  puts class="s">"bug report; corruption found at month-end close is an incident."
end