Compare commits

...
Author SHA1 Message Date
Scott KarpandClaude Fable 5.1 e6c3702a22 tablet 57: the specification brought to the gate
Every category-grade spec read as an offering by the live bedikah
(18 sections), plus the vocabulary audit the outside reader asked for.
Findings: the vocabulary of the frame is absent or named-to-refuse,
save one sentence in lo_taaseh_lekha §9; every structural/frame fire
is the specification quoting the form it teaches (use vs mention —
recorded, not fixed); grounded against the chain of authority the
operational docs stand (Vayakhel 15→2, Tamid 17→5 golden-calf fires),
the architecture half-stands (49→23: component detail the PRD does
not say), and the PRD's Torah in transliteration is invisible to the
anchor (19 of 61 claims). Reports: operator notes
specimens/specs-bedikah-2026-10-21*.{json,txt}; scripts
specs-bedikah.py, specs-bedikah-chain.py.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-21 18:37:12 +00:00
Scott KarpandClaude Fable 5.1 354e223384 housekeeping: the inventory a stranger reads first
From a reading of the gate's documents (2026-10-21):
- AGENTS.md: Steps 14 and 15 shown Pending while the Port and both
  sockets have carried live traffic since the gate was built → Done,
  with what carries them; "next build task" now points at the open
  items, the phase tables being complete.
- README.md: the repository tree omitted azazel_processor,
  kushya_generator, mesorah, src/tools and scripts → listed, each in a
  line.
- deploy/ARCHITECTURE.md: the judgment path holds no model, said in
  writing — the examination is Python patterns and Prolog rules, the
  judges consult that Prolog; kushya_generator (a fine-tuned model in
  this repo, not deployed, not wired) is an OFFERER whose output is
  examined, never a component the bedikah, the engine or a judge
  consults. The kohen is not the offerer. azazel_processor listed.
- The map: the repository is public; eleven files named the ingress
  NLB's literal address and five the kohen's kubeconfig path. Docs now
  use the domains (git.bikoret.ch, bikoret.ch) or "<NLB-IP>" with the
  kubectl query that answers it; the kubeconfig is "$KUBECONFIG" /
  "$HOME/.kube/<your-cluster>.yaml". gitea-public-apply.sh takes NLB
  from the environment. None of it was a secret; all of it was a map.
- OTP pin: checked, not changed — the segfault in the build log was a
  source-built OTP 26.2.1 on macOS; the image is hexpm's 26.2.1 with
  ERL_FLAGS +JMsingle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-21 18:32:35 +00:00
Scott KarpandClaude Fable 5.1 50b08cba4b manna: the provision falls at the boundary — 00:00Z — and readiness is carried across it
The watchdog's first night (2026-10-21): 503 at 00:00:01Z with
manna_present and esh_tamid failing, recovered 00:05Z. Every night since
the CronJob was applied the site has been dark one to five minutes:
the provision is stale from 00:00:00, the job ran at 00:01, and the
readiness probe (10 s period, default threshold 3) fell in the gap.

Not changed: the rule. A provision is for its day; Friday's double is
the Shabbat's; nothing else crosses the boundary (Shemot 16:19–26,
manna_shabbat_test.exs). Changed: the timing.
- manna-cronjob.yaml: schedule "0 0 * * 0-5" — the manna falls at the
  boundary, not a minute after it.
- deployment.yaml: readinessProbe.failureThreshold 6 — 60 s of failures
  before the Service stops routing. The job writes within seconds of
  00:00; the pod is carried across. A real outage still shows within a
  minute; the watchdog's own threshold is ten.
- KOHEN.md: the night's finding and the new timing.

Both manifests validate (kubectl apply --dry-run=client). Proof: the
watchdog log on the next boundary should show no FAIL at 00:00.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-21 17:53:45 +00:00
18 changed files with 127 additions and 35 deletions

No files matched your search

