agentic examples

Configurable Cops

Configurable Cops: a style guide nobody can configure is a style FIGHT on a delay timer. RuboCop's deepest lesson isn't any single cop - it's the .yml: enable/disable per cop, parameters instead of hardcoded taste, and (the policy that saved a thousand upgrades) NEW COPS ARRIVE PENDING - they never fire until the team opts in, so a linter update can't turn a green build red by surprise.

Observability & Ops Round 16 Bozhidar Batsov exit 0

source on github

bundle exec ruby examples/configurable_cops.rb

a real captured run

CONFIGURABLE COPS (same contract, two teams, two configs)

  team A (defaults + opted into pending cop): 4 offense(s)
    Documentation/Description      capability has no description
    Style/EnumOrder                input :mode enum is not sorted
    Metrics/RequiredInputCount     6 required inputs (Max: 5)
    Lint/UntypedField              input :ref has no type

  team B (raised Max, disabled EnumOrder, pending cop stays off): 1 offense(s)
    Documentation/Description      capability has no description

  the pending status is the load-bearing idea: Lint/UntypedField
  shipped in this release, and for team B it fired ZERO times -
  not because it's wrong but because a linter update must never
  turn a green build red without the team's signature. team A
  signed. and look at what team B's config really is: a RECORD OF
  DECISIONS - 'Max: 8' with a comment, blame-able to a person and
  a date, instead of the same argument re-fought in every review.
  hardcoded taste creates rebels; configurable taste creates a
  paper trail. the style guide is the conversation; the config
  file is its minutes.

source

# frozen_string_literal: true

# Configurable Cops: a style guide nobody can configure is a style
# FIGHT on a delay timer. RuboCop's deepest lesson isn't any single
# cop - it's the .yml: enable/disable per cop, parameters instead of
# hardcoded taste, and (the policy that saved a thousand upgrades)
# NEW COPS ARRIVE PENDING - they never fire until the team opts in,
# so a linter update can't turn a green build red by surprise.
#
#   bundle exec ruby examples/configurable_cops.rb
#
# Runs offline; one contract, two teams, two verdicts, zero fights.

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

# The defendant, unchanged between teams
CONTRACT = {
  name: class="s">"quote_shipping", description: class="s">"", version: class="s">"1.0.0",
  inputs: {
    mode: {type: class="s">"string", required: true, enum: %w[sea air road]},
    weight_kg: {type: class="s">"number", required: true, min: 0, max: 5_000},
    a: {type: class="s">"string", required: true}, b: {type: class="s">"string", required: true},
    c: {type: class="s">"string", required: true}, d: {type: class="s">"string", required: true},
    ref: {}
  }
}.freeze

# Cops carry status (:stable or :pending) and read their params from config
COPS = {
  class="s">"Documentation/Description" => {
    status: class="y">:stable,
    check: ->(s, _p) { s[class="y">:description].to_s.empty? ? [class="s">"capability has no description"] : [] }
  },
  class="s">"Style/EnumOrder" => {
    status: class="y">:stable,
    check: ->(s, _p) { s[class="y">:inputs].select { |_, d| d[class="y">:enum] && d[class="y">:enum] != d[class="y">:enum].sort }.map { |k, _| class="s">"input :#{k} enum is not sorted" } }
  },
  class="s">"Metrics/RequiredInputCount" => {
    status: class="y">:stable, defaults: {class="s">"Max" => 5},
    check: ->(s, p) {
      required = s[class="y">:inputs].count { |_, d| d[class="y">:required] }
      (required > p[class="s">"Max"]) ? [class="s">"#{required} required inputs (Max: #{p["Maxclass="s">"]})"] : []
    }
  },
  class="s">"Lint/UntypedField" => {
    status: class="y">:pending, # arrived in this release: fires ONLY if the team opts in
    check: ->(s, _p) { s[class="y">:inputs].select { |_, d| d[class="y">:type].nil? }.map { |k, _| class="s">"input :#{k} has no type" } }
  }
}.freeze

def inspect_with(config_yaml, spec)
  config = YAML.safe_load(config_yaml) || {}
  COPS.flat_map do |name, cop|
    cop_config = config.fetch(name, {})
    enabled = cop_config.fetch(class="s">"Enabled", cop[class="y">:status] == class="y">:stable)
    next [] unless enabled

    params = (cop[class="y">:defaults] || {}).merge(cop_config.except(class="s">"Enabled"))
    cop[class="y">:check].call(spec, params).map { |offense| [name, offense] }
  end
end

TEAM_A = <<~YAML
  # team A: defaults, plus we opted into the new pending cop
  Lint/UntypedField:
    Enabled: true
YAML

TEAM_B = <<~YAML
  # team B: we have seven required inputs and we've MET our capability;
  # raising Max is a decision, recorded here, reviewable in git blame
  Metrics/RequiredInputCount:
    Max: 8
  Style/EnumOrder:
    Enabled: false   # our enums are ordered by freight class, not alphabet
YAML

puts class="s">"CONFIGURABLE COPS (same contract, two teams, two configs)"
puts
[[class="s">"team A (defaults + opted into pending cop)", TEAM_A],
  [class="s">"team B (raised Max, disabled EnumOrder, pending cop stays off)", TEAM_B]].each do |team, config|
  offenses = inspect_with(config, CONTRACT)
  puts class="s">"  #{team}: #{offenses.size} offense(s)"
  offenses.each { |cop, offense| puts format(class="s">"    %-30s %s", cop, offense) }
  puts
end

puts class="s">"  the pending status is the load-bearing idea: Lint/UntypedField"
puts class="s">"  shipped in this release, and for team B it fired ZERO times -"
puts class="s">"  not because it's wrong but because a linter update must never"
puts class="s">"  turn a green build red without the team's signature. team A"
puts class="s">"  signed. and look at what team B's config really is: a RECORD OF"
puts class="s">"  DECISIONS - 'Max: 8' with a comment, blame-able to a person and"
puts class="s">"  a date, instead of the same argument re-fought in every review."
puts class="s">"  hardcoded taste creates rebels; configurable taste creates a"
puts class="s">"  paper trail. the style guide is the conversation; the config"
puts class="s">"  file is its minutes."