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
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