agentic examples

The Plan Kata

The Plan Kata: red, green, refactor - for a plan. The "tests" are assertions about the graph (one root, one leaf, labeled joins, nothing too deep), written BEFORE any tasks exist. Each step adds the smallest thing that moves a red line green, and the refactor step changes structure with the assertions standing guard. You've TDD'd methods; plans deserve the same discipline.

Testing & Verification Round 11 Katrina Owen exit 0

source on github

bundle exec ruby examples/plan_kata.rb

a real captured run

THE PLAN KATA (assertions first, tasks second)

  step: empty plan (the honest starting point)
    has exactly one entry point      RED
    has exactly one deliverable      RED
    every join names its inputs      green
    no deeper than four stages       green
    no orphan tasks                  green
    -> 2 red

  step: add the entry point
    has exactly one entry point      green
    has exactly one deliverable      green
    every join names its inputs      green
    no deeper than four stages       green
    no orphan tasks                  green
    -> 0 red

  step: add parse
    has exactly one entry point      green
    has exactly one deliverable      green
    every join names its inputs      green
    no deeper than four stages       green
    no orphan tasks                  green
    -> 0 red

  step: bolt on a price feed (two sins)
    has exactly one entry point      RED
    has exactly one deliverable      green
    every join names its inputs      RED
    no deeper than four stages       green
    no orphan tasks                  green
    -> 2 red

  step: refactor in place: rewire, relabel
    has exactly one entry point      green
    has exactly one deliverable      green
    every join names its inputs      green
    no deeper than four stages       green
    no orphan tasks                  green
    -> 0 red

  the kata's shape is the point: the assertions existed before
  the plan did, every addition was the smallest thing that moved
  a line, and the two deliberate sins were CAUGHT and NAMED by
  tests written when nobody was defensive about the design yet.
  and the refactor was a real refactor this time: rewire_task
  (round 12, this kata's own ask) changed the plan's shape without
  demolishing its identity - red, green, REFACTOR, with all three
  words meaning what they say. kata complete, all green.

source

# frozen_string_literal: true

# The Plan Kata: red, green, refactor - for a plan. The "tests" are
# assertions about the graph (one root, one leaf, labeled joins,
# nothing too deep), written BEFORE any tasks exist. Each step adds
# the smallest thing that moves a red line green, and the refactor
# step changes structure with the assertions standing guard. You've
# TDD'd methods; plans deserve the same discipline.
#
#   bundle exec ruby examples/plan_kata.rb
#
# Runs offline; exits 1 if the kata ends with a red assertion.

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

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

# The test list, written first - what a GOOD ingest plan looks like,
# structurally, before we know what the tasks are
ASSERTIONS = {
  class="s">"has exactly one entry point" => ->(g) { g[class="y">:stats][class="y">:roots].size == 1 },
  class="s">"has exactly one deliverable" => ->(g) { g[class="y">:stats][class="y">:leaves].size == 1 },
  class="s">"every join names its inputs" => ->(g) {
    g[class="y">:dependencies].select { |_, d| d.size >= 2 }.keys.all? { |id|
      g[class="y">:edges].select { |e| e[class="y">:to] == id }.all? { |e| e[class="y">:label] }
    }
  },
  class="s">"no deeper than four stages" => ->(g) { g[class="y">:stats][class="y">:max_depth] <= 4 },
  class="s">"no orphan tasks" => ->(g) {
    g[class="y">:tasks].size < 2 || (g[class="y">:stats][class="y">:roots] & g[class="y">:stats][class="y">:leaves]).empty?
  }
}.freeze

def check(orchestrator)
  graph = orchestrator.graph
  ASSERTIONS.transform_values { |assertion| assertion.call(graph) }
end

def report(step, results)
  reds = results.count { |_, ok| !ok }
  puts class="s">"  step: #{step}"
  results.each { |name, ok| puts format(class="s">"    %-32s %s", name, ok ? class="s">"green" : class="s">"RED") }
  puts format(class="s">"    -> %d red", reds)
  puts
end

puts class="s">"THE PLAN KATA (assertions first, tasks second)"
puts

# RED: no tasks at all - most assertions can't hold on emptiness
o = Agentic:class="y">:PlanOrchestrator.new
report(class="s">"empty plan (the honest starting point)", check(o))

# GREEN, smallest step: one task satisfies one-root-one-leaf trivially
ingest = task_named(class="s">"ingest")
o.add_task(ingest)
report(class="s">"add the entry point", check(o))

# Grow: parse feeds off ingest; deliverable moves - still green
parse = task_named(class="s">"parse")
o.add_task(parse, [ingest])
report(class="s">"add parse", check(o))

# RED on purpose: a second source creates a second root, and an
# unlabeled join - two assertions object, and they name the problem
prices = task_named(class="s">"prices")
merge = task_named(class="s">"merge")
o.add_task(prices)
o.add_task(merge, [parse, prices])
report(class="s">"bolt on a price feed (two sins)", check(o))

# GREEN again: REFACTOR IN PLACE - the round-12 release gave plans
# rewire_task, so fixing the shape no longer means demolishing it.
# Route the price feed through the one door, and give the merge its
# labels; the assertions stand guard the whole time.
o.rewire_task(prices, [ingest])
o.rewire_task(merge, needs: {parsed: parse, prices: prices})
report_task = task_named(class="s">"report")
o.add_task(report_task, [merge])
final = check(o)
report(class="s">"refactor in place: rewire, relabel", final)

reds = final.count { |_, ok| !ok }
puts class="s">"  the kata's shape is the point: the assertions existed before"
puts class="s">"  the plan did, every addition was the smallest thing that moved"
puts class="s">"  a line, and the two deliberate sins were CAUGHT and NAMED by"
puts class="s">"  tests written when nobody was defensive about the design yet."
puts class="s">"  and the refactor was a real refactor this time: rewire_task"
puts class="s">"  (round 12, this kata's own ask) changed the plan's shape without"
puts class="s">"  demolishing its identity - red, green, REFACTOR, with all three"
puts class="s">"  words meaning what they say. #{(reds == 0) ? "kata complete, all green.class="s">" : "KATA INCOMPLETE.class="s">"}"
exit((reds == 0) ? 0 : 1)