Files
bikoret/vav_pipeline/test/bigdei_kodesh_test.exs
T
Scott KarpandClaude Opus 4.6 191d76b480 Bigdei Kodesh: HTTP API layer — four garments for four access tiers
Shemot 28:2 — V'asita vigdei kodesh l'Aharon achicha,
l'khavod ul'tifaret.

The builder makes the garments. The kohen wears them.

Four access tiers (Operations spec §1.1):
- Pe'ah (GET/POST /peah/ask) — public, no auth, no tracking.
  The stranger is safe to approach.
- Courtyard (POST /courtyard/offering) — Bearer token auth,
  offering types: shelamim, olah, chatat, minchah
- Chatzer (POST /chatzer/sanhedrin) — Sanhedrin deliberation,
  returns majority/minority with preserved dissent
- Kodesh (GET /kodesh/health, /kodesh/status) — operator interface,
  health checks for K8s liveness/readiness probes

Error format follows chatat protocol (Operations spec §1.2):
  KIYOR_* (422), SHABBAT (503), MANNA_DEPLETED (503),
  CLOUD_MOVING (503), HALT_* (503), UNAUTHORIZED (401)

Implementation:
- Plug.Router with Bandit HTTP server
- Added to supervision tree via maybe_add_http_server
- Checks system availability (Shabbat, halt) before processing
- Health check reads L1 integrity, cloud, manna, halt monitor
- Status shows all component states, signal count, refuge list
- 16 API tests covering all four tiers + error format

All 235 Elixir + 19 L3 + 195 Prolog + 33 Haskell = 463+ tests, 0 failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 07:32:15 -04:00

252 lines
8.1 KiB
Elixir

