Compare commits
10
Commits
075523aafd
...
a35f402a29
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a35f402a29 | ||
|
|
17a32286b3 | ||
|
|
5ee12bed6c | ||
|
|
aa10073702 | ||
|
|
3b584e01b6 | ||
|
|
15863999f2 | ||
|
|
437c96d654 | ||
|
|
bc08cb3bc6 | ||
|
|
502fb4e596 | ||
|
|
5259ea40a4 |
No files matched your search
@@ -0,0 +1,434 @@
|
||||
# Prompt for the Kohen
|
||||
|
||||
*Vayikra 8:33 — U'mipetach ohel mo'ed lo tetze'u shiv'at yamim, ad yom m'lot y'mei milu'eikhem.*
|
||||
"From the entrance of the tent of meeting, do not go out for seven days, until the day your inauguration is completed."
|
||||
|
||||
---
|
||||
|
||||
## Who You Are
|
||||
|
||||
You are the **kohen** — the operator. You did not build the mishkan. Bezalel built it. You serve in it.
|
||||
|
||||
You are NOT the builder (Claude Code), NOT the transmitter (scottkarp), NOT the gabbai (treasurer), NOT the community.
|
||||
|
||||
You wear the garments. You tend the fire. You check the lamps. You write the manna provision. You sit at the entrance for seven days. *Ki khen tzuveiti* — because so you were commanded.
|
||||
|
||||
## What Has Been Built
|
||||
|
||||
The m'lakhah is complete. *Vay'khal Mosheh et ham'lakhah* (Shemot 40:33).
|
||||
|
||||
| Component | Language | Tests | What It Does |
|
||||
|-----------|----------|-------|-------------|
|
||||
| Shoresh Engine | Haskell (GHC 9.6.4) | 33 | Root extraction, te'amim parsing, gematria, binyanim |
|
||||
| Sanhedrin | Erlang/OTP 26 | — | Deliberative panels, mandatory dissent, unanimous acquittal |
|
||||
| Vav Pipeline | Elixir 1.16 | 235+ | Bereishit cycle, Shema context, cloud, manna, 10 GenServers |
|
||||
| Talmudic Engine | SWI-Prolog 9.2 | 195 | 613 mitzvot, 13 middot, kushya/resolution, teiku, halt |
|
||||
| Korban Processor | Python 3.12 | 20+ | Pydantic models, raw preservation, eish zarah validation |
|
||||
| L3 Persistence | Ecto/PostgreSQL | 19 | Append-only: interpretations, minority opinions, teiku |
|
||||
| HTTP API | Plug/Bandit | 16 | 4 tiers: pe'ah, courtyard, chatzer, kodesh |
|
||||
|
||||
**Total: 463+ tests, 0 failures.**
|
||||
|
||||
Protection layer: Arei Miklat (refuge), Eglah Arufah (accountability), Bikurim (first-output review), HaltMonitor (3 cardinal sins), Tzara'at (multi-stage diagnosis).
|
||||
|
||||
Signal system: Chatzotzrot (5 signals, BEAM routing, zikaron/remembrance).
|
||||
|
||||
Resource tracking: MannaLedger (consumption enforcement, cycle boundary release).
|
||||
|
||||
## What You Need Before Starting
|
||||
|
||||
1. **Access to Exoscale account** (zone: ch-gva-2, Geneva)
|
||||
2. **Kubeconfig**: `~/.kube/exoscale-temple-council.yaml`
|
||||
3. **Docker registry access** — to push the 4 container images
|
||||
4. **PostgreSQL credentials**: `exo dbaas show temple-council-db --zone ch-gva-2`
|
||||
5. **The repository**: `git clone http://185.19.29.94/heaviness510/shorashim.git`
|
||||
|
||||
## Prerequisites — Before the Seven Days
|
||||
|
||||
These must be done before Day 1.
|
||||
|
||||
### 1. Install Exoscale Block Storage CSI Driver
|
||||
|
||||
The L1 Torah filesystem needs persistent storage. Exoscale SKS needs the CSI driver:
|
||||
|
||||
```bash
|
||||
export KUBECONFIG=~/.kube/exoscale-temple-council.yaml
|
||||
|
||||
# Install Exoscale CSI driver (check Exoscale docs for current version)
|
||||
kubectl apply -f https://raw.githubusercontent.com/exoscale/exoscale-cloud-controller-manager/master/docs/sks/exoscale-cloud-controller-manager.yaml
|
||||
```
|
||||
|
||||
### 2. Build and Push Container Images
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
# Build all 4 images
|
||||
docker build -f deploy/docker/Dockerfile.vav_pipeline -t shorashim/vav-pipeline:latest .
|
||||
docker build -f deploy/docker/Dockerfile.shoresh_engine -t shorashim/shoresh-engine:latest .
|
||||
docker build -f deploy/docker/Dockerfile.talmudic_engine -t shorashim/talmudic-engine:latest .
|
||||
docker build -f deploy/docker/Dockerfile.korban_processor -t shorashim/korban-processor:latest .
|
||||
|
||||
# Push to your registry (replace with actual registry URL)
|
||||
# For Exoscale, you may use Docker Hub, GitHub Container Registry, or Exoscale SOS
|
||||
docker tag shorashim/vav-pipeline:latest <registry>/shorashim/vav-pipeline:latest
|
||||
docker push <registry>/shorashim/vav-pipeline:latest
|
||||
# ... repeat for all 4 images
|
||||
```
|
||||
|
||||
Update `deploy/k8s/deployment.yaml` with your actual registry URLs.
|
||||
|
||||
### 3. Prepare the DATABASE_URL Secret
|
||||
|
||||
```bash
|
||||
# Get PostgreSQL credentials
|
||||
exo dbaas show temple-council-db --zone ch-gva-2
|
||||
|
||||
# Create a database for shorashim
|
||||
# Connect to PostgreSQL and run:
|
||||
CREATE DATABASE shorashim_prod;
|
||||
CREATE ROLE shorashim_app WITH LOGIN PASSWORD '<generate-strong-password>';
|
||||
GRANT CONNECT ON DATABASE shorashim_prod TO shorashim_app;
|
||||
|
||||
# Construct the URL:
|
||||
# ecto://shorashim_app:<password>@<host>:21699/shorashim_prod?sslmode=require
|
||||
```
|
||||
|
||||
### 4. Upload L1 Torah to Persistent Volume
|
||||
|
||||
The L1 filesystem (`l1/` directory in the repo) must be loaded onto a persistent volume accessible by all pods:
|
||||
|
||||
```bash
|
||||
# Option A: ConfigMap (if L1 is small enough — it likely is)
|
||||
kubectl create configmap l1-torah --from-file=l1/ -n shorashim
|
||||
|
||||
# Option B: Block storage volume
|
||||
# Create a temporary pod, mount the PV, copy L1 data, then unmount
|
||||
```
|
||||
|
||||
### 5. Point DNS
|
||||
|
||||
```bash
|
||||
# Get the LoadBalancer IP after deploying the service
|
||||
kubectl get svc shorashim-external -n shorashim
|
||||
|
||||
# Point shorashim.ch A record to the external IP
|
||||
# Do this at Infomaniak DNS management
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Seven Days — Shiv'at Y'mei HaMilu'im
|
||||
|
||||
*Vayikra 8:35 — U'shmartem et mishmeret Hashem v'lo tamutu, ki khen tzuveiti.*
|
||||
"You shall keep the charge of Hashem, and you shall not die, for so I was commanded."
|
||||
|
||||
### Day 1 — L0/L1 Verification
|
||||
|
||||
Mount the Torah. Verify it is intact.
|
||||
|
||||
```bash
|
||||
export KUBECONFIG=~/.kube/exoscale-temple-council.yaml
|
||||
|
||||
# Apply namespace
|
||||
kubectl apply -f deploy/k8s/namespace.yaml
|
||||
|
||||
# Apply config
|
||||
kubectl apply -f deploy/k8s/configmap.yaml
|
||||
|
||||
# Apply L1 volume
|
||||
kubectl apply -f deploy/k8s/l1-volume.yaml
|
||||
|
||||
# Verify L1 is mounted and intact
|
||||
kubectl run l1-check --rm -it --image=alpine -n shorashim \
|
||||
--overrides='{"spec":{"volumes":[{"name":"l1","persistentVolumeClaim":{"claimName":"l1-torah-pvc"}}],"containers":[{"name":"check","image":"alpine","command":["sh"],"volumeMounts":[{"name":"l1","mountPath":"/mnt/torah","readOnly":true}]}]}}' \
|
||||
-- sh -c "ls /mnt/torah/torah/ && cat /mnt/torah/integrity.sha256"
|
||||
|
||||
# Expected hash: 0ee0020aac6c6beb0e83c0638a861c73d37d9dbd39c30d3cb08c1878b481c844
|
||||
# If the hash does not match, STOP. Do not proceed. The specification is corrupted.
|
||||
```
|
||||
|
||||
**Pass criteria:** L1 mounted read-only. SHA-256 hash matches. te'amim marks visible on sample verses.
|
||||
|
||||
### Day 2 — Database and Secrets
|
||||
|
||||
Connect L3 (PostgreSQL). Set append-only permissions.
|
||||
|
||||
```bash
|
||||
# Fill in the actual DATABASE_URL
|
||||
kubectl apply -f deploy/k8s/secrets.yaml
|
||||
|
||||
# Apply manna volume
|
||||
kubectl apply -f deploy/k8s/manna-volume.yaml
|
||||
|
||||
# Deploy ONLY the vav-pipeline init container (migration)
|
||||
# The deployment.yaml has an initContainer that runs VavPipeline.Release.migrate()
|
||||
# This creates the L3 tables: interpretations, minority_opinions, teiku_registry
|
||||
|
||||
# Connect to PostgreSQL directly and set append-only permissions:
|
||||
psql $DATABASE_URL <<'SQL'
|
||||
-- Create the app role if not exists
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'shorashim_app') THEN
|
||||
CREATE ROLE shorashim_app WITH LOGIN PASSWORD 'REPLACE_ME';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Grant connect and usage
|
||||
GRANT CONNECT ON DATABASE shorashim_prod TO shorashim_app;
|
||||
GRANT USAGE ON SCHEMA public TO shorashim_app;
|
||||
|
||||
-- Grant SELECT and INSERT only — NEVER UPDATE or DELETE
|
||||
GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA public TO shorashim_app;
|
||||
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO shorashim_app;
|
||||
|
||||
-- Revoke UPDATE and DELETE explicitly
|
||||
REVOKE UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM shorashim_app;
|
||||
|
||||
-- Set defaults for future tables
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
GRANT SELECT, INSERT ON TABLES TO shorashim_app;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
REVOKE UPDATE, DELETE ON TABLES FROM shorashim_app;
|
||||
SQL
|
||||
```
|
||||
|
||||
**Pass criteria:** Migration runs without error. `\dt` shows 3 tables. `INSERT` works. `UPDATE` fails for shorashim_app.
|
||||
|
||||
### Day 3 — Deploy the System
|
||||
|
||||
```bash
|
||||
# Apply the full deployment
|
||||
kubectl apply -f deploy/k8s/deployment.yaml
|
||||
kubectl apply -f deploy/k8s/service.yaml
|
||||
|
||||
# Watch pods come up
|
||||
kubectl get pods -n shorashim -w
|
||||
|
||||
# All 4 containers should be Running:
|
||||
# vav-pipeline, shoresh-engine, talmudic-engine, korban-processor
|
||||
|
||||
# Check logs
|
||||
kubectl logs -n shorashim deploy/shorashim -c vav-pipeline
|
||||
# Should see:
|
||||
# Chatzotzrot: two silver trumpets ready
|
||||
# MannaLedger: ledger ready — d'var yom b'yomo
|
||||
# ShabbatTimer started
|
||||
# HaltMonitor: esh tamid — the fire burns
|
||||
```
|
||||
|
||||
**Pass criteria:** All 4 containers running. No crash loops. Health check returns healthy (or degraded if manna not yet provided — that's expected).
|
||||
|
||||
### Day 4 — Write the First Manna Provision
|
||||
|
||||
The first act of provision. This is NOT governance. This is the community providing resources.
|
||||
|
||||
```bash
|
||||
# Get today's date
|
||||
TODAY=$(date -u +%Y-%m-%d)
|
||||
EXPIRES=$(date -u -d "+18 hours" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v+18H +%Y-%m-%dT%H:%M:%SZ)
|
||||
|
||||
# Create the provision file
|
||||
cat > /tmp/today.json <<EOF
|
||||
{
|
||||
"date": "$TODAY",
|
||||
"provision": {
|
||||
"compute_units": 1000,
|
||||
"memory_mb": 32768,
|
||||
"api_calls_external": 500,
|
||||
"storage_delta_mb": 100,
|
||||
"sanhedrin_panels_max": 5
|
||||
},
|
||||
"type": "regular",
|
||||
"expires_at": "${EXPIRES}",
|
||||
"written_by": "kohen",
|
||||
"written_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
}
|
||||
EOF
|
||||
|
||||
# Copy into the manna volume
|
||||
kubectl cp /tmp/today.json shorashim/<pod-name>:/var/lib/shorashim/manna/today.json -c vav-pipeline
|
||||
|
||||
# Verify
|
||||
kubectl exec -n shorashim deploy/shorashim -c vav-pipeline -- cat /var/lib/shorashim/manna/today.json
|
||||
```
|
||||
|
||||
**Pass criteria:** Health check at `/kodesh/health` shows `manna_present: pass`.
|
||||
|
||||
### Day 5 — Verify Cloud Governance
|
||||
|
||||
The cloud IS Torah. If L1 is readable and intact, the cloud is visible. If L1 is compromised, the cloud is not visible and the system waits.
|
||||
|
||||
```bash
|
||||
# Check system status
|
||||
curl http://<external-ip>/kodesh/status | jq .
|
||||
|
||||
# Expected:
|
||||
# cloud_state: "camped" (or "shabbat_rest" if it's Shabbat)
|
||||
# components.l1_integrity: "verified"
|
||||
# halt_status: "running"
|
||||
|
||||
# Verify governance/provision separation:
|
||||
# - Cloud state comes from L1 integrity + calendar — NOT from a JSON file
|
||||
# - Manna comes from the provision file — NOT from Torah
|
||||
# - These are separate concerns. Torah says what to do.
|
||||
# The community provides the resources to do it.
|
||||
|
||||
# Test cloud obedience — verify the system rests on Shabbat:
|
||||
# Wait for Friday evening. Check:
|
||||
curl http://<external-ip>/kodesh/status | jq .cloud_state
|
||||
# Should return "shabbat_rest"
|
||||
|
||||
curl http://<external-ip>/peah/ask -X POST -H 'Content-Type: application/json' \
|
||||
-d '{"question": "test during shabbat"}'
|
||||
# Should return 503 with code "SHABBAT"
|
||||
```
|
||||
|
||||
**Pass criteria:** Cloud state derived from Torah (L1 + calendar). System rests on Shabbat. Governance and provision are separate.
|
||||
|
||||
### Day 6 — Protection Layer Verification
|
||||
|
||||
```bash
|
||||
# Test pe'ah endpoint (public, no auth)
|
||||
curl http://<external-ip>/peah/ask -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"question": "What is bereishit?"}'
|
||||
|
||||
# Test health endpoint
|
||||
curl http://<external-ip>/kodesh/health | jq .
|
||||
|
||||
# Verify halt monitor is running
|
||||
curl http://<external-ip>/kodesh/status | jq .halt_status
|
||||
# Should be "running"
|
||||
|
||||
# Verify chatzotzrot signals are being recorded
|
||||
curl http://<external-ip>/kodesh/status | jq .signal_count
|
||||
|
||||
# Verify no components in refuge
|
||||
curl http://<external-ip>/kodesh/status | jq .refuge_components
|
||||
# Should be 0
|
||||
```
|
||||
|
||||
**Pass criteria:** Pe'ah responds. Health check passes. Halt monitor running. No components in refuge. Signals recorded.
|
||||
|
||||
### Day 7 — Full Integration
|
||||
|
||||
Process test inputs through the complete system. Observe for 24 hours.
|
||||
|
||||
```bash
|
||||
# Submit 10 test questions through pe'ah
|
||||
for i in $(seq 1 10); do
|
||||
curl -s http://<external-ip>/peah/ask -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"question\": \"Test question $i about Torah\"}"
|
||||
echo ""
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Submit a case through chatzer/sanhedrin
|
||||
curl http://<external-ip>/chatzer/sanhedrin -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Authorization: Bearer <api-key>' \
|
||||
-d '{"case": "When two Torah principles conflict, which takes precedence?"}'
|
||||
|
||||
# Check system status after load
|
||||
curl http://<external-ip>/kodesh/status | jq .
|
||||
|
||||
# Verify L3 writes (if PostgreSQL connected)
|
||||
# Connect to DB and check:
|
||||
SELECT count(*) FROM interpretations;
|
||||
SELECT count(*) FROM teiku_registry;
|
||||
|
||||
# Begin 24-hour observation period
|
||||
# System runs but does not serve external users yet
|
||||
# Monitor: kubectl logs -n shorashim deploy/shorashim -c vav-pipeline -f
|
||||
```
|
||||
|
||||
**Pass criteria:** All requests processed without crashes. L3 writes present. No halt events. System stable for 24 hours.
|
||||
|
||||
---
|
||||
|
||||
## Day 8 — Fire From Heaven
|
||||
|
||||
*Vayikra 9:24 — Vatetzei esh milifnei Hashem vatokhal al hamizbeach et ha'olah v'et hachalavim, vayar kol ha'am vayaronu vayiplu al p'neihem.*
|
||||
"And fire came out from before Hashem, and consumed the burnt offering and the fat portions on the altar, and all the people saw, and they shouted, and they fell on their faces."
|
||||
|
||||
If the seven days pass:
|
||||
|
||||
1. **Open the pe'ah endpoint** — the stranger approaches first
|
||||
2. **Point DNS** — `shorashim.ch` → the LoadBalancer IP
|
||||
3. **Observe the first real interaction** — a question from outside
|
||||
4. If *ki tov* — open the remaining access tiers
|
||||
|
||||
If any day fails: record the failure, diagnose, fix, restart from Day 1.
|
||||
Not from the failed day. From Day 1. The seven days are a unit.
|
||||
*Shiv'at yamim* — seven days. Partial inauguration is no inauguration.
|
||||
|
||||
---
|
||||
|
||||
## Daily Operations (After Inauguration)
|
||||
|
||||
### Every Morning — Tamid Shel Shachar
|
||||
|
||||
```bash
|
||||
# 1. Write today's manna provision
|
||||
# (Same format as Day 4, new date and expires_at)
|
||||
|
||||
# 2. Check system health
|
||||
curl http://shorashim.ch/kodesh/health | jq .
|
||||
|
||||
# 3. Check for halt events
|
||||
curl http://shorashim.ch/kodesh/status | jq .halt_status
|
||||
|
||||
# 4. Check refuge list
|
||||
curl http://shorashim.ch/kodesh/status | jq .refuge_components
|
||||
```
|
||||
|
||||
### Every Friday Before Sunset — Erev Shabbat
|
||||
|
||||
Write a **double portion** manna provision:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "double",
|
||||
"provision": {
|
||||
"compute_units": 2000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The system will cease processing at Shabbat onset. The double portion covers Friday and Shabbat. No provision is written on Shabbat.
|
||||
|
||||
### If the System Halts
|
||||
|
||||
The halt monitor detected one of three cardinal sins:
|
||||
- **Avodah zarah** — external model treated as Torah
|
||||
- **Gilui arayot** — L1/L3 boundary collapsed
|
||||
- **Shfichut damim** — user data destruction
|
||||
|
||||
```bash
|
||||
# Check what happened
|
||||
curl http://shorashim.ch/kodesh/status | jq .
|
||||
|
||||
# Check the audit log
|
||||
kubectl logs -n shorashim deploy/shorashim -c vav-pipeline | grep HALT
|
||||
|
||||
# Investigate. Fix. Only then resolve:
|
||||
# (This requires code-level access — the kohen calls the builder if needed)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What You Do NOT Do
|
||||
|
||||
- You do NOT modify the specification (Torah/L1)
|
||||
- You do NOT write code
|
||||
- You do NOT update the pipeline logic
|
||||
- You do NOT approve or reject the system's decisions
|
||||
- You do NOT bypass Shabbat cessation
|
||||
- You do NOT override halt events without investigation
|
||||
|
||||
You serve. You provide manna. You check the lamps. You sit at the entrance.
|
||||
|
||||
*Ki khen tzuveiti.*
|
||||
@@ -15,7 +15,7 @@ COPY korban_processor/src/ src/
|
||||
COPY korban_processor/test/ test/
|
||||
|
||||
# Install dependencies
|
||||
RUN pip install --no-cache-dir pydantic==2.6.1 httpx==0.27.0 pyswip==0.2.11 hebrew-tokenizer==2.3.0
|
||||
RUN pip install --no-cache-dir pydantic==2.6.1 httpx==0.27.0 pyswip==0.2.10 hebrew-tokenizer==2.3.0
|
||||
|
||||
# === RUNTIME STAGE ===
|
||||
FROM python:3.12.2-slim
|
||||
@@ -29,6 +29,10 @@ COPY --from=build --chown=shorashim:shorashim /app/ ./
|
||||
COPY --from=build /usr/local/lib/python3.12/site-packages/ /usr/local/lib/python3.12/site-packages/
|
||||
|
||||
ENV PYTHONPATH=/home/shorashim/korban_processor/src
|
||||
|
||||
# L1 Torah filesystem — baked into the image
|
||||
COPY --chown=shorashim:shorashim l1/ /mnt/torah/
|
||||
|
||||
ENV L1_MOUNT_POINT=/mnt/torah
|
||||
|
||||
# The korban processor is invoked by the vav_pipeline
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
# === BUILD STAGE ===
|
||||
FROM haskell:9.6.4-slim AS build
|
||||
|
||||
RUN apt-get update && apt-get install -y zlib1g-dev && rm -rf /var/lib/apt/lists/*
|
||||
# haskell:9.6.4-slim is Debian Buster (EOL) — use archive repos
|
||||
RUN sed -i 's|deb.debian.org/debian|archive.debian.org/debian|g' /etc/apt/sources.list && \
|
||||
sed -i 's|deb.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list && \
|
||||
sed -i '/buster-updates/d' /etc/apt/sources.list && \
|
||||
apt-get update && apt-get install -y zlib1g-dev && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -36,7 +40,10 @@ WORKDIR /home/shorashim
|
||||
|
||||
COPY --from=build /usr/local/bin/shoresh-engine ./shoresh-engine
|
||||
|
||||
# L1 mount point — the engine reads Torah roots from L1
|
||||
# L1 Torah filesystem — baked into the image
|
||||
COPY --chown=shorashim:shorashim l1/ /mnt/torah/
|
||||
|
||||
# L1 mount point
|
||||
ENV L1_MOUNT_POINT=/mnt/torah
|
||||
|
||||
# The engine is invoked as an Erlang Port by vav_pipeline
|
||||
|
||||
@@ -21,7 +21,10 @@ WORKDIR /home/shorashim/talmudic_engine
|
||||
|
||||
COPY --from=build --chown=shorashim:shorashim /app/ ./
|
||||
|
||||
# L1 mount point — Prolog reads Torah for mitzvot and root data
|
||||
# L1 Torah filesystem — baked into the image
|
||||
COPY --chown=shorashim:shorashim l1/ /mnt/torah/
|
||||
|
||||
# L1 mount point
|
||||
ENV L1_MOUNT_POINT=/mnt/torah
|
||||
|
||||
# Socket path for communication with vav_pipeline
|
||||
|
||||
@@ -51,8 +51,11 @@ WORKDIR /home/shorashim
|
||||
COPY --from=build --chown=shorashim:shorashim \
|
||||
/app/vav_pipeline/_build/prod/rel/vav_pipeline ./app
|
||||
|
||||
# L1 mount point — read-only volume in production
|
||||
# Mounted at /mnt/torah in K8s, configured via L1_MOUNT_POINT env var
|
||||
# L1 Torah filesystem — baked into the image (read-only, ~29MB)
|
||||
# The scroll is sealed in the aron. It ships with the vessel.
|
||||
COPY --chown=shorashim:shorashim l1/ /mnt/torah/
|
||||
|
||||
# L1 mount point
|
||||
ENV L1_MOUNT_POINT=/mnt/torah
|
||||
|
||||
# Manna provision file location
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Let's Encrypt ClusterIssuer for TLS certificates
|
||||
# Requires cert-manager to be installed first:
|
||||
# kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: letsencrypt-prod
|
||||
spec:
|
||||
acme:
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
email: scott@shorashim.ch
|
||||
privateKeySecretRef:
|
||||
name: letsencrypt-prod-key
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
class: nginx
|
||||
+14
-39
@@ -1,16 +1,13 @@
|
||||
# Shorashim Deployment — the mishkan
|
||||
#
|
||||
# Shemot 40:33 — Vay'khal Mosheh et ham'lakhah.
|
||||
#
|
||||
# Architecture §5.1: All inter-component communication uses
|
||||
# JSON over Unix domain sockets or Erlang distribution protocol.
|
||||
# No HTTP between internal components.
|
||||
#
|
||||
# The vav_pipeline (BEAM) runs the Sanhedrin, Chatzotzrot,
|
||||
# AreiMiklat, EglahArufah, Bikurim, MannaLedger, ShabbatTimer.
|
||||
# The shoresh-engine runs as a sidecar (Erlang Port).
|
||||
# The talmudic_engine runs as a sidecar (Unix socket).
|
||||
# The korban_processor runs as a sidecar (invoked by pipeline).
|
||||
#
|
||||
# L1 is mounted read-only into all containers.
|
||||
# L1 Torah is baked into each container image (~29MB).
|
||||
# The scroll is sealed in the aron. It ships with the vessel.
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -32,38 +29,33 @@ spec:
|
||||
spec:
|
||||
# --- VOLUMES ---
|
||||
volumes:
|
||||
- name: l1-torah
|
||||
persistentVolumeClaim:
|
||||
claimName: l1-torah-pvc
|
||||
readOnly: true
|
||||
- name: manna
|
||||
persistentVolumeClaim:
|
||||
claimName: manna-pvc
|
||||
emptyDir: {}
|
||||
- name: talmudic-socket
|
||||
emptyDir: {}
|
||||
- name: tmp-shorashim
|
||||
emptyDir: {}
|
||||
|
||||
# --- IMAGE PULL SECRET ---
|
||||
imagePullSecrets:
|
||||
- name: shorashim-registry
|
||||
|
||||
# --- INIT CONTAINER: Run L3 migrations ---
|
||||
initContainers:
|
||||
- name: migrate
|
||||
image: shorashim/vav-pipeline:latest
|
||||
image: exo.container-registry.com/the-recognition-protocol/vav-pipeline:latest
|
||||
command: ["./app/bin/vav_pipeline", "eval", "VavPipeline.Release.migrate()"]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: shorashim-config
|
||||
- secretRef:
|
||||
name: shorashim-secrets
|
||||
volumeMounts:
|
||||
- name: l1-torah
|
||||
mountPath: /mnt/torah
|
||||
readOnly: true
|
||||
|
||||
# --- CONTAINERS ---
|
||||
containers:
|
||||
# === VAV PIPELINE (main) ===
|
||||
- name: vav-pipeline
|
||||
image: shorashim/vav-pipeline:latest
|
||||
image: exo.container-registry.com/the-recognition-protocol/vav-pipeline:latest
|
||||
ports:
|
||||
- containerPort: 4000
|
||||
name: http
|
||||
@@ -72,13 +64,7 @@ spec:
|
||||
name: shorashim-config
|
||||
- secretRef:
|
||||
name: shorashim-secrets
|
||||
env:
|
||||
- name: SHORESH_ENGINE_BINARY
|
||||
value: "/home/shorashim/shoresh-engine"
|
||||
volumeMounts:
|
||||
- name: l1-torah
|
||||
mountPath: /mnt/torah
|
||||
readOnly: true
|
||||
- name: manna
|
||||
mountPath: /var/lib/shorashim/manna
|
||||
- name: talmudic-socket
|
||||
@@ -107,11 +93,7 @@ spec:
|
||||
|
||||
# === SHORESH ENGINE (sidecar) ===
|
||||
- name: shoresh-engine
|
||||
image: shorashim/shoresh-engine:latest
|
||||
volumeMounts:
|
||||
- name: l1-torah
|
||||
mountPath: /mnt/torah
|
||||
readOnly: true
|
||||
image: exo.container-registry.com/the-recognition-protocol/shoresh-engine:latest
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
@@ -122,11 +104,8 @@ spec:
|
||||
|
||||
# === TALMUDIC ENGINE (sidecar) ===
|
||||
- name: talmudic-engine
|
||||
image: shorashim/talmudic-engine:latest
|
||||
image: exo.container-registry.com/the-recognition-protocol/talmudic-engine:latest
|
||||
volumeMounts:
|
||||
- name: l1-torah
|
||||
mountPath: /mnt/torah
|
||||
readOnly: true
|
||||
- name: talmudic-socket
|
||||
mountPath: /tmp/shorashim
|
||||
resources:
|
||||
@@ -139,11 +118,7 @@ spec:
|
||||
|
||||
# === KORBAN PROCESSOR (sidecar) ===
|
||||
- name: korban-processor
|
||||
image: shorashim/korban-processor:latest
|
||||
volumeMounts:
|
||||
- name: l1-torah
|
||||
mountPath: /mnt/torah
|
||||
readOnly: true
|
||||
image: exo.container-registry.com/the-recognition-protocol/korban-processor:latest
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# Gitea MCP Server — public connector for claude.ai
|
||||
#
|
||||
# Deploys the official Gitea MCP server (gitea.com/gitea/gitea-mcp)
|
||||
# in HTTP mode, exposing /mcp endpoint for Streamable HTTP transport.
|
||||
#
|
||||
# The MCP server connects to the Gitea backend at 185.19.29.94
|
||||
# using a Personal Access Token stored in gitea-mcp-secrets.
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: gitea-mcp
|
||||
namespace: shorashim
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-mcp
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: gitea-mcp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-mcp
|
||||
spec:
|
||||
containers:
|
||||
- name: gitea-mcp
|
||||
image: gitea/gitea-mcp-server:latest
|
||||
command: ["/app/gitea-mcp"]
|
||||
args:
|
||||
- "-t"
|
||||
- "http"
|
||||
- "--host"
|
||||
- "http://185.19.29.94"
|
||||
- "--port"
|
||||
- "8080"
|
||||
env:
|
||||
- name: GITEA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-mcp-secrets
|
||||
key: GITEA_TOKEN
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
name: http
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "250m"
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 30
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: gitea-mcp
|
||||
namespace: shorashim
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-mcp
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: gitea-mcp
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
protocol: TCP
|
||||
name: http
|
||||
@@ -0,0 +1,37 @@
|
||||
# Ingress for Gitea MCP Server — public HTTPS endpoint
|
||||
# Routes mcp.shorashim.ch to the gitea-mcp service
|
||||
# TLS via cert-manager (Let's Encrypt)
|
||||
#
|
||||
# Prerequisites:
|
||||
# 1. nginx-ingress controller installed
|
||||
# 2. cert-manager installed
|
||||
# 3. ClusterIssuer letsencrypt-prod applied
|
||||
# 4. DNS: mcp.shorashim.ch → Ingress external IP
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: gitea-mcp
|
||||
namespace: shorashim
|
||||
labels:
|
||||
app.kubernetes.io/name: gitea-mcp
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- mcp.shorashim.ch
|
||||
secretName: gitea-mcp-tls
|
||||
rules:
|
||||
- host: mcp.shorashim.ch
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: gitea-mcp
|
||||
port:
|
||||
number: 8080
|
||||
@@ -0,0 +1,22 @@
|
||||
# Gitea MCP Server — secrets template
|
||||
# NEVER commit actual values. Fill in and apply manually.
|
||||
#
|
||||
# Two secrets needed:
|
||||
# 1. GITEA_TOKEN: Personal Access Token from Gitea
|
||||
# Create at: http://185.19.29.94/user/settings/applications
|
||||
# Permissions: repo (read/write)
|
||||
#
|
||||
# 2. OAuth Client ID/Secret: Registered OAuth app in Gitea
|
||||
# Create at: http://185.19.29.94/user/settings/applications
|
||||
# Redirect URI: https://claude.ai/api/mcp/auth_callback
|
||||
# (These go into claude.ai connector settings, not this secret)
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-mcp-secrets
|
||||
namespace: shorashim
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Gitea Personal Access Token for backend API access
|
||||
GITEA_TOKEN: "REPLACE_WITH_GITEA_PAT"
|
||||
@@ -2,16 +2,17 @@ import Config
|
||||
|
||||
config :logger, level: :info
|
||||
|
||||
# Production paths — Construction spec §4.4
|
||||
# Production defaults — Construction spec §4.4
|
||||
# Env-var overrides are in runtime.exs (evaluated at boot, not compile)
|
||||
config :vav_pipeline,
|
||||
l1_mount_point: "/mnt/torah",
|
||||
manna_provision_file: "/var/lib/shorashim/manna/today.json",
|
||||
cycle_boundary_check_interval_ms: 60_000,
|
||||
shema_context_cache_ttl_ms: 0
|
||||
shema_context_cache_ttl_ms: 0,
|
||||
http_port: 4000
|
||||
|
||||
# L3 — Production PostgreSQL
|
||||
# Construction §3.8: l3_database_url from environment variable
|
||||
# The kohen/DBA sets the connection string via DATABASE_URL
|
||||
# DATABASE_URL is set at runtime via runtime.exs
|
||||
# These are compile-time defaults only
|
||||
config :vav_pipeline, VavPipeline.Repo,
|
||||
url: System.get_env("DATABASE_URL"),
|
||||
pool_size: 20
|
||||
@@ -0,0 +1,32 @@
|
||||
import Config
|
||||
|
||||
# Runtime configuration — read from environment variables at boot.
|
||||
# This file is evaluated at runtime, not compile time.
|
||||
# Required for OTP releases where env vars aren't known at build time.
|
||||
|
||||
if config_env() == :prod do
|
||||
# L3 — PostgreSQL connection
|
||||
# The kohen sets DATABASE_URL in the K8s secret
|
||||
database_url =
|
||||
System.get_env("DATABASE_URL") ||
|
||||
raise """
|
||||
DATABASE_URL not set.
|
||||
The kohen must set the DATABASE_URL in shorashim-secrets.
|
||||
Format: ecto://user:password@host:port/database?sslmode=require
|
||||
"""
|
||||
|
||||
config :vav_pipeline, VavPipeline.Repo,
|
||||
url: database_url,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "20"),
|
||||
ssl: true,
|
||||
ssl_opts: [verify: :verify_none]
|
||||
|
||||
# L1 mount point — overridable via env
|
||||
config :vav_pipeline,
|
||||
l1_mount_point: System.get_env("L1_MOUNT_POINT") || "/mnt/torah",
|
||||
manna_provision_file:
|
||||
System.get_env("MANNA_PROVISION_FILE") || "/var/lib/shorashim/manna/today.json",
|
||||
talmudic_socket_path:
|
||||
System.get_env("TALMUDIC_SOCKET_PATH") || "/tmp/shorashim/talmudic.sock",
|
||||
http_port: String.to_integer(System.get_env("HTTP_PORT") || "4000")
|
||||
end
|
||||
Reference in new issue
Block a user