Tablet 46: the watch — rate limits at every gate, per IP at the pe'ah, per key inside

Tamid §1.1 wrote the pe'ah's limit (10/min, 100/h per IP); nothing
enforced it, on any tier, and every admitted request spends manna.

VavPipeline.BigdeiKodesh.Mishmar: fixed minute and hour windows per
subject in ETS, the subject stored only as sha256(boot salt, tier,
subject) — no IP and no key is ever in memory as itself, the sweep
drops closed windows, nothing survives a restart (the Tamid's "not
logged beyond the current request", kept in memory too). A refused
knock is not counted. 429 RATE_LIMITED with Retry-After and the manna
explanation (Shemot 16:18). Pe'ah per peer address; courtyard and
chatzer per key, after the gate (a wrong key is 401 and never counted).
Numbers: pe'ah 10/100 (Tamid), courtyard 20/200 and chatzer 5/60
(from Construction §2.3; config :rate_limits).

Service shorashim-external: externalTrafficPolicy Local. With Cluster
the pod saw every caller as the node, 91.92.153.113 (observed via
/proc/net/tcp) — a per-IP limit would have been one bucket for the
world.

Spec: tamid §1.1 (watch, 429 rows, the Service note), KOHEN.md.
Doorpost 42b38626… → e4e3d56d…. tablet46_mishmar_test; Elixir 533/0
(L3 on and off).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Fable 5.1 committed 2026-10-06 16:08:57 +00:00
1 parent 79eb34840f
commit 54ca651f37
12 files changed
+406 -17

No files matched your search

-1
View File
@@ -1 +0,0 @@
{"consumed":{"api_calls_external":0,"compute_units":3,"memory_mb":0,"sanhedrin_panels_max":0,"storage_delta_mb":0},"cycle_date":"2026-10-06","written_at":"2026-10-06T15:15:24.042079Z"}
+135
View File
@@ -0,0 +1,135 @@
defmodule VavPipeline.Tablet46MishmarTest do
@moduledoc """
Tablet 46 (2026-10-06) — no gate had a watch.
Tamid §1.1 writes the pe'ah's limit in the spec; nothing enforced it,
on any tier. Every admitted request spends manna; one caller could
gather the whole omer.
"""
use ExUnit.Case, async: false
import Plug.Test
import Plug.Conn
alias VavPipeline.BigdeiKodesh.{Mishmar, Router}
@opts Router.init([])
setup do
original = Application.get_env(:vav_pipeline, :rate_limits)
Application.put_env(:vav_pipeline, :rate_limits,
peah: [minute: 3, hour: 5],
courtyard: [minute: 2, hour: 100],
chatzer: [minute: 10_000, hour: 100_000]
)
Mishmar.reset()
on_exit(fn ->
Application.put_env(:vav_pipeline, :rate_limits, original)
Mishmar.reset()
end)
:ok
end
describe "Mishmar.knock/3" do
test "counts the minute, then the hour, per subject; a refusal is not counted" do
t = 1_000_000 * 60
assert {:ok, 2} = Mishmar.knock(:peah, "a", t)
assert {:ok, 1} = Mishmar.knock(:peah, "a", t + 1)
assert {:ok, 0} = Mishmar.knock(:peah, "a", t + 2)
assert {:error, :minute, 57} = Mishmar.knock(:peah, "a", t + 3)
assert {:error, :minute, 57} = Mishmar.knock(:peah, "a", t + 3)
# Another subject is another count.
assert {:ok, 2} = Mishmar.knock(:peah, "b", t + 3)
# The next minute opens — but the hour (5) is nearly spent: 3 so far.
assert {:ok, 2} = Mishmar.knock(:peah, "a", t + 60)
assert {:ok, 1} = Mishmar.knock(:peah, "a", t + 61)
assert {:error, :hour, retry} = Mishmar.knock(:peah, "a", t + 62)
assert retry == 3600 - rem(t + 62, 3600)
# The next hour opens.
assert {:ok, 2} = Mishmar.knock(:peah, "a", t + 3600)
end
test "tiers are counted apart" do
t = 2_000_000 * 60
assert {:ok, 1} = Mishmar.knock(:courtyard, "k", t)
assert {:ok, 0} = Mishmar.knock(:courtyard, "k", t)
assert {:error, :minute, _} = Mishmar.knock(:courtyard, "k", t)
assert {:ok, 2} = Mishmar.knock(:peah, "k", t)
end
test "the sweep drops closed windows and nothing else" do
t = 3_000_000 * 60
assert {:ok, _} = Mishmar.knock(:peah, "old", t)
assert {:ok, _} = Mishmar.knock(:peah, "new", t + 7200)
:ok = Mishmar.sweep(Mishmar, t + 7200)
# "old" has been forgotten entirely; "new" is still counted.
assert :ets.info(Mishmar, :size) == 2
assert {:ok, 1} = Mishmar.knock(:peah, "new", t + 7200)
end
test "the table holds hashes, never the subject" do
:ok = Mishmar.reset()
{:ok, _} = Mishmar.knock(:peah, "203.0.113.7")
for {{id, _, _}, _} <- :ets.tab2list(Mishmar) do
assert is_binary(id) and byte_size(id) == 32
refute id =~ "203.0.113"
end
end
end
describe "at the router" do
test "the pe'ah: the fourth knock from one address in a minute is 429 with Retry-After and the manna explanation" do
statuses = for _ <- 1..4, do: ask({203, 0, 113, 9}).status
assert Enum.take(statuses, 3) |> Enum.all?(&(&1 != 429))
conn = ask({203, 0, 113, 9})
assert conn.status == 429
[retry] = get_resp_header(conn, "retry-after")
assert String.to_integer(retry) in 1..60
body = Jason.decode!(conn.resp_body)
assert body["error"]["code"] == "RATE_LIMITED"
assert body["error"]["guidance"]["manna"] =~ "Shemot 16:18"
# Another address is not held back by this one.
refute ask({203, 0, 113, 10}).status == 429
end
test "the courtyard: per key, and only past the gate" do
# A wrong key knocks all it likes and is never counted — 401, not 429.
for _ <- 1..5, do: assert(bedikah("Bearer wrong").status == 401)
assert bedikah("Bearer test-token").status != 429
assert bedikah("Bearer test-token").status != 429
conn = bedikah("Bearer test-token")
assert conn.status == 429
assert Jason.decode!(conn.resp_body)["error"]["guidance"]["issue"] =~ "courtyard allows 2 a minute"
# The chatzer key is its own hand, even at the same door.
refute bedikah("Bearer chatzer-test-token").status == 429
end
end
defp ask(ip) do
%{conn(:post, "/peah/ask", Jason.encode!(%{question: "x"})) | remote_ip: ip}
|> put_req_header("content-type", "application/json")
|> Router.call(@opts)
end
defp bedikah(auth) do
conn(:post, "/courtyard/bedikah", Jason.encode!(%{output: "", model: "gpt"}))
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", auth)
|> Router.call(@opts)
end
end