Prd/components/backend/test/test_context_maintainer.rb
Lucy Doupalů be9f14ce34 Helpdesk - operator console + patched GrapheneOS Dialer for call handling
A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer
answers technician calls, records both call legs as separate channels, and a
Ruby backend transcribes them through Whisper and files an AI summary against
the caller.

Squashed to a single commit for sharing. No credentials are included; secrets
live outside the repo in /etc/helpdesk/env on the server or a gitignored
.claude/env.local locally. See .claude/env.local.example for the shape.

Start at README.md, then docs/architecture.md.
2026-07-27 18:50:32 +02:00

44 lines
2.2 KiB
Ruby

# frozen_string_literal: true
require_relative "../context_maintainer"
require "json"
$pass = 0; $fail = 0
def ok(d); $pass += 1; puts " ok #{d}"; end
def bad(d, g = nil); $fail += 1; puts " FAIL #{d}#{g.nil? ? '' : " (#{g.inspect})"}"; end
def eq(a, b, d); a == b ? ok(d) : bad(d, a); end
def truthy(x, d); x ? ok(d) : bad(d, x); end
def env(summary:, other:)
JSON.generate("choices" => [{ "message" => { "content" =>
JSON.generate("summary" => summary, "other_context" => other) } }], "usage" => { "cost" => 0.001 })
end
puts "maintainer: builds {summary, other_context}"
m = Helpdesk::ContextMaintainer.new(api_key: "x",
transport: ->(_u, _h, _b) { [200, env(summary: "Souhrn.", other: ["A", "B"])] })
r = m.build(mode: :incremental, old_ai_context: { "summary" => "", "other_context" => [] },
digests: ["digest"], ledger: [])
truthy(r[:ok], "ok")
eq(r[:ai_context]["summary"], "Souhrn.", "summary rendered")
eq(r[:ai_context]["other_context"], ["A", "B"], "other_context rendered")
puts "maintainer: pinned section forced verbatim + flags divergence"
r2 = m.build(mode: :incremental, old_ai_context: { "summary" => "PIN", "other_context" => [] },
pinned_sections: { "summary" => "PIN" }, digests: ["d"])
eq(r2[:ai_context]["summary"], "PIN", "pinned summary is the operator text, not the LLM's")
truthy(r2[:needs_review], "LLM diverged from the pin -> needs_review")
puts "maintainer: model selection per mode"
seen = []
m2 = Helpdesk::ContextMaintainer.new(api_key: "x",
transport: ->(_u, _h, b) { seen << JSON.parse(b)["model"]; [200, env(summary: "s", other: [])] })
m2.build(mode: :incremental, old_ai_context: {}, digests: [])
m2.build(mode: :rebuild, old_ai_context: {}, digests: [])
eq(seen[0], "google/gemini-3.6-flash", "incremental uses the configured model")
eq(seen[1], "google/gemini-3.6-flash", "rebuild uses the configured model")
puts "maintainer: no key -> graceful no-op"
truthy(Helpdesk::ContextMaintainer.new(api_key: "").respond_to?(:build), "constructs without a key")
r3 = Helpdesk::ContextMaintainer.new(api_key: "").build(mode: :incremental, old_ai_context: {})
truthy(!r3[:ok], "no key + no transport -> ok:false (no crash)")
puts "\n#{$pass} passed, #{$fail} failed"; exit($fail.zero? ? 0 : 1)