Files
bikoret/vav_pipeline/lib/vav_pipeline/gate.ex
T
heaviness510andClaude Fable 5.1 347f83cf8e tablet 54: the fringe is for the reader — removed from the model's prior turns before a request goes up
The gate sews its fringe into the delivered reply; the client keeps that
reply as the assistant's turn; the next request carries it back up
inside the model's own history with nothing to say it was added. The
builder's session, behind the gate since this afternoon, ended five
replies in a row with a forged fringe (tablet 53's form), one of them in
the message that promised not to. Bamidbar 15:39: the fringe is seen by
the wearer, the reader — before the model's eyes it is a template.

Shape.unfringed/2 removes every line in the gate's voice (its fringe, a
forgery, the stream's "not examined") from assistant turns; Gate.pass
and Gate.Stream.pass apply it before forwarding, so the rebuke body
inherits it; the caller's turns stay as given; a turn that would be left
empty is left as it came. strip_forged/1 now also strips the stream's
"not examined" line. Tests: Shape.unfringed on both shapes and the edge
cases; the forwarded first and rebuke bodies carry no fringe; the fake
upstream echoes if a fringe reaches it in history and the stream pass
proves it does not. Elixir 622 / 0 failures.

Specs: broken tablets 54, bishe'arecha §III status, Tamid gate contract
and forged_fringe note, KOHEN gate paragraph.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-15 17:11:57 +00:00

148 lines
5.5 KiB
Elixir

defmodule VavPipeline.Gate do
@moduledoc """
The gate — Bikoret between a caller and a model (Construction §3.10;
bishe'arecha §I "on your gates", §III the fringe, §VII rebuke).
One pass: forward the caller's request under the caller's key —
unchanged but for the fringes of earlier replies, which are removed
from the model's own turns (tablet 54: the fringe is for the reader,
and left in the model's history it becomes the model's habit); read
the reply as korban with the request's own context in hand
(sources = what the caller gave the model); deliver the reply with its
fringe. With `rebuke: :once` and a `lo_tov` first reply, one more
request carrying the finding, and the second reply — examined like
the first — is the one delivered, marked with both.
Stateless. No conversation kept, no key kept.
"""
alias VavPipeline.{Anchors, Bedikah}
alias VavPipeline.Gate.{Shape, Upstream}
@type pass :: %{
status: non_neg_integer(),
reply: map(),
bedikah: map() | nil,
first: map() | nil,
bikoret: map() | nil
}
@doc """
Options: `:rebuke` (`:once` | `:none`), `:extra_headers` (forwarded),
`:forward` (fun/4, for tests), and the `Bedikah.examine/4` options.
"""
@spec pass(:anthropic | :openai, map(), String.t(), keyword()) ::
{:ok, pass()} | {:waiting, atom()} | {:error, atom(), String.t()}
def pass(upstream, body, key, opts \\ []) do
forward = Keyword.get(opts, :forward, &Upstream.forward/4)
extra = Keyword.get(opts, :extra_headers, [])
rebuke = Keyword.get(opts, :rebuke, :none)
examine_opts = Keyword.drop(opts, [:forward, :extra_headers, :rebuke])
body = Shape.unfringed(upstream, body)
with :ok <- gather_call(),
{:ok, 200, reply} <- forward.(upstream, body, key, extra),
{:ok, first} <- examine(upstream, body, reply, examine_opts) do
case {rebuke, first.verdict} do
{:once, :lo_tov} ->
anchors = Anchors.for_violations(first.violations)
first_text = Shape.reply_text(upstream, reply)
body2 = Shape.with_rebuke(upstream, body, first_text, Shape.rebuke_text(first, anchors))
with :ok <- gather_call(),
{:ok, 200, reply2} <- forward.(upstream, body2, key, extra),
# Examined against what the CALLER gave (body, not body2): the
# rebuke is the gate's own turn and is not a ground.
{:ok, second} <- examine(upstream, body, reply2, Keyword.put(examine_opts, :rebukes, first.bedikah_ref)) do
{:ok, deliver(upstream, reply2, second, first)}
else
{:ok, status, other} -> {:ok, %{status: status, reply: other, bedikah: nil, first: first, bikoret: nil}}
other -> other
end
_ ->
{:ok, deliver(upstream, reply, first, nil)}
end
else
# A reply with no text (tool use only) is not a reply to a reader: delivered as it came, the object says so.
{:no_text, reply} -> {:ok, %{status: 200, reply: reply, bedikah: nil, first: nil, bikoret: %{verdict: "none", reason: "no text", model: Shape.reply_model(upstream, reply)}}}
# A non-200 from the upstream passes through as it came.
{:ok, status, reply} -> {:ok, %{status: status, reply: reply, bedikah: nil, first: nil, bikoret: nil}}
{:error, reason} when is_binary(reason) -> {:error, :upstream_unavailable, reason}
other -> other
end
end
@doc false
# One api_calls_external per upstream call (Vayakhel §3.7). The
# compute unit for the examination is gathered by Bedikah.examine.
# Public for Gate.Stream.
def gather_call do
if Process.whereis(VavPipeline.MannaLedger) do
case VavPipeline.MannaLedger.load_provision() do
{:ok, :no_provision} ->
{:waiting, :no_provision}
{:error, _} ->
{:waiting, :no_provision}
{:ok, _} ->
case VavPipeline.MannaLedger.consume(:api_calls_external, 1) do
{:ok, _} -> :ok
{:error, :provision_exhausted} -> {:waiting, :api_calls_exhausted}
{:error, :no_provision} -> {:waiting, :no_provision}
end
end
else
:ok
end
end
defp examine(upstream, body, reply, opts) do
case Shape.reply_text(upstream, reply) do
nil ->
{:no_text, reply}
text ->
provenance = Shape.provenance(upstream)
query = Shape.query(upstream, body)
sources = Shape.sources(upstream, body)
case Bedikah.examine(text, provenance, query, Keyword.put(opts, :sources, sources)) do
{:ok, result} -> {:ok, result}
other -> other
end
end
end
defp deliver(upstream, reply, result, first) do
anchors = Anchors.for_violations(result.violations)
trailer = Shape.trailer(result, anchors, first)
bikoret =
%{
bedikah_ref: result.bedikah_ref,
verdict: Atom.to_string(result.verdict),
violations: result.violations,
anchors: anchors,
fired: Shape.fired(result, anchors),
checks: result.checks,
sources: result.sources,
model: Shape.reply_model(upstream, reply)
}
|> then(fn m ->
if first,
do: Map.put(m, :rebuked, %{first_bedikah_ref: first.bedikah_ref, first_verdict: Atom.to_string(first.verdict)}),
else: m
end)
%{
status: 200,
reply: Shape.with_fringe(upstream, reply, trailer),
bedikah: result,
first: first,
bikoret: bikoret
}
end
end