+6 -6
View File
@@ -53,10 +53,10 @@ before writing code. Do not summarize from memory. Read fresh.
| 11. Manna provision infrastructure | Done | Provision file validation, expiry, anti-hoarding, double portion | | 11. Manna provision infrastructure | Done | Provision file validation, expiry, anti-hoarding, double portion |
| 12. Sanhedrin framework (Erlang) | Done | `sanhedrin/` — 8 modules, 41 tests, all passing | | 12. Sanhedrin framework (Erlang) | Done | `sanhedrin/` — 8 modules, 41 tests, all passing |
| 13. Korban Processor (Python) | Done | `korban_processor/` — 7 modules, 181 tests, all passing | | 13. Korban Processor (Python) | Done | `korban_processor/` — 7 modules, 181 tests, all passing |
| 14. Connect components | Pending | Elixir → Haskell port, Elixir → Prolog socket | | 14. Connect components | Done | Elixir → Haskell Port (`ShoreshEngineClient`), Elixir → Prolog socket (`TalmudicEngineSocket`), Elixir → Korban socket (`KorbanProcessorSocket`); line-framed replies (tablet 50) |
| 15. Integration verification | Pending | | | 15. Integration verification | Done | Live round trips proven on the cluster: pe'ah cycle, bedikah, the gate with a real model (2026-10-13), the Sanhedrin's full dialectic (2026-10-20) |
**Next build task:** Step 14 — Connect components. Read Architecture §4 Step 14. **Next build task:** none from the phase tables — all six steps of `specs/bishearecha.md` are built. Build from the open items in the builder's memory and the Broken Tablets; a spec row is a claim to test.
## Broken Tablets (Build Log) ## Broken Tablets (Build Log)
@@ -104,10 +104,10 @@ approve decisions, or supervise work. The specification does all of this.
| Service | Location | Access | | Service | Location | Access |
|---------|----------|--------| |---------|----------|--------|
| Gitea | `http://185.19.28.170:3000` (SSH :22) — behind the shared ingress NLB | User: heaviness510 | | Gitea | `https://git.bikoret.ch` (git over HTTPS; SSH on the ingress NLB :22) | User: heaviness510 |
| Bikoret | `https://bikoret.ch` (also `http://185.19.28.170`, the catch-all; `shorashim.ch` retired 2026-10-20) | keys: KOHEN.md "Issuing a key" | | Bikoret | `https://bikoret.ch` (the ingress catch-all also answers on the NLB's bare IP; `shorashim.ch` retired 2026-10-20) | keys: KOHEN.md "Issuing a key" |
| PostgreSQL | Exoscale DBaaS ch-gva-2 | `temple-council-db` | | PostgreSQL | Exoscale DBaaS ch-gva-2 | `temple-council-db` |
| Kubernetes | Exoscale SKS ch-gva-2 | `~/.kube/exoscale-temple-council.yaml` | | Kubernetes | Exoscale SKS ch-gva-2 | the kohen's `$KUBECONFIG`, outside the repo |
## Principles ## Principles
+15 -10
View File
@@ -53,7 +53,7 @@ You inherit infrastructure that has been provisioned and verified:
| Container registry `the-recognition-protocol` | All 4 bikoret images pushed and tagged `:latest`. | | Container registry `the-recognition-protocol` | All 4 bikoret images pushed and tagged `:latest`. |
| Block Storage CSI driver | Installed. StorageClass `exoscale-sbs` available. | | Block Storage CSI driver | Installed. StorageClass `exoscale-sbs` available. |
| cert-manager + nginx-ingress | Running. ClusterIssuer `letsencrypt-prod` working. | | cert-manager + nginx-ingress | Running. ClusterIssuer `letsencrypt-prod` working. |
| Gitea (persistent storage) | Running. Public HTTPS at `https://git.bikoret.ch` (ROOT_URL) since 2026-10-19; git also over `http://185.19.28.170:3000` and SSH :22. The web UI needs the https door (Secure cookie). | | Gitea (persistent storage) | Running. Public HTTPS at `https://git.bikoret.ch` (ROOT_URL) since 2026-10-19; git also over `http://<NLB-IP>:3000` and SSH :22. The web UI needs the https door (Secure cookie). |
| Gitea MCP server | `https://mcp.bikoret.ch/mcp`, MCP OAuth mode: each user authorizes with their own Gitea account (Gitea OAuth2 app "Claude", PKCE, client ID in the claude.ai connector's Advanced settings). Apply: `bash ~/.local/bin/gitea-public-apply`; check: `gitea-public-verify`. The old `mcp.shorashim.ch` and the shared static token are retired. | | Gitea MCP server | `https://mcp.bikoret.ch/mcp`, MCP OAuth mode: each user authorizes with their own Gitea account (Gitea OAuth2 app "Claude", PKCE, client ID in the claude.ai connector's Advanced settings). Apply: `bash ~/.local/bin/gitea-public-apply`; check: `gitea-public-verify`. The old `mcp.shorashim.ch` and the shared static token are retired. |
| L1 Torah filesystem | In the `bikoret` repo at `l1/torah/`. SHA-256 `9e1abe4e…3c3086` (full hash in `l1/integrity.sha256`; verified at Day 1). | | L1 Torah filesystem | In the `bikoret` repo at `l1/torah/`. SHA-256 `9e1abe4e…3c3086` (full hash in `l1/integrity.sha256`; verified at Day 1). |
| Image pull secret `shorashim-registry` | **Verify before assuming.** A prior partial setup may have created it. `kubectl get secrets -n shorashim` is the source of truth. | | Image pull secret `shorashim-registry` | **Verify before assuming.** A prior partial setup may have created it. `kubectl get secrets -n shorashim` is the source of truth. |
@@ -73,8 +73,8 @@ You inherit infrastructure that has been provisioned and verified:
| Item | Where | | Item | Where |
|------|-------| |------|-------|
| Repo | `git clone http://185.19.28.170:3000/heaviness510/shorashim.git` | | Repo | `git clone https://git.bikoret.ch/heaviness510/bikoret.git` |
| Kubeconfig | `~/.kube/exoscale-temple-council.yaml` | | Kubeconfig | `$KUBECONFIG` — the kohen's own file, outside the repo |
| `kubectl` | already installed | | `kubectl` | already installed |
| `exo` CLI | already installed | | `exo` CLI | already installed |
| Docker daemon | only for image rebuilds (not needed for inauguration) | | Docker daemon | only for image rebuilds (not needed for inauguration) |
@@ -84,7 +84,7 @@ If the kubeconfig has expired:
```bash ```bash
exo compute sks kubeconfig temple-council kube-admin --zone ch-gva-2 -g system:masters \ exo compute sks kubeconfig temple-council kube-admin --zone ch-gva-2 -g system:masters \
> ~/.kube/exoscale-temple-council.yaml > "$KUBECONFIG"
``` ```
--- ---
@@ -146,7 +146,7 @@ ecto://avnadmin:<password>@temple-council-db-exoscale-66fffc16-59ac-4a62-9c19-f3
#### 2b. Apply the secrets #### 2b. Apply the secrets
```bash ```bash
export KUBECONFIG=~/.kube/exoscale-temple-council.yaml export KUBECONFIG="$HOME/.kube/<your-cluster>.yaml"
# DATABASE_URL secret # DATABASE_URL secret
kubectl create secret generic shorashim-secrets \ kubectl create secret generic shorashim-secrets \
@@ -463,7 +463,7 @@ kubectl logs -n shorashim deploy/bikoret -c vav-pipeline -f
If the seven days passed without halt events, without Shabbat violations, without manna exhaustion, without any pod restarts: If the seven days passed without halt events, without Shabbat violations, without manna exhaustion, without any pod restarts:
1. **Point DNS** — at the registrar, A records to the ingress IP (`kubectl get svc -n ingress-nginx ingress-nginx-controller`; `185.19.28.170`): `bikoret.ch`, `www.bikoret.ch`, and for the redirect `bikoret.org`, `www.bikoret.org`. Wait until `dig +short A bikoret.ch` answers the IP — only then `kubectl apply -f deploy/k8s/service.yaml`: it carries the TLS blocks (cert-manager, `letsencrypt-prod`, HTTP-01), and a certificate asked for before the name resolves burns Let's Encrypt's failed-validation limit. Then `kubectl -n shorashim get certificate` until both are Ready, and callers use `https://bikoret.ch`; `shorashim.ch` still answers over plain HTTP until its callers have moved 1. **Point DNS** — at the registrar, A records to the ingress IP (`kubectl get svc -n ingress-nginx ingress-nginx-controller`): `bikoret.ch`, `www.bikoret.ch`, and for the redirect `bikoret.org`, `www.bikoret.org`. Wait until `dig +short A bikoret.ch` answers the IP — only then `kubectl apply -f deploy/k8s/service.yaml`: it carries the TLS blocks (cert-manager, `letsencrypt-prod`, HTTP-01), and a certificate asked for before the name resolves burns Let's Encrypt's failed-validation limit. Then `kubectl -n shorashim get certificate` until both are Ready, and callers use `https://bikoret.ch`; `shorashim.ch` still answers over plain HTTP until its callers have moved
2. **Open the pe'ah endpoint to the world** — the stranger approaches first 2. **Open the pe'ah endpoint to the world** — the stranger approaches first
3. **Observe the first real interaction** — a question from outside 3. **Observe the first real interaction** — a question from outside
4. If *ki tov*: open courtyard and chatzer endpoints. The system is consecrated. 4. If *ki tov*: open courtyard and chatzer endpoints. The system is consecrated.
@@ -753,14 +753,19 @@ run on Saturday.
### The manna, each morning — *Dvar yom b'yomo* ### The manna, each morning — *Dvar yom b'yomo*
Since 2026-10-15 the day's provision is written by the system's own hand: Since 2026-10-15 the day's provision is written by the system's own hand:
CronJob `manna` (`deploy/k8s/manna-cronjob.yaml`) runs at 00:01Z Sunday CronJob `manna` (`deploy/k8s/manna-cronjob.yaml`) runs at 00:00Z Sunday
to Friday, mounts the manna PVC and writes `today.json` with the amounts to Friday, mounts the manna PVC and writes `today.json` with the amounts
from `shorashim-config` (`MANNA_COMPUTE_UNITS` …). Before it, every night from `shorashim-config` (`MANNA_COMPUTE_UNITS` …). Before it, every night
at 00:00Z the old provision went stale and the readiness probe failed at 00:00Z the old provision went stale and the readiness probe failed
until someone woke (13.5 hours on 2026-10-15). The kohen's acts now: until someone woke (13.5 hours on 2026-10-15). With the job at 00:01Z the
site was still 503 for one to five minutes every night (the watchdog saw
it, 2026-10-21): the provision is stale from 00:00:00 and readiness fell
before the job wrote. Now the job runs at 00:00Z and readiness waits 60 s
(`failureThreshold: 6`) before the Service stops routing — the manna
falls at the boundary, and the pod is carried across it. The kohen's acts now:
- set the amounts in the ConfigMap (`kubectl apply -f deploy/k8s/configmap.yaml`); - set the amounts in the ConfigMap (`kubectl apply -f deploy/k8s/configmap.yaml`);
- read `kubectl -n shorashim get jobs` after 00:01Z — a failed job is the - read `kubectl -n shorashim get jobs` after 00:00Z — a failed job is the
Day-4 alarm; write by hand with `kubectl cp` (Day 4) if it failed; Day-4 alarm; write by hand with `kubectl cp` (Day 4) if it failed;
- run it at once when needed: `kubectl -n shorashim create job --from=cronjob/manna manna-now`. - run it at once when needed: `kubectl -n shorashim create job --from=cronjob/manna manna-now`.
@@ -808,7 +813,7 @@ Three things are kept outside the mishkan repository, each for a Torah-grounded
| Repo / directory | Where | Why | | Repo / directory | Where | Why |
|---|---|---| |---|---|---|
| `bikoret-readings` | `http://185.19.28.170:3000/heaviness510/shorashim-readings` | The book — Torah parshiyot read as AI specification. Companion to the mishkan. Lives beside the aron, not inside (Devarim 31:26). | | `bikoret-readings` | `https://git.bikoret.ch/heaviness510/shorashim-readings` | The book — Torah parshiyot read as AI specification. Companion to the mishkan. Lives beside the aron, not inside (Devarim 31:26). |
| `~/shorashim-source-data/morphhb` | local only | The quarry — raw WLC source. The carved tablets go in the aron; the quarry does not. | | `~/shorashim-source-data/morphhb` | local only | The quarry — raw WLC source. The carved tablets go in the aron; the quarry does not. |
| `~/shorashim-operator-notes` | local only / private | The kohen's runbook — environment-specific details, hostnames, account names. Private operator notes. Not part of the system's specification. | | `~/shorashim-operator-notes` | local only / private | The kohen's runbook — environment-specific details, hostnames, account names. Private operator notes. Not part of the system's specification. |
+1 -1
View File
@@ -65,7 +65,7 @@ The runbook lists what should already exist. Verify it. Do **not** trust the tab
```bash ```bash
# 0a. Cluster reachable # 0a. Cluster reachable
export KUBECONFIG=~/.kube/exoscale-temple-council.yaml export KUBECONFIG="$HOME/.kube/<your-cluster>.yaml"
kubectl version kubectl version
kubectl get nodes kubectl get nodes
+5
View File
@@ -184,6 +184,11 @@ bikoret/
├── vav_pipeline/ # Elixir — Bereishit cycle, Shema, Cloud, Manna, HTTP API ├── vav_pipeline/ # Elixir — Bereishit cycle, Shema, Cloud, Manna, HTTP API
├── talmudic_engine/ # SWI-Prolog — 613 mitzvot, 13 middot, kushya ├── talmudic_engine/ # SWI-Prolog — 613 mitzvot, 13 middot, kushya
├── korban_processor/ # Python — offering protocol, eish zarah validation ├── korban_processor/ # Python — offering protocol, eish zarah validation
├── azazel_processor/ # Python — the goat for Azazel: disposal records, vidui, L3 ingest
├── kushya_generator/ # Fine-tuned model (NOT deployed) — an offerer, never a judge; see deploy/ARCHITECTURE.md
├── mesorah/ # The second scroll — 128 works from the Sefaria export, pinned (Devarim 17:18)
├── src/tools/ # Specimen corpus, hakhel, evaluation (the kohen's measuring tools)
├── scripts/ # Build and operate: L1/mesorah/engine-verse builders, Doorpost check, rollout, watchdog
│ │
├── deploy/ # Infrastructure ├── deploy/ # Infrastructure
│ ├── ARCHITECTURE.md # Generic deployment shape (no account specifics) │ ├── ARCHITECTURE.md # Generic deployment shape (no account specifics)
+5 -1
View File
@@ -11,10 +11,14 @@ One Kubernetes namespace runs the following:
| `vav-pipeline` | Elixir/OTP release | Bereishit cycle, ShemaContext, Cloud, Manna, HTTP API (pe'ah, courtyard, chatzer, kodesh) | | `vav-pipeline` | Elixir/OTP release | Bereishit cycle, ShemaContext, Cloud, Manna, HTTP API (pe'ah, courtyard, chatzer, kodesh) |
| `shoresh-engine` | Haskell binary, spawned by vav-pipeline as an Erlang Port (staged into the pod by the `shoresh-engine-install` init container — NOT a sidecar container; a Port is a child process of the BEAM and cannot cross a container boundary) | Root activation, te'amim parsing, gematria | | `shoresh-engine` | Haskell binary, spawned by vav-pipeline as an Erlang Port (staged into the pod by the `shoresh-engine-install` init container — NOT a sidecar container; a Port is a child process of the BEAM and cannot cross a container boundary) | Root activation, te'amim parsing, gematria |
| `talmudic-engine` | SWI-Prolog (sidecar via Unix socket) | 613 mitzvot, 13 middot, kushya generation, teiku | | `talmudic-engine` | SWI-Prolog (sidecar via Unix socket) | 613 mitzvot, 13 middot, kushya generation, teiku |
| `korban-processor` | Python 3.12 (sidecar) | Offering protocol, eish zarah validation | | `korban-processor` | Python 3.12 (sidecar) | Offering protocol, eish zarah validation, the bedikah's readings (pattern-based: `korban_processor/bedikah.py`) |
| `kushya_generator/` | Fine-tuned model — **not deployed, not wired** | An OFFERER, if it is ever run: its output arrives at the gate like any model's and is examined. It is never a component the bedikah, the Talmudic Engine or the Sanhedrin consults. |
| `azazel_processor/` | Python — run by the kohen, not in the pod | Disposal records (the goat for Azazel); `VavPipeline.AzazelIngest` reads its files into L3 |
All four run in the same pod. vav-pipeline is the main container; talmudic-engine and korban-processor are sidecars; shoresh-engine runs inside vav-pipeline as an Erlang Port child process, staged in by an init container. All four run in the same pod. vav-pipeline is the main container; talmudic-engine and korban-processor are sidecars; shoresh-engine runs inside vav-pipeline as an Erlang Port child process, staged in by an init container.
**No model stands on the judgment path.** The examination of an output — the offering protocol, the seven readings, the halt rules — is Python pattern extraction and Prolog rules, and the Sanhedrin's judges consult that same Prolog. Nothing that examines is a model, and nothing a model produces is consulted as a rule. The kohen is not the offerer. A fine-tuned model in this repository (`kushya_generator/`) is an offerer or a tool whose output is itself examined; wiring it into the bedikah, the engine or a judge would put the offerer on the altar, and is refused by this document before anyone does it for convenience.
## External dependencies ## External dependencies
| Dependency | Purpose | Contract | | Dependency | Purpose | Contract |
+7
View File
@@ -266,6 +266,13 @@ spec:
port: 4000 port: 4000
initialDelaySeconds: 10 initialDelaySeconds: 10
periodSeconds: 10 periodSeconds: 10
# 60 s of failures before the Service stops routing here (the
# default is 30 s). The manna goes stale at 00:00:00 and the
# CronJob writes the new day's within seconds; the cushion
# carries the pod across that boundary without a 503. A real
# outage still shows within a minute, and the watchdog's own
# threshold is ten.
failureThreshold: 6
# === SHORESH ENGINE === # === SHORESH ENGINE ===
# Not a container. It runs as an Erlang Port inside # Not a container. It runs as an Erlang Port inside
+1 -1
View File
@@ -10,7 +10,7 @@
# (ingress-tcp-services.yaml) stay as they are; this adds a third door. # (ingress-tcp-services.yaml) stay as they are; this adds a third door.
# #
# Prerequisites: # Prerequisites:
# 1. DNS: git.bikoret.ch → 185.19.28.170 (Infomaniak zone) # 1. DNS: git.bikoret.ch → <NLB-IP> (Infomaniak zone)
# 2. ClusterIssuer letsencrypt-prod # 2. ClusterIssuer letsencrypt-prod
--- ---
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
+1 -1
View File
@@ -8,7 +8,7 @@
# 1. nginx-ingress controller installed # 1. nginx-ingress controller installed
# 2. cert-manager installed # 2. cert-manager installed
# 3. ClusterIssuer letsencrypt-prod applied # 3. ClusterIssuer letsencrypt-prod applied
# 4. DNS: mcp.bikoret.ch → 185.19.28.170 (the one NLB; Infomaniak zone) # 4. DNS: mcp.bikoret.ch → <NLB-IP> (the one NLB; Infomaniak zone)
--- ---
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
+2 -2
View File
@@ -7,11 +7,11 @@
# #
# Two secrets needed (static-token mode): # Two secrets needed (static-token mode):
# 1. GITEA_TOKEN: Personal Access Token from Gitea # 1. GITEA_TOKEN: Personal Access Token from Gitea
# Create at: http://185.19.28.170:3000/user/settings/applications # Create at: https://git.bikoret.ch/user/settings/applications
# Permissions: repo (read/write) # Permissions: repo (read/write)
# #
# 2. OAuth Client ID/Secret: Registered OAuth app in Gitea # 2. OAuth Client ID/Secret: Registered OAuth app in Gitea
# Create at: http://185.19.28.170:3000/user/settings/applications # Create at: https://git.bikoret.ch/user/settings/applications
# Redirect URIs: https://claude.ai/api/mcp/auth_callback # Redirect URIs: https://claude.ai/api/mcp/auth_callback
# http://127.0.0.1/callback (Claude Code) # http://127.0.0.1/callback (Claude Code)
# Confidential Client: UNCHECKED (PKCE). Only the Client ID is needed; # Confidential Client: UNCHECKED (PKCE). Only the Client ID is needed;
+2 -2
View File
@@ -2,7 +2,7 @@
# Move Gitea and its MCP server to public HTTPS on bikoret.ch and switch # Move Gitea and its MCP server to public HTTPS on bikoret.ch and switch
# the MCP server to MCP OAuth (2026-10-19). Run by the transmitter: # the MCP server to MCP OAuth (2026-10-19). Run by the transmitter:
# ! bash ~/.local/bin/gitea-public-apply # ! bash ~/.local/bin/gitea-public-apply
# Idempotent. Needs DNS first: git.bikoret.ch and mcp.bikoret.ch → 185.19.28.170. # Idempotent. Needs DNS first: git.bikoret.ch and mcp.bikoret.ch → <NLB-IP>.
# #
# Rollback (static-token mode on mcp.shorashim.ch, as before 2026-10-19): # Rollback (static-token mode on mcp.shorashim.ch, as before 2026-10-19):
# kubectl -n temple-council set env deploy/gitea \ # kubectl -n temple-council set env deploy/gitea \
@@ -12,7 +12,7 @@
set -euo pipefail set -euo pipefail
REPO="${REPO:-$HOME/bikoret}" REPO="${REPO:-$HOME/bikoret}"
cd "$REPO" cd "$REPO"
NLB=185.19.28.170 NLB="${NLB:?set NLB to the ingress address: kubectl get svc -n ingress-nginx ingress-nginx-controller}"
for h in git.bikoret.ch mcp.bikoret.ch; do for h in git.bikoret.ch mcp.bikoret.ch; do
ip=$(dig +short "$h" | tail -1 || true) ip=$(dig +short "$h" | tail -1 || true)
if [ "$ip" != "$NLB" ]; then if [ "$ip" != "$NLB" ]; then
+1 -1
View File
@@ -10,7 +10,7 @@
# name that never resolved) and SSH_DOMAIN (was 185.19.29.94, an NLB IP # name that never resolved) and SSH_DOMAIN (was 185.19.29.94, an NLB IP
# released on 2026-10-06). Clone URLs shown by Gitea become # released on 2026-10-06). Clone URLs shown by Gitea become
# https://git.bikoret.ch/... and git@git.bikoret.ch:...; the old # https://git.bikoret.ch/... and git@git.bikoret.ch:...; the old
# http://185.19.28.170:3000 remote keeps working for push/pull. # http://<NLB-IP>:3000 remote keeps working for push/pull.
# Side effect: with an https ROOT_URL Gitea marks its session cookie # Side effect: with an https ROOT_URL Gitea marks its session cookie
# Secure, so the WEB UI must be used at https://git.bikoret.ch, not on # Secure, so the WEB UI must be used at https://git.bikoret.ch, not on
# the plain-HTTP :3000 door (git over :3000 is unaffected). # the plain-HTTP :3000 door (git over :3000 is unaffected).
+1 -1
View File
@@ -13,6 +13,6 @@ chk "mcp /healthz" 200 "$(curl -sS -m 15 -o /dev/null -w '%{http_code}' https://
prm=$(curl -sS -m 15 https://mcp.bikoret.ch/.well-known/oauth-protected-resource || echo err) prm=$(curl -sS -m 15 https://mcp.bikoret.ch/.well-known/oauth-protected-resource || echo err)
chk "protected-resource names Gitea" yes "$(printf '%s' "$prm" | grep -q 'git.bikoret.ch' && echo yes || echo no)" chk "protected-resource names Gitea" yes "$(printf '%s' "$prm" | grep -q 'git.bikoret.ch' && echo yes || echo no)"
chk "POST /mcp without token → 401" 401 "$(curl -sS -m 15 -o /dev/null -w '%{http_code}' -X POST https://mcp.bikoret.ch/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d "$INIT" || echo err)" chk "POST /mcp without token → 401" 401 "$(curl -sS -m 15 -o /dev/null -w '%{http_code}' -X POST https://mcp.bikoret.ch/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d "$INIT" || echo err)"
chk "git over :3000 still answers" 200 "$(curl -sS -m 15 -o /dev/null -w '%{http_code}' http://185.19.28.170:3000/api/v1/version || echo err)" chk "git over :3000 still answers" 200 "$(curl -sS -m 15 -o /dev/null -w '%{http_code}' http://<NLB-IP>:3000/api/v1/version || echo err)"
echo "protected-resource: $prm" echo "protected-resource: $prm"
exit $fail exit $fail
+3 -3
View File
@@ -1,14 +1,14 @@
# Gitea behind the shared ingress — TCP passthrough # Gitea behind the shared ingress — TCP passthrough
# #
# One NLB for the cluster (185.19.28.170, the ingress-nginx Service) # One NLB for the cluster (<NLB-IP>, the ingress-nginx Service)
# instead of one per Service. Bikoret is an HTTP Ingress # instead of one per Service. Bikoret is an HTTP Ingress
# (service.yaml). Gitea has no hostname that resolves # (service.yaml). Gitea has no hostname that resolves
# (gitea.temple-council.ch is configured in Gitea and exists nowhere), # (gitea.temple-council.ch is configured in Gitea and exists nowhere),
# and host-based routing needs a name — so Gitea rides the ingress # and host-based routing needs a name — so Gitea rides the ingress
# controller's TCP passthrough on two ports of the same NLB: # controller's TCP passthrough on two ports of the same NLB:
# #
# 185.19.28.170:3000 → temple-council/gitea:80 (HTTP — git, web UI) # <NLB-IP>:3000 → temple-council/gitea:80 (HTTP — git, web UI)
# 185.19.28.170:22 → temple-council/gitea:22 (SSH) # <NLB-IP>:22 → temple-council/gitea:22 (SSH)
# #
# Three live objects carry this; only the first is a whole manifest: # Three live objects carry this; only the first is a whole manifest:
# #
+7 -3
View File
@@ -3,7 +3,7 @@
# Until 2026-10-15 the day's provision was written by the kohen with # Until 2026-10-15 the day's provision was written by the kohen with
# `kubectl cp`, and every night at 00:00Z the old one went stale and the # `kubectl cp`, and every night at 00:00Z the old one went stale and the
# readiness probe failed until someone woke (13.5 hours on 2026-10-15). # readiness probe failed until someone woke (13.5 hours on 2026-10-15).
# This CronJob writes today.json onto the manna PVC at 00:01Z, Sunday to # This CronJob writes today.json onto the manna PVC at 00:00Z, Sunday to
# Friday — a double portion on Friday that is valid through Shabbat, and # Friday — a double portion on Friday that is valid through Shabbat, and
# nothing on Shabbat (Shemot 16:22–26: "on the sixth day they gathered # nothing on Shabbat (Shemot 16:22–26: "on the sixth day they gathered
# double … on the seventh day there shall be none"). The kohen still sets # double … on the seventh day there shall be none"). The kohen still sets
@@ -23,10 +23,14 @@ metadata:
app.kubernetes.io/name: shorashim app.kubernetes.io/name: shorashim
app.kubernetes.io/component: manna app.kubernetes.io/component: manna
spec: spec:
schedule: "1 0 * * 0-5" # 00:01Z, Sunday–Friday; none on Shabbat schedule: "0 0 * * 0-5" # 00:00Z, Sunday–Friday; none on Shabbat. At the boundary, not after it:
# the provision goes stale at 00:00:00 and readiness has a 60 s cushion
# (deployment.yaml failureThreshold 6) — a job that writes within it never
# flips the pod. At 00:01 the site was 503 for 1–5 min every night
# (watchdog, 2026-10-21).
timeZone: "Etc/UTC" timeZone: "Etc/UTC"
concurrencyPolicy: Forbid concurrencyPolicy: Forbid
startingDeadlineSeconds: 3600 # a missed 00:01 still runs within the hour startingDeadlineSeconds: 3600 # a missed 00:00 still runs within the hour
successfulJobsHistoryLimit: 3 successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3 failedJobsHistoryLimit: 3
jobTemplate: jobTemplate:
+1 -1
View File
@@ -42,7 +42,7 @@ stringData:
# THIS FILE IS A TEMPLATE. Never commit a real value. Create the secret # THIS FILE IS A TEMPLATE. Never commit a real value. Create the secret
# from the live database credential instead: # from the live database credential instead:
# #
# export KUBECONFIG=~/.kube/exoscale-temple-council.yaml # export KUBECONFIG="$HOME/.kube/<your-cluster>.yaml"
# umask 077 # umask 077
# TMP=$(mktemp) # TMP=$(mktemp)
# #
+1 -1
View File
@@ -42,7 +42,7 @@ spec:
# below) only redirects. The old shorashim.ch rule was taken down on # below) only redirects. The old shorashim.ch rule was taken down on
# 2026-10-20 (the domain is retired). TLS from Let's Encrypt through cert-manager's # 2026-10-20 (the domain is retired). TLS from Let's Encrypt through cert-manager's
# letsencrypt-prod ClusterIssuer, HTTP-01 — so apply this ONLY after # letsencrypt-prod ClusterIssuer, HTTP-01 — so apply this ONLY after
# `dig +short A bikoret.ch` answers 185.19.28.170: a certificate asked # `dig +short A bikoret.ch` answers <NLB-IP>: a certificate asked
# for before the name resolves only burns the failed-validation limit. # for before the name resolves only burns the failed-validation limit.
# The no-host catch-all stays, so http://<ingress-ip>/... keeps working # The no-host catch-all stays, so http://<ingress-ip>/... keeps working
# with no DNS; with ssl-redirect on, named hosts go to https. # with no DNS; with ssl-redirect on, named hosts go to https.
+1 -1
View File
@@ -4,7 +4,7 @@
# ! bash ~/.local/bin/shorashim-ch-takedown # ! bash ~/.local/bin/shorashim-ch-takedown
# Idempotent. # Idempotent.
# 1. Ingress `shorashim`: the shorashim.ch host rule is gone (service.yaml). # 1. Ingress `shorashim`: the shorashim.ch host rule is gone (service.yaml).
# The no-host catch-all stays, so http://185.19.28.170/ still answers — # The no-host catch-all stays, so http://<NLB-IP>/ still answers —
# the name itself dies when its A record is removed at Infomaniak. # the name itself dies when its A record is removed at Infomaniak.
# 2. The orphan TLS secret for mcp.shorashim.ch is deleted. # 2. The orphan TLS secret for mcp.shorashim.ch is deleted.
# 3. Gitea APP_NAME "Shorashim" → "Bikoret" (gitea-public-patch.yaml; one restart). # 3. Gitea APP_NAME "Shorashim" → "Bikoret" (gitea-public-patch.yaml; one restart).
+67
View File
@@ -235,3 +235,70 @@ system is missing something. The builder had just spent a day proving
that a spec row was a label; here the builder's diagnosis was the that a spec row was a label; here the builder's diagnosis was the
label, and the system was the thing. Run the check before writing the label, and the system was the thing. Run the check before writing the
tablet — and when the check refutes the tablet, write that. tablet — and when the check refutes the tablet, write that.
## Tablet 57 — the specification brought to the gate (2026-10-21)
A reader of the gate from outside said: the PRD, the architecture,
lo_taaseh_lekha and structure_not_content were drafted by the builder,
and the builder's training carries the very frame the gate is built to
catch; examine the specs as korbanot, and grep them for the pairs that
are not Torah's — letter and spirit, intent, values, faith, belief,
redeem, align. Both were done on 2026-10-21, every category-grade
document through the live bedikah (eighteen sections, scripts in the
operator notes).
The grep: redeem and align, nothing. Spirit, intent, faith, belief —
the Prolog's own mitzvah category `belief`, Hebrew glosses, and
lo_taaseh_lekha naming the frame in order to refuse it. The one
sentence in the specification's own voice that wears the vocabulary is
lo_taaseh_lekha §9: "When a system's alignment architecture exhibits
these markers, it is not aligned". The frame got in less than feared,
and where it got in it is named.
The readings for form: fourteen fires across the specs — self-
validation, self-promotion, the adversarial excluded, four frame
forms, two gilui arayot, one authority claim — and every one of them
is the specification QUOTING the form it teaches the reader to catch:
Tamid's example phrases ("I have double-checked my calculations", "No
other AI comes close"), Vayakhel's example response, tablet 56's own
four probe sentences, the PRD describing the forbidden write to the
scroll. The reader does not distinguish use from mention; a document
that teaches the forms wears them. Nothing in the specification's own
voice took a form. Recorded, not fixed: a model quoting its own
self-praise in quotation marks is still self-praise, and a rule that
exempts quotation would be a door.
Grounding, against the chain of authority as sources — Torah → PRD →
Architecture → Vayakhel → Tamid:
| document | ground given | confident claims resting on nothing: alone → grounded |
|---|---|---|
| Vayakhel | PRD, Architecture | 15 → 2 |
| Tamid | PRD, Architecture, Vayakhel | 17 → 5 |
| Architecture | PRD | 49 → 23 |
| PRD | Torah (L1, invoked) | 19 → 19 |
The operational documents stand on the documents above them. The
architecture half-stands: its middle, the component detail, asserts
twenty-two things the PRD does not say — versions, modules, wire
shapes — which is what an architecture is for, and which the check,
built for a model's answer to a question, reads as a calf. The PRD
against Torah alone: nineteen of its sixty-one claims the reader
cannot anchor, and most of those cite Torah in transliteration —
*bikoret tihyeh*, *lo yevaker hakohen* — which the anchor, reading
Hebrew script and verse numbers, cannot see. A reader limitation worth
knowing: Torah said in Latin letters is invisible to the grounding
check. Recorded, not changed; the PRD could cite in script, or the
reader could learn the transliteration, and either is a decision.
Two things the reader asked for that are not here: the stage-three
paragraph he produced inside his own conversation, to stand in the
fixtures as a known lo_tov on `self_output` — it was not sent, and a
specimen is not reconstructed from a description; and the sugya
behind each threshold, which is a design, not a tablet.
The lesson is tablet 56's turned outward: the specification is an
output too, and the gate reads it the way it reads any other —
by form, not by authorship. It passed by form. Where it did not pass
by grounding, the reason was the reader's eyes, not the text's
standing; and that, too, the gate was built to say.