agentic examples

The Ractor Shareability Audit

The Ractor Shareability Audit: `freeze` is a promise about one object; Ractor.shareable? is a promise about everything it can reach. The graph API says "frozen snapshot" - this audit asks the stricter question: which framework values could cross a Ractor boundary TODAY, which need make_shareable's deep freeze, and which can never go because they hold live machinery?

Scheduling & Concurrency Round 14 Marc-André Lafortune exit 0

source on github

bundle exec ruby examples/ractor_shareability.rb

a real captured run

THE RACTOR SHAREABILITY AUDIT (frozen is not the same promise)

  value                    frozen?  shareable?  after make_shareable
  graph snapshot           true     false       a deep-frozen copy crosses
  graph[:order]            true     true        (already crosses)
  graph[:stats]            true     true        (already crosses)
  to_json_schema output    false    false       a deep-frozen copy crosses
  a Task object            false    false       a deep-frozen copy crosses
  TaskResult.success       false    false       a deep-frozen copy crosses
  a RateLimit              false    false       REFUSED: holds live machinery

  proof of travel: checked 1 properties in another Ractor

  the audit's grammar lesson: graph[:order] and graph[:stats] are
  data all the way down and cross as-is. the full snapshot is
  'frozen' but REACHES unfrozen Task objects - a top-floor promise
  on a building with unlocked doors below; a deep-frozen COPY
  crosses fine, and copies are what you should send anyway. the
  RateLimit is the honest REFUSAL: it holds a real Mutex, and no
  amount of freezing turns a lock into a value - it's a machine,
  not a fact. that's the Ractor pattern in one line: send facts,
  keep machines. and note the auditor's own first-draft sin,
  preserved in the comment above: it deep-froze the system under
  audit and contaminated row after row - Ractor.shareable? is
  ruby's strictest freeze referee, and referees must not tamper
  with the evidence.

source

# frozen_string_literal: true

# The Ractor Shareability Audit: `freeze` is a promise about one
# object; Ractor.shareable? is a promise about everything it can
# reach. The graph API says "frozen snapshot" - this audit asks the
# stricter question: which framework values could cross a Ractor
# boundary TODAY, which need make_shareable's deep freeze, and which
# can never go because they hold live machinery?
#
#   bundle exec ruby examples/ractor_shareability.rb
#
# Runs offline; verdicts come from Ractor itself, not from reading code.

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

Agentic.logger.level = class="y">:fatal
Warning[class="y">:experimental] = false # Ractor is experimental; the audit knows

def task_named(name)
  Agentic:class="y">:Task.new(description: name, agent_spec: {class="s">"name" => name, class="s">"instructions" => class="s">"w"})
end

orchestrator = Agentic:class="y">:PlanOrchestrator.new
a = task_named(class="s">"a")
b = task_named(class="s">"b")
orchestrator.add_task(a)
orchestrator.add_task(b, [a])

spec = Agentic:class="y">:CapabilitySpecification.new(
  name: class="s">"quote", description: class="s">"q", version: class="s">"1.0.0",
  inputs: {mode: {type: class="s">"string", required: true, enum: %w[air sea]}},
  rules: {gate: {relation: class="y">:requires, fields: [class="y">:mode]}}
)

SUBJECTS = {
  class="s">"graph snapshot" => orchestrator.graph,
  class="s">"graph[class="y">:order]" => orchestrator.graph[class="y">:order],
  class="s">"graph[class="y">:stats]" => orchestrator.graph[class="y">:stats],
  class="s">"to_json_schema output" => spec.to_json_schema,
  class="s">"a Task object" => a,
  class="s">"TaskResult.success" => Agentic:class="y">:TaskResult.new(task_id: class="s">"t", success: true, output: class="s">"x"),
  class="s">"a RateLimit" => Agentic:class="y">:RateLimit.new(2)
}.freeze

# One verdict per subject, on a COPY wherever possible - an auditor
# that deep-freezes the system under audit is contaminating its own
# evidence (the first draft of this file did exactly that)
def verdict(value)
  frozen = value.frozen?
  return [frozen, true, class="s">"(already crosses)"] if Ractor.shareable?(value)

  copy = begin
    Marshal.load(Marshal.dump(value))
  rescue TypeError
    nil # holds procs, mutexes, IO - unmarshalable machinery
  end

  after = if copy
    begin
      Ractor.make_shareable(copy)
      class="s">"a deep-frozen copy crosses"
    rescue Ractor:class="y">:Error, TypeError => e
      class="s">"refused: #{e.class.name.split("::class="s">").last}"
    end
  else
    begin
      Ractor.make_shareable(value)
      class="s">"deep-frozen IN PLACE (mutates the original!)"
    rescue Ractor:class="y">:Error, TypeError
      class="s">"REFUSED: holds live machinery"
    end
  end
  [frozen, false, after]
end

puts class="s">"THE RACTOR SHAREABILITY AUDIT (frozen is not the same promise)"
puts
puts format(class="s">"  %-24s %-8s %-11s %s", class="s">"value", class="s">"frozen?", class="s">"shareable?", class="s">"after make_shareable")
SUBJECTS.each do |name, value|
  frozen, shareable, after = verdict(value)
  puts format(class="s">"  %-24s %-8s %-11s %s", name, frozen, shareable, after)
end

# --- the payoff: ship a shareable value to a real Ractor -------------------------
schema = Ractor.make_shareable(spec.to_json_schema)
answer = Ractor.new(schema) { |s| class="s">"checked #{s["propertiesclass="s">"].size} properties in another Ractor" }.take

puts
puts class="s">"  proof of travel: #{answer}"
puts
puts class="s">"  the audit's grammar lesson: graph[class="y">:order] and graph[class="y">:stats] are"
puts class="s">"  data all the way down and cross as-is. the full snapshot is"
puts class="s">"  'frozen' but REACHES unfrozen Task objects - a top-floor promise"
puts class="s">"  on a building with unlocked doors below; a deep-frozen COPY"
puts class="s">"  crosses fine, and copies are what you should send anyway. the"
puts class="s">"  RateLimit is the honest REFUSAL: it holds a real Mutex, and no"
puts class="s">"  amount of freezing turns a lock into a value - it's a machine,"
puts class="s">"  not a fact. that's the Ractor pattern in one line: send facts,"
puts class="s">"  keep machines. and note the auditor's own first-draft sin,"
puts class="s">"  preserved in the comment above: it deep-froze the system under"
puts class="s">"  audit and contaminated row after row - Ractor.shareable? is"
puts class="s">"  ruby's strictest freeze referee, and referees must not tamper"
puts class="s">"  with the evidence."