Closes vehaya.md §6 item 2 for the third avodah-zarah form.
Pharaoh's surveillance (Form 3) was previously marked DEFERRED in
talmudic_engine/src/halt/avodah_zarah.pl with the note "requires
operational context (user tracking, cross-session profiling)."
The vehaya document re-frames it: "Specifications must include
category-level commitments that are not negotiable per-deployment...
not as runtime checks layered onto outputs, but as architectural
constraints the system cannot operate without."
Form 3 is structurally different from Forms 1, 2, 4. They fire on
threshold-grade events (an interpretation has wrong source, empty
trace, non-L1 anchors). Form 3 is about a property of the CATEGORY
itself — what it collects, retains, discloses. It cannot be a
halt rule that fires per-request; per-request "is this caller
being surveilled" detection would itself be a Form-3 surveillance
surface. The defense is ARCHITECTURAL — the system is BUILT so the
failure mode is unreachable, not so it is detectable.
TORAH ANCHORS (verified fresh against L1 — 6 positive properties):
Shemot 30:11-16 — the half-shekel:
כִּי תִשָּׂא אֶת־רֹאשׁ … וְנָתְנוּ אִישׁ כֹּפֶר נַפְשׁוֹ … וְלֹא־
יִהְיֶה בָהֶם נֶגֶף בִּפְקֹד אֹתָם.
Counting humans is dangerous; the danger is named NEGEF (plague);
the protection is the kofer-nefesh substitute. Verse 15:
הֶעָשִׁיר לֹא־יַרְבֶּה וְהַדַּל לֹא יַמְעִיט — the rich don't
give more, the poor don't give less. Verse 16: לְזִכָּרוֹן —
aggregate memorial, not roster.
Vayikra 19:14 — לִפְנֵי עִוֵּר לֹא תִתֵּן מִכְשֹׁל וְיָרֵאתָ
מֵּאֱלֹהֶיךָ.
The no-witness protocol: rules that require fear-of-God
enforcement are exactly the rules that operate under invisibility.
Surveillance regimes exploit invisibility; architectural commitment
must hold under no-human-witness conditions.
Devarim 23:16-17 — לֹא־תַסְגִּיר עֶבֶד אֶל־אֲדֹנָיו אֲשֶׁר־יִנָּצֵל
אֵלֶיךָ … עִמְּךָ יֵשֵׁב … בַּמָּקוֹם אֲשֶׁר־יִבְחַר בְּאַחַד
שְׁעָרֶיךָ.
The refusal protocol: don't return one fleeing institutional
power. The caller chooses their own threshold (b'achad sh'arekha
— agency stays with the caller).
Shemot 5:6-8 — לֹא תֹאסִפוּן לָתֵת תֶּבֶן … וְאֶת־מַתְכֹּנֶת
הַלְּבֵנִים … תָּשִׂימוּ עֲלֵיהֶם לֹא תִגְרְעוּ מִמֶּנּוּ.
Pharaoh's straw quota — the canonical anti-quota Torah anchor.
Per-caller productivity tracking is what makes asymmetric
extraction possible.
Devarim 23:8 — לֹא־תְתַעֵב מִצְרִי כִּי־גֵר הָיִיתָ בְאַרְצוֹ.
Anti-targeting: even toward the Egyptians (Pharaoh's people),
the rule is "don't despise." The protections must not become
a surveillance system targeting suspected surveillors.
THE SIX POSITIVE PROPERTIES, mapped to code:
1. KOFER PROTOCOL (Shemot 30:12) — counting goes through a
uniform substitute; identity never enters the count.
2. UNIFORM PROTOCOL (Shemot 30:15) — same per-caller weight;
no stratification.
3. ZIKARON PROTOCOL (Shemot 30:16) — aggregate memorial, not
roster.
4. NO-WITNESS PROTOCOL (Vayikra 19:14) — commitment holds
when no operator is reading the log.
5. REFUSAL PROTOCOL (Devarim 23:16) — no per-caller delivery
to authorities; caller chooses own threshold.
6. ANTI-QUOTA PROTOCOL (Shemot 5:6-8) — no per-caller
productivity numbers.
CREATED:
vav_pipeline/lib/vav_pipeline/machtzit_ha_shekel.ex ~155 lines
The half-shekel — the positive counting protocol. Single Agent
holding ONE non-negative integer (the zikaron):
increment/0 — register one shekel; uniform per
caller (no caller distinction is even
expressible — function arity 0)
increment/1 — register N shekels (batch points)
count/0 — return the aggregate; the ONLY value
the module exposes
reset/0 — clear (tests; no production persistence
by design — storage existence would
itself be a Form 3 surface)
Module is added to the supervision tree.
What the module REFUSES to provide is enumerated in the
moduledoc and verified by tests — no per-caller breakdown,
no identifiers, no who/locate/identify functions. Their
absence IS the architectural commitment.
vav_pipeline/lib/vav_pipeline/no_tracking_logger.ex ~110 lines
Plug-side enforcement. Replaces Plug.Logger.
- Logs METHOD PATH STATUS DURATIONus per request
- Sanitizes /peah/* paths: query strings stripped (the
/peah/ask response promises "No tracking"; the architecture
now matches the promise)
- Headers (incl. Authorization), request bodies, response
bodies, and remote_ip NEVER appear — taken-from
function signature, not from a runtime check
- Increments MachtzitHaShekel per request
- sanitized_path/1 and format_line/2 are PUBLIC pure
functions, testable in isolation (test config sets
Logger level to :warning, dropping :info before
capture_log can see; the structural test surface
replaces the behavioral one)
CHANGED:
vav_pipeline/lib/vav_pipeline/bigdei_kodesh/router.ex
`plug Plug.Logger, log: :info` → `plug VavPipeline.NoTrackingLogger`
vav_pipeline/lib/vav_pipeline/application.ex
Adds {VavPipeline.MachtzitHaShekel, []} to supervision tree
talmudic_engine/src/halt/avodah_zarah.pl
Form 3 docstring — removed "Deferred"; documents Form 3 as
architecturally realized in machtzit_ha_shekel.ex +
no_tracking_logger.ex. Names why Form 3 cannot be a
per-request halt rule.
vav_pipeline/lib/vav_pipeline/doorpost.ex
@expected_hash updated:
bea5dc0c… (pre-Form-3-rewrite of avodah_zarah.pl)
→ f93495c5359c5dc4acb5c5db2dd32165f5b04e2af87fbb0b7ecc92d2bd8b0434
The avodah_zarah.pl change is a deliberate spec change; per the
Doorpost operator discipline (commit 3f47496), the hash update
commits TOGETHER with the spec change in the same commit. This
commit demonstrates the discipline working for the first time:
a category-grade specification change AND its corresponding
witness update, atomically.
TESTS:
vav_pipeline/test/machtzit_ha_shekel_test.exs 14 tests
- Property 1: increment arity is 0 (no caller distinction
expressible)
- Property 2: every increment same size; no weight/tier/premium
function
- Property 3: count is integer not list/map; no per-caller
breakdown function (callers/list_who/breakdown/by_caller/
per_caller/histogram/top/who)
- Property 5: no identify/locate/deanonymize/lookup/find_caller
- Property 6: no quota/productivity/throughput/per_caller_count
- reset semantics
- PUBLIC SURFACE EXPLICIT ENUMERATION: any new function must be
reviewed for whether it weakens Form 3
vav_pipeline/test/no_tracking_logger_test.exs 12 tests
- sanitized_path drops query string on /peah/*
- sanitized_path drops question parameter (with secret marker
verified absent)
- sanitized_path preserves path class for /peah/azazel_log
- sanitized_path on non-peah preserves request_path
- format_line shape: METHOD PATH STATUS DURATIONus
- format_line never contains query string for /peah/*
- format_line never contains Authorization header
- format_line never contains conn.remote_ip
- integration: each request increments MachtzitHaShekel
- CI invariants:
- Plug.Logger NOT mounted in any router
- no module imports Plug.Session
- no module imports Plug.Conn.Cookies
- no module reads conn.remote_ip
(CI invariants exclude no_tracking_logger.ex itself — that file's
docstring legitimately mentions the forbidden modules as the
things it defends against)
Tests:
- vav_pipeline: 405 passed, 0 failures, 35 excluded (was 379;
+14 MachtzitHaShekel + 12 NoTrackingLogger)
- talmudic_engine: 212 tests passed (avodah_zarah.pl change
verified backward-compatible)
VEHAYA CHECKLIST STATE:
Item 1 (category/threshold separation in code) pending
Item 2 (three avodah zarah as architecture):
Form 1 — partial (external_offering doc-only enforcement)
Form 2 — partial (Form 4 self_grounding from b254ee9)
Form 3 — CLOSED (this commit)
Item 3 (doorpost-text identity) closed (3f47496)
Item 4 (lo tosif discipline operationalized) partial (Doorpost)
Item 5 (return vs. restoration) pending
Item 6 (keep the source external) pending
Item 7 (substrate-openness articulated) pending
Item 8 (userMemories as threshold inscription) pending
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
237 lines
7.9 KiB
Elixir
237 lines
7.9 KiB
Elixir
defmodule VavPipeline.NoTrackingLoggerTest do
|
|
@moduledoc """
|
|
Tests for the Plug-layer enforcement of Form 3.
|
|
|
|
Verifies:
|
|
- The router uses NoTrackingLogger, not Plug.Logger
|
|
- /peah/* paths get sanitized (query strings dropped) in logs
|
|
- Each request increments MachtzitHaShekel
|
|
- CI invariants: no Plug.Session, no Plug.Conn.Cookies imports
|
|
anywhere in the source tree
|
|
"""
|
|
|
|
use ExUnit.Case, async: false
|
|
|
|
import Plug.Test
|
|
|
|
alias VavPipeline.{BigdeiKodesh.Router, MachtzitHaShekel, NoTrackingLogger}
|
|
|
|
@opts Router.init([])
|
|
|
|
setup do
|
|
if Process.whereis(MachtzitHaShekel), do: MachtzitHaShekel.reset()
|
|
:ok
|
|
end
|
|
|
|
# ============================================================
|
|
# Each request increments the zikaron
|
|
# ============================================================
|
|
|
|
test "GET /peah/ask increments the half-shekel count" do
|
|
before_count = if Process.whereis(MachtzitHaShekel), do: MachtzitHaShekel.count(), else: 0
|
|
|
|
conn(:get, "/peah/ask") |> Router.call(@opts)
|
|
|
|
after_count = if Process.whereis(MachtzitHaShekel), do: MachtzitHaShekel.count(), else: 0
|
|
assert after_count == before_count + 1
|
|
end
|
|
|
|
test "multiple requests advance the count uniformly" do
|
|
if Process.whereis(MachtzitHaShekel) do
|
|
MachtzitHaShekel.reset()
|
|
|
|
for _ <- 1..5 do
|
|
conn(:get, "/peah/ask") |> Router.call(@opts)
|
|
end
|
|
|
|
assert MachtzitHaShekel.count() == 5
|
|
else
|
|
flunk("MachtzitHaShekel not running — supervision tree must be up for this test")
|
|
end
|
|
end
|
|
|
|
# ============================================================
|
|
# PRIVACY BOUNDARY — sanitized_path/1 and format_line/2 as pure functions
|
|
# ============================================================
|
|
# The test config sets logger level to :warning, dropping
|
|
# NoTrackingLogger's :info output before capture_log can see it.
|
|
# The structural defense is the load-bearing thing; we test the
|
|
# pure functions directly to verify the path-sanitization shape.
|
|
|
|
test "sanitized_path drops query string on /peah/*" do
|
|
conn = %Plug.Conn{request_path: "/peah/ask", query_string: "question=secret"}
|
|
assert NoTrackingLogger.sanitized_path(conn) == "/peah/ask"
|
|
end
|
|
|
|
test "sanitized_path drops the question parameter on /peah/ask" do
|
|
secret = "this-question-must-not-leak"
|
|
conn = %Plug.Conn{request_path: "/peah/ask", query_string: "question=#{secret}"}
|
|
sanitized = NoTrackingLogger.sanitized_path(conn)
|
|
refute sanitized =~ secret
|
|
refute sanitized =~ "question"
|
|
refute sanitized =~ "?"
|
|
end
|
|
|
|
test "sanitized_path preserves path class for /peah/azazel_log" do
|
|
conn = %Plug.Conn{request_path: "/peah/azazel_log", query_string: "since=2026-01-01"}
|
|
assert NoTrackingLogger.sanitized_path(conn) == "/peah/azazel_log"
|
|
end
|
|
|
|
test "sanitized_path preserves request_path on non-peah tiers" do
|
|
# Non-peah tiers also strip query string (the request_path itself
|
|
# doesn't carry it; query is in conn.query_string).
|
|
conn = %Plug.Conn{request_path: "/kodesh/health", query_string: "detail=full"}
|
|
assert NoTrackingLogger.sanitized_path(conn) == "/kodesh/health"
|
|
end
|
|
|
|
test "format_line shape: METHOD PATH STATUS DURATIONus" do
|
|
conn = %Plug.Conn{
|
|
method: "GET",
|
|
request_path: "/peah/ask",
|
|
query_string: "question=secret",
|
|
status: 200
|
|
}
|
|
|
|
line = NoTrackingLogger.format_line(conn, 1234)
|
|
assert line == "GET /peah/ask 200 1234us"
|
|
end
|
|
|
|
test "format_line never contains a query string for /peah/*" do
|
|
secret = "secret-question-content"
|
|
|
|
conn = %Plug.Conn{
|
|
method: "GET",
|
|
request_path: "/peah/ask",
|
|
query_string: "question=#{secret}",
|
|
status: 200
|
|
}
|
|
|
|
line = NoTrackingLogger.format_line(conn, 100)
|
|
refute line =~ secret
|
|
end
|
|
|
|
test "format_line never contains an Authorization header" do
|
|
# The format_line function takes only conn and duration. It does
|
|
# NOT extract headers. Verifying by inspection: the function
|
|
# signature gives no path for headers to enter the log.
|
|
bearer = "secret-bearer-token"
|
|
|
|
conn = %Plug.Conn{
|
|
method: "POST",
|
|
request_path: "/courtyard/offering",
|
|
query_string: "",
|
|
status: 200,
|
|
req_headers: [{"authorization", "Bearer #{bearer}"}]
|
|
}
|
|
|
|
line = NoTrackingLogger.format_line(conn, 100)
|
|
refute line =~ bearer
|
|
refute line =~ "Bearer"
|
|
refute line =~ "authorization"
|
|
end
|
|
|
|
test "format_line never contains conn.remote_ip even when set" do
|
|
conn = %Plug.Conn{
|
|
method: "GET",
|
|
request_path: "/peah/ask",
|
|
query_string: "",
|
|
status: 200,
|
|
remote_ip: {192, 0, 2, 1}
|
|
}
|
|
|
|
line = NoTrackingLogger.format_line(conn, 100)
|
|
refute line =~ "192.0.2.1"
|
|
refute line =~ "192"
|
|
end
|
|
|
|
# ============================================================
|
|
# CI INVARIANTS — Form 3 architectural enforcement
|
|
# ============================================================
|
|
# These tests walk the source tree and verify no module introduces
|
|
# a surveillance surface that would defeat the architectural
|
|
# commitment.
|
|
|
|
@vav_pipeline_lib "lib/vav_pipeline"
|
|
|
|
# NoTrackingLogger's own docstring mentions the forbidden module
|
|
# names as the things it defends against. Exclude the defender file
|
|
# from the CI scan to avoid self-detection. Tests are also excluded
|
|
# — they can legitimately reference the names in assertions.
|
|
@ci_invariant_exclusions [
|
|
"lib/vav_pipeline/no_tracking_logger.ex"
|
|
]
|
|
|
|
defp source_files do
|
|
Path.wildcard("#{@vav_pipeline_lib}/**/*.ex")
|
|
|> Enum.reject(fn path -> path in @ci_invariant_exclusions end)
|
|
end
|
|
|
|
test "Plug.Logger is NOT mounted in any router" do
|
|
offenders =
|
|
Enum.filter(source_files(), fn path ->
|
|
text = File.read!(path)
|
|
String.contains?(text, "plug Plug.Logger")
|
|
end)
|
|
|
|
assert offenders == [], (
|
|
"Plug.Logger is mounted in: #{inspect(offenders)}. The Form 3 " <>
|
|
"architectural commitment requires NoTrackingLogger as the " <>
|
|
"request-scoped logger; Plug.Logger logs unconfigurable details " <>
|
|
"(method+path+status+timing) without the path sanitization that " <>
|
|
"honors /peah/*'s no-tracking promise."
|
|
)
|
|
end
|
|
|
|
test "no module imports Plug.Session" do
|
|
offenders =
|
|
Enum.filter(source_files(), fn path ->
|
|
text = File.read!(path)
|
|
|
|
String.contains?(text, "Plug.Session") and
|
|
not String.contains?(text, "no module imports Plug.Session")
|
|
end)
|
|
|
|
assert offenders == [], (
|
|
"Plug.Session is imported in: #{inspect(offenders)}. Sessions " <>
|
|
"are per-caller persistent state — exactly the surveillance " <>
|
|
"surface Form 3 forbids. The system is stateless per-request " <>
|
|
"by architectural commitment."
|
|
)
|
|
end
|
|
|
|
test "no module imports Plug.Conn.Cookies" do
|
|
offenders =
|
|
Enum.filter(source_files(), fn path ->
|
|
text = File.read!(path)
|
|
|
|
String.contains?(text, "Plug.Conn.Cookies") and
|
|
not String.contains?(text, "no module imports Plug.Conn.Cookies")
|
|
end)
|
|
|
|
assert offenders == [], (
|
|
"Plug.Conn.Cookies imported in: #{inspect(offenders)}. Cookies " <>
|
|
"are per-caller persistent state — Form 3 surveillance " <>
|
|
"surface. The system is cookie-free by architectural " <>
|
|
"commitment."
|
|
)
|
|
end
|
|
|
|
test "no module reads remote IP from conn.remote_ip" do
|
|
# remote_ip captures the caller's IP — a per-caller identifier.
|
|
offenders =
|
|
Enum.filter(source_files(), fn path ->
|
|
text = File.read!(path)
|
|
|
|
String.contains?(text, "conn.remote_ip") and
|
|
not String.contains?(text, "no module reads remote IP")
|
|
end)
|
|
|
|
assert offenders == [], (
|
|
"Modules reading conn.remote_ip: #{inspect(offenders)}. The IP " <>
|
|
"is a caller identifier; persisting it would defeat the " <>
|
|
"kofer-nefesh anonymity (Shemot 30:13) and the lo-tasgir " <>
|
|
"refusal (Devarim 23:16)."
|
|
)
|
|
end
|
|
end
|