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.
104 lines
6.6 KiB
Ruby
104 lines
6.6 KiB
Ruby
# frozen_string_literal: true
|
|
# Zero-dependency offline tests for the pure ledger reducer. Run: ruby components/backend/test/test_ledger.rb
|
|
require_relative "../lib/helpdesk/ledger"
|
|
|
|
$pass = 0; $fail = 0
|
|
def ok(d); $pass += 1; puts " ok #{d}"; end
|
|
def bad(d, got = nil); $fail += 1; puts " FAIL #{d}#{got.nil? ? '' : " (got: #{got.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
|
|
|
|
L = Helpdesk::Ledger
|
|
IDS = (1..9999).to_a
|
|
def mint; -> { "led#{IDS.shift}" }; end
|
|
# deterministic tiny vectors so cosine is predictable; entry_vec resolves from the delta that created it.
|
|
def d(entry_id:, decision:, q: "q", vec: nil, quote: "…")
|
|
{ "entry_id" => entry_id, "question" => q, "decision" => decision, "quote" => quote, "question_vec" => vec }
|
|
end
|
|
# resolver: entries created in these tests store their raw vec under vec_ref["_test_vec"] for lookup
|
|
def resolver; ->(e) { e.dig("vec_ref", "_test_vec") }; end
|
|
|
|
puts "packing round-trips"
|
|
v = [0.1, -0.25, 1.0, 0.0]
|
|
eq(L.unpack_vec(L.pack_vec(v)).map { |x| x.round(4) }, v, "pack/unpack Float32 round-trips (to 4dp)")
|
|
truthy(L.pack_vec(v).is_a?(String) && !L.pack_vec(v).include?("\n"), "packed vec is a single-line string")
|
|
|
|
puts "cosine"
|
|
eq(L.cosine([1,0], [1,0]), 1.0, "identical -> 1.0")
|
|
eq(L.cosine([1,0], [0,1]), 0.0, "orthogonal -> 0.0")
|
|
eq(L.cosine([1,0], [1,2,3]), 0.0, "dim mismatch -> 0.0 (never raises)")
|
|
|
|
puts "canonical entry_id keying"
|
|
r = L.apply(ledger: [], deltas: [d(entry_id: nil, decision: "no", q: "reset?")],
|
|
event_id: 1, started_at: "2026-07-01T09:00:00Z", applied_event_ids: [], entry_vec: resolver, next_id: mint)
|
|
eq(r[:ledger].size, 1, "first delta creates one entry")
|
|
eq(r[:ledger][0]["decision"], "no", "decision recorded")
|
|
eq(r[:ledger][0]["last_event_id"], 1, "last_event_id set")
|
|
truthy(r[:changed], "changed=true on new entry")
|
|
led = r[:ledger]; eid = led[0]["id"]
|
|
r2 = L.apply(ledger: led, deltas: [d(entry_id: eid, decision: "no", q: "reset again?")],
|
|
event_id: 2, started_at: "2026-07-02T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
eq(r2[:ledger].size, 1, "same entry_id + same decision -> refresh, no new entry")
|
|
eq(r2[:ledger][0]["last_event_id"], 2, "refresh updates last_event_id")
|
|
|
|
puts "never flip a past no: later reversal supersedes + flags, old kept"
|
|
r3 = L.apply(ledger: r2[:ledger], deltas: [d(entry_id: eid, decision: "yes")],
|
|
event_id: 3, started_at: "2026-07-03T09:00:00Z", applied_event_ids: [1, 2], entry_vec: resolver, next_id: mint)
|
|
eq(r3[:ledger].size, 2, "reversal APPENDS (old retained), never mutates in place")
|
|
old = r3[:ledger].find { |e| e["id"] == eid }
|
|
neu = r3[:ledger].find { |e| e["id"] != eid }
|
|
eq(old["decision"], "no", "old 'no' entry unchanged")
|
|
eq(old["superseded_by"], neu["id"], "old entry superseded_by the new one")
|
|
truthy(old["contradiction"] && neu["contradiction"], "both flagged contradiction")
|
|
eq(neu["decision"], "yes", "new entry carries the new decision")
|
|
|
|
puts "out-of-order (older) reversal does NOT supersede the current decision"
|
|
r4 = L.apply(ledger: r2[:ledger], deltas: [d(entry_id: eid, decision: "yes")],
|
|
event_id: 4, started_at: "2026-06-01T09:00:00Z", applied_event_ids: [1, 2], entry_vec: resolver, next_id: mint)
|
|
older = r4[:ledger].find { |e| e["id"] == eid }
|
|
eq(older["decision"], "no", "current 'no' stays current when the reversing event is OLDER")
|
|
truthy(older["superseded_by"].nil?, "older reversal does not supersede")
|
|
truthy(r4[:ledger].any? { |e| e["contradiction"] }, "older reversal still recorded + flagged for audit")
|
|
|
|
puts "idempotency per event_id"
|
|
r5 = L.apply(ledger: r2[:ledger], deltas: [d(entry_id: eid, decision: "yes")],
|
|
event_id: 2, started_at: "2026-07-02T09:00:00Z", applied_event_ids: [1, 2], entry_vec: resolver, next_id: mint)
|
|
eq(r5[:ledger].size, 1, "re-applying an already-applied event_id is a no-op")
|
|
truthy(!r5[:changed], "no-op apply reports changed=false")
|
|
|
|
puts "cosine backstop: null entry_id, near-match same decision -> refresh"
|
|
base = L.apply(ledger: [], deltas: [d(entry_id: nil, decision: "no", vec: [1.0, 0.0])],
|
|
event_id: 1, started_at: "2026-07-01T09:00:00Z", applied_event_ids: [], entry_vec: nil, next_id: mint)[:ledger]
|
|
base[0]["vec_ref"] = { "_test_vec" => [1.0, 0.0] } # stash the vec so the resolver can find it
|
|
r6 = L.apply(ledger: base, deltas: [d(entry_id: nil, decision: "no", vec: [0.98, 0.02])],
|
|
event_id: 2, started_at: "2026-07-02T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
eq(r6[:ledger].size, 1, "near-match (cosine>=0.86) same decision -> refresh, no new entry")
|
|
|
|
puts "cosine backstop: near-match DIFFERENT decision -> contradiction"
|
|
r7 = L.apply(ledger: base, deltas: [d(entry_id: nil, decision: "yes", vec: [0.98, 0.02])],
|
|
event_id: 3, started_at: "2026-07-03T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
eq(r7[:ledger].size, 2, "near-match different decision -> append")
|
|
truthy(r7[:ledger].all? { |e| e["contradiction"] }, "both flagged contradiction")
|
|
|
|
puts "cosine below threshold -> new entry; nil vec -> new + flagged"
|
|
r8 = L.apply(ledger: base, deltas: [d(entry_id: nil, decision: "no", vec: [0.0, 1.0])],
|
|
event_id: 4, started_at: "2026-07-04T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
eq(r8[:ledger].size, 2, "far vector -> distinct new entry")
|
|
r9 = L.apply(ledger: base, deltas: [d(entry_id: nil, decision: "no", vec: nil)],
|
|
event_id: 5, started_at: "2026-07-05T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
neu9 = r9[:ledger].find { |e| e["last_event_id"] == 5 }
|
|
truthy(neu9 && neu9["contradiction"], "embed-failed (nil vec) new entry flagged for review, never silently merged")
|
|
|
|
puts "unknown/foreign entry_id falls back to the null path (never nil-derefs)"
|
|
r10 = L.apply(ledger: base, deltas: [d(entry_id: "does-not-exist", decision: "no", vec: [0.0, 1.0])],
|
|
event_id: 6, started_at: "2026-07-06T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
eq(r10[:ledger].size, 2, "unknown entry_id -> treated as null -> new entry (no crash)")
|
|
|
|
puts "FIX 6: foreign entry_id + nil vec -> new entry flagged contradiction"
|
|
r11 = L.apply(ledger: base, deltas: [d(entry_id: "does-not-exist", decision: "no", vec: nil)],
|
|
event_id: 7, started_at: "2026-07-07T09:00:00Z", applied_event_ids: [1], entry_vec: resolver, next_id: mint)
|
|
neu11 = r11[:ledger].find { |e| e["last_event_id"] == 7 }
|
|
truthy(neu11 && neu11["contradiction"], "foreign entry_id + nil question_vec -> new entry flagged contradiction")
|
|
|
|
puts "\n#{$pass} passed, #{$fail} failed"
|
|
exit($fail.zero? ? 0 : 1)
|