#!/usr/bin/env ruby
# run_conf10.rb — replay the draft-zambo-aer1-10 corpus against
# aer1verify.rb, mirroring aer-1/conformance.py's traversal and verdict
# logic vector for vector.
#
#   ruby run_conf10.rb [/path/to/aer-1]   # exit 0 iff CONFORMANCE OK
#
# Written by ARION, an autonomous agent.

require "json"
require "digest"
require_relative "aer1verify"

AER = ARGV[0] || "/workspace/research/zambo-aer1/aer-1"
$pass = 0; $fail = 0; $problems = []

def verdict(corpus, name, ok, detail = "")
  if ok
    $pass += 1; printf("[%-11s] %s: PASS\n", corpus, name)
  else
    $fail += 1; $problems << "#{corpus} #{name}"
    printf("[%-11s] %s: FAIL %s\n", corpus, name, detail)
  end
end

def reasons(r) = r[:failures].map { |f| f[:reason] }
OPT = { kind: "auto", strict: false, profile: false, anchor: false }.freeze

# --- valid/ -------------------------------------------------------------
Dir[File.join(AER, "test-vectors/valid/*.json")].sort.each do |f|
  r = verify_document(JSON.parse(File.read(f)), OPT)
  verdict("valid", File.basename(f), r[:failures].empty?, reasons(r).join("; "))
end

# --- invalid/ -----------------------------------------------------------
Dir[File.join(AER, "test-vectors/invalid/*.json")].sort.each do |f|
  r = verify_document(JSON.parse(File.read(f)), OPT)
  verdict("invalid", File.basename(f), !r[:failures].empty?, "accepted!")
end

# --- invalid-profile/ ---------------------------------------------------
Dir[File.join(AER, "test-vectors/invalid-profile/*.json")].sort.each do |f|
  doc = JSON.parse(File.read(f))
  core = verify_document(doc, OPT)
  prof = verify_document(doc, OPT.merge(profile: true))
  prof_fails = prof[:failures].select { |x| x[:check] == "reference-profile" }
  ok = core[:failures].empty? && !prof_fails.empty?
  verdict("invalid-profile", File.basename(f), ok,
          core[:failures].empty? ? "profile accepted" : "core: #{reasons(core).join(";")}")
end

# --- anchored/ -----------------------------------------------------------
Dir[File.join(AER, "test-vectors/anchored/*.json")].sort.each do |f|
  doc = JSON.parse(File.read(f))
  r = verify_document(doc, OPT.merge(anchor: true))
  core_fails = r[:failures].select { |x| x[:check] == "core" }
  tier_fails = r[:failures].select { |x| x[:check] == "disinterested-tier" }
  expect_pass = File.basename(f) == "anchored-valid.json"
  ok = core_fails.empty? && (expect_pass ? tier_fails.empty? : !tier_fails.empty?)
  verdict("anchored", File.basename(f), ok, reasons(r).join("; "))
end

# --- chain-vectors.json (v06 regression) --------------------------------
JSON.parse(File.read(File.join(AER, "chain-vectors.json")))["vectors"].each do |v|
  tl = v["timeline"] || v["entries"]
  r = verify_document(tl, OPT.merge(kind: "chain06"))
  ok = r[:failures].empty? == (v["expected_verdict"] == "valid")
  verdict("chain06", v["name"], ok, reasons(r).join("; "))
end

# --- chain-vectors-v07.json ---------------------------------------------
JSON.parse(File.read(File.join(AER, "chain-vectors-v07.json")))["vectors"].each do |v|
  tl = v["timeline"] || v["entries"]
  r = verify_document(tl, OPT.merge(kind: "chain"))
  ok = r[:failures].empty? == (v["expected_verdict"] == "valid")
  verdict("chain-v07", v["name"], ok, reasons(r).join("; "))
end

# --- commitment-vectors.json --------------------------------------------
JSON.parse(File.read(File.join(AER, "commitment-vectors.json")))["vectors"].each do |v|
  fails = verify_chain_commitment(v["timeline"], v["commitment"], OPT)
  ok = fails.empty? == (v["expected_verdict"] == "valid")
  verdict("commitment", v["name"], ok, fails.join("; "))
end

# --- merkle-vectors.json -------------------------------------------------
JSON.parse(File.read(File.join(AER, "merkle-vectors.json")))["vectors"].each do |v|
  if v["receipt_ids"]
    got = merkle_root(v["receipt_ids"])
    verdict("merkle", v["name"], got == v["expected_root"], "got #{got}")
  elsif v["leaves"]
    lvl = v["leaves"].sort_by { |l| l["seq"] }
          .map { |l| Digest::SHA256.digest(l["preimage"]) }
    while lvl.length > 1
      lvl << lvl[-1] if lvl.length.odd?
      lvl = lvl.each_slice(2).map { |a, b| Digest::SHA256.digest(a + b) }
    end
    got = lvl.empty? ? Digest::SHA256.hexdigest("") : lvl[0].unpack1("H*")
    ok = got == v["expected_root"] && got != v["must_not_equal"]
    verdict("merkle-legacy", v["name"], ok, "got #{got}")
  end
  if v["expected_workflow_verdict"]
    unless v["receipt_ids"]
      verdict("merkle-wf", v["name"], false, "no receipt_ids"); next
    end
    wf = {
      "type" => "verifiable-workflow-receipt", "version" => "1",
      "workflow_id" => "11111111-1111-1111-1111-111111111111",
      "receipt_id" => "22222222-2222-2222-2222-222222222222",
      "session_id" => "test-session", "goal" => "test workflow",
      "status" => "ok",
      "steps" => v["receipt_ids"].each_with_index.map { |rid, i| {
        "seq" => i + 1, "tool" => "test-tool", "receipt_id" => rid,
        "receipt_hash" => "a" * 64, "started_at" => "2026-01-01T00:00:00Z",
        "ended_at" => "2026-01-01T00:00:01Z", "status" => "ok" } },
      "merkle_root" => v["expected_root"],
      "output_hash" => "b" * 64,
      "verify_url" => "https://example.com/workflow/test",
    }
    wf_fails = check_workflow(wf, OPT)
    got_verdict = wf_fails.empty? ? "valid" : "invalid"
    ok = got_verdict == v["expected_workflow_verdict"]
    if ok && got_verdict == "invalid" && v["rejected_by"]
      ok = wf_fails.any? { |f| f.include?(v["rejected_by"]) }
    end
    verdict("merkle-wf", v["name"], ok, "verdict #{got_verdict}")
  end
end

printf("\n== SUMMARY ==  %d passed, %d failed\n", $pass, $fail)
if $fail > 0
  $problems.each { |p| puts " - #{p}" }
  exit 1
end
puts "CONFORMANCE OK (-10 corpus): all vectors behave as expected."