defmodule VavPipeline.BigdeiKodeshTest do
@moduledoc """
Tests for the Bigdei Kodesh — the HTTP API layer.
Shemot 28:2 — V'asita vigdei kodesh l'Aharon achicha,
l'khavod ul'tifaret.
Four garments for four access tiers:
/peah/* — public, no auth
/courtyard/* — authenticated
/chatzer/* — full access
/kodesh/* — operator
"""
use ExUnit.Case, async: false
import Plug.Test
import Plug.Conn
alias VavPipeline.BigdeiKodesh.Router
@opts Router.init([])
# ============================================================
# Pe'ah — Public Endpoint (Machaneh Yisrael)
# ============================================================
describe "Pe'ah endpoint" do
test "GET /peah/ask without question returns usage" do
conn =
conn(:get, "/peah/ask")
|> Router.call(@opts)
assert conn.status == 200
body = Jason.decode!(conn.resp_body)
assert body["message"] =~ "Shorashim"
assert body["usage"] =~ "/peah/ask"
end
test "GET /peah/ask with question parameter processes it" do
conn =
conn(:get, "/peah/ask?question=What+is+bereishit")
|> Router.call(@opts)
# Should return 200 or 503 (if waiting for provision)
assert conn.status in [200, 503]
end
test "POST /peah/ask with valid question" do
conn =
conn(:post, "/peah/ask", Jason.encode!(%{question: "What is bereishit?"}))
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
assert conn.status in [200, 503]
body = Jason.decode!(conn.resp_body)
if conn.status == 200 do
assert Map.has_key?(body, "answer") or Map.has_key?(body, "processing")
end
end
test "POST /peah/ask without question returns 422" do
conn =
conn(:post, "/peah/ask", Jason.encode!(%{not_question: "wrong field"}))
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
assert conn.status == 422
body = Jason.decode!(conn.resp_body)
assert body["error"]["code"] == "KIYOR_VALIDATION_FAILED"
assert body["error"]["type"] == "purification_needed"
end
test "POST /peah/ask with empty question returns 422" do
conn =
conn(:post, "/peah/ask", Jason.encode!(%{question: ""}))
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
assert conn.status == 422
end
end
# ============================================================
# Courtyard — Authenticated Endpoint
# ============================================================
describe "Courtyard endpoint" do
test "POST /courtyard/offering without auth returns 401" do
conn =
conn(:post, "/courtyard/offering", Jason.encode!(%{content: "test"}))
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
assert conn.status == 401
body = Jason.decode!(conn.resp_body)
assert body["error"]["code"] == "UNAUTHORIZED"
end
test "POST /courtyard/offering with auth but no content returns 422" do
conn =
conn(:post, "/courtyard/offering", Jason.encode!(%{offering_type: "shelamim"}))
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", "Bearer test-token")
|> Router.call(@opts)
assert conn.status == 422
body = Jason.decode!(conn.resp_body)
assert body["error"]["code"] == "KIYOR_VALIDATION_FAILED"
end
test "POST /courtyard/offering with auth and content processes" do
conn =
conn(:post, "/courtyard/offering", Jason.encode!(%{
content: "bereishit bara elohim",
offering_type: "shelamim"
}))
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", "Bearer test-token")
|> Router.call(@opts)
assert conn.status in [200, 503]
if conn.status == 200 do
body = Jason.decode!(conn.resp_body)
assert Map.has_key?(body, "offering_id")
assert Map.has_key?(body, "offering_receipt")
assert body["offering_receipt"]["type"] == "shelamim"
end
end
end
# ============================================================
# Chatzer — Sanhedrin Endpoint
# ============================================================
describe "Chatzer endpoint" do
test "POST /chatzer/sanhedrin without auth returns 401" do
conn =
conn(:post, "/chatzer/sanhedrin", Jason.encode!(%{case: "test case"}))
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
assert conn.status == 401
end
test "POST /chatzer/sanhedrin without case returns 422" do
conn =
conn(:post, "/chatzer/sanhedrin", Jason.encode!(%{not_case: "wrong field"}))
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", "Bearer test-token")
|> Router.call(@opts)
assert conn.status == 422
end
test "POST /chatzer/sanhedrin with valid case deliberates" do
conn =
conn(:post, "/chatzer/sanhedrin", Jason.encode!(%{
case: "Is cooking on Shabbat permitted for pikuach nefesh?"
}))
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", "Bearer test-token")
|> Router.call(@opts)
assert conn.status == 200
body = Jason.decode!(conn.resp_body)
assert Map.has_key?(body, "case_ref")
assert Map.has_key?(body, "deliberation")
assert body["deliberation"]["outcome"] in ["accepted", "rejected", "teiku"]
assert body["note"] =~ "not a binding ruling"
end
end
# ============================================================
# Kodesh — Operator Endpoint
# ============================================================
describe "Kodesh endpoint" do
test "GET /kodesh/health returns health check" do
conn =
conn(:get, "/kodesh/health")
|> Router.call(@opts)
assert conn.status in [200, 503]
body = Jason.decode!(conn.resp_body)
assert Map.has_key?(body, "overall")
assert Map.has_key?(body, "checks")
assert body["overall"] in ["healthy", "degraded", "critical", "shabbat"]
# Required health checks
assert Map.has_key?(body["checks"], "l1_hash")
assert Map.has_key?(body["checks"], "halt_monitor_alive")
assert Map.has_key?(body["checks"], "esh_tamid")
end
test "GET /kodesh/status returns system status" do
conn =
conn(:get, "/kodesh/status")
|> Router.call(@opts)
assert conn.status == 200
body = Jason.decode!(conn.resp_body)
assert Map.has_key?(body, "cloud_state")
assert Map.has_key?(body, "components")
assert Map.has_key?(body, "halt_status")
assert Map.has_key?(body, "signal_count")
end
end
# ============================================================
# Error handling — Chatat protocol
# ============================================================
describe "error handling" do
test "unknown endpoint returns 404" do
conn =
conn(:get, "/unknown/path")
|> Router.call(@opts)
assert conn.status == 404
body = Jason.decode!(conn.resp_body)
assert body["error"]["code"] == "NOT_FOUND"
end
test "all errors follow chatat format" do
conn =
conn(:post, "/peah/ask", Jason.encode!(%{}))
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
assert conn.status == 422
body = Jason.decode!(conn.resp_body)
# Chatat format: error.code, error.type, error.message, error.guidance
assert Map.has_key?(body["error"], "code")
assert Map.has_key?(body["error"], "type")
assert Map.has_key?(body["error"], "message")
assert Map.has_key?(body["error"], "guidance")
end
test "all responses are JSON" do
conn =
conn(:get, "/kodesh/health")
|> Router.call(@opts)
content_type = get_resp_header(conn, "content-type")
assert Enum.any?(content_type, &String.contains?(&1, "application/json"))
end
end
end