Phase 5 deployment: Dockerfiles, K8s manifests, halt monitor (Steps 33, 36)

Shemot 40:33 — Vay'khal Moshe et ham'lakhah.
The builder completes the work. The vessel is ready for transport.

Step 33 — Deployment configuration:
- Dockerfiles for all 4 components:
  - vav_pipeline: Elixir 1.16.1/OTP 26.2.1 release with Sanhedrin
  - shoresh_engine: GHC 9.6.4 binary
  - talmudic_engine: SWI-Prolog 9.2.2
  - korban_processor: Python 3.12.2 with pydantic
- Kubernetes manifests for Exoscale SKS (ch-gva-2):
  - Namespace, ConfigMap, Secrets template
  - L1 Torah PV/PVC (read-only mount)
  - Manna provision PVC (kohen writes, system reads)
  - Deployment: vav-pipeline + 3 sidecars, shared volumes
  - Service: ClusterIP + LoadBalancer with Exoscale NLB
  - Init container runs Ecto migrations (VavPipeline.Release)

Step 36 — Halt monitor (esh tamid):
- GenServer watches for three cardinal sins
- halt!/3 immediately halts system, sounds Chatzotzrot war signal
- Permanent audit log — halt events never deleted
- resolve/1 requires explicit operator action to resume
- alive?/0 for morning tamid verification
- 13 tests: alive check, 3 halt types, resolution, audit log,
  chatzotzrot war signal integration
- Added to supervision tree

All 219 Elixir + 19 L3 + 195 Prolog + 33 Haskell = 447+ tests, 0 failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott KarpandClaude Opus 4.6 committed 2026-03-22 07:11:02 -04:00
1 parent 219bbecaff
commit fe93c11d13
15 files changed
+889

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
# Shorashim Korban Processor — Python offering protocol
# Construction spec §1.1: Python 3.12.2
# Processes korbanot (model outputs) through the offering protocol
FROM python:3.12.2-slim AS build
WORKDIR /app
# Install build deps
RUN pip install --no-cache-dir poetry-core
# Copy project files
COPY korban_processor/pyproject.toml ./
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
# === RUNTIME STAGE ===
FROM python:3.12.2-slim
RUN useradd --create-home --shell /bin/bash shorashim
USER shorashim
WORKDIR /home/shorashim/korban_processor
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
ENV L1_MOUNT_POINT=/mnt/torah
# The korban processor is invoked by the vav_pipeline
# In Phase 5, it will also expose an HTTP endpoint for external model integration
CMD ["python", "-m", "korban_processor"]
+44
View File
@@ -0,0 +1,44 @@
# Shorashim Shoresh Engine — Haskell root activation engine
# Construction spec §1.1: GHC 9.6.4, Cabal 3.10
# Communicates with vav_pipeline via Erlang Port (stdin/stdout)
# === 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/*
WORKDIR /app
# Copy cabal files first for dependency caching
COPY shoresh-engine/shoresh-engine.cabal ./
COPY shoresh-engine/cabal.project.freeze ./
RUN cabal update && cabal build --only-dependencies
# Copy source and build
COPY shoresh-engine/ ./
RUN cabal build && \
cp $(cabal list-bin shoresh-engine) /usr/local/bin/shoresh-engine
# === RUNTIME STAGE ===
FROM ubuntu:jammy-20240125
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libgmp10 zlib1g && \
rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --shell /bin/bash shorashim
USER shorashim
WORKDIR /home/shorashim
COPY --from=build /usr/local/bin/shoresh-engine ./shoresh-engine
# L1 mount point — the engine reads Torah roots from L1
ENV L1_MOUNT_POINT=/mnt/torah
# The engine is invoked as an Erlang Port by vav_pipeline
# In K8s, it runs as a sidecar or is called via the Port protocol
CMD ["./shoresh-engine"]
+31
View File
@@ -0,0 +1,31 @@
# Shorashim Talmudic Engine — SWI-Prolog dialectical reasoning
# Construction spec §1.1: SWI-Prolog 9.2.2
# Communicates with vav_pipeline via Unix domain socket
# === BUILD STAGE ===
FROM swipl:9.2.2 AS build
WORKDIR /app
COPY talmudic_engine/ ./
# Verify Prolog loads without errors
RUN swipl -g "consult('src/main'),halt(0)" -t "halt(1)"
# === RUNTIME STAGE ===
FROM swipl:9.2.2
RUN useradd --create-home --shell /bin/bash shorashim
USER shorashim
WORKDIR /home/shorashim/talmudic_engine
COPY --from=build --chown=shorashim:shorashim /app/ ./
# L1 mount point — Prolog reads Torah for mitzvot and root data
ENV L1_MOUNT_POINT=/mnt/torah
# Socket path for communication with vav_pipeline
ENV TALMUDIC_SOCKET_PATH=/tmp/shorashim/talmudic.sock
# Start the Prolog socket server
CMD ["swipl", "-g", "consult('src/main'),start_socket_server", "-t", "halt(1)"]
+68
View File
@@ -0,0 +1,68 @@
# Shorashim Vav Pipeline — Elixir/OTP release with Sanhedrin
# Construction spec §1.1: Elixir 1.16.1, OTP 26.2.1
# The pipeline and Sanhedrin run in the same BEAM VM.
# === BUILD STAGE ===
FROM hexpm/elixir:1.16.1-erlang-26.2.1-ubuntu-jammy-20240125 AS build
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy Sanhedrin (Erlang dep, referenced as path dep from vav_pipeline)
COPY sanhedrin/ sanhedrin/
# Copy Vav Pipeline
COPY vav_pipeline/ vav_pipeline/
WORKDIR /app/vav_pipeline
# Fetch deps and compile in prod mode
ENV MIX_ENV=prod
RUN mix local.hex --force && \
mix local.rebar --force && \
mix deps.get --only prod && \
mix compile
# Build OTP release
RUN mix release
# === RUNTIME STAGE ===
FROM ubuntu:jammy-20240125
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libstdc++6 openssl ca-certificates locales && \
rm -rf /var/lib/apt/lists/* && \
sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
locale-gen
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
# Non-root user — the system serves, it does not own
RUN useradd --create-home --shell /bin/bash shorashim
USER shorashim
WORKDIR /home/shorashim
# Copy the release
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
ENV L1_MOUNT_POINT=/mnt/torah
# Manna provision file location
ENV MANNA_PROVISION_FILE=/var/lib/shorashim/manna/today.json
# PostgreSQL connection for L3
# Set DATABASE_URL in production deployment
# ENV DATABASE_URL=
# Health check port
EXPOSE 4000
CMD ["./app/bin/vav_pipeline", "start"]
+27
View File
@@ -0,0 +1,27 @@
# Shorashim ConfigMap — non-secret configuration
# Construction spec §4.4: Tuning constants
apiVersion: v1
kind: ConfigMap
metadata:
name: shorashim-config
namespace: shorashim
data:
# L1 mount point — read-only Torah filesystem
L1_MOUNT_POINT: "/mnt/torah"
# Manna provision file location
MANNA_PROVISION_FILE: "/var/lib/shorashim/manna/today.json"
# Talmudic Engine socket
TALMUDIC_SOCKET_PATH: "/tmp/shorashim/talmudic.sock"
# Shabbat location — Zurich (Construction spec §4.4)
SHABBAT_LATITUDE: "47.3769"
SHABBAT_LONGITUDE: "8.5417"
SHABBAT_TIMEZONE_OFFSET: "1"
# Cycle boundary check interval (ms)
CYCLE_BOUNDARY_CHECK_INTERVAL_MS: "60000"
# Pipeline latency budget (ms) — Construction spec §2.5
PIPELINE_LATENCY_BUDGET_MS: "5000"
+153
View File
@@ -0,0 +1,153 @@
# Shorashim Deployment — the mishkan
#
# 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.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: shorashim
namespace: shorashim
labels:
app.kubernetes.io/name: shorashim
app.kubernetes.io/version: "0.1.0"
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: shorashim
template:
metadata:
labels:
app.kubernetes.io/name: shorashim
spec:
# --- VOLUMES ---
volumes:
- name: l1-torah
persistentVolumeClaim:
claimName: l1-torah-pvc
readOnly: true
- name: manna
persistentVolumeClaim:
claimName: manna-pvc
- name: talmudic-socket
emptyDir: {}
- name: tmp-shorashim
emptyDir: {}
# --- INIT CONTAINER: Run L3 migrations ---
initContainers:
- name: migrate
image: shorashim/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
ports:
- containerPort: 4000
name: http
envFrom:
- configMapRef:
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
mountPath: /tmp/shorashim
- name: tmp-shorashim
mountPath: /tmp
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /kodesh/health
port: 4000
initialDelaySeconds: 30
periodSeconds: 60
readinessProbe:
httpGet:
path: /kodesh/health
port: 4000
initialDelaySeconds: 10
periodSeconds: 10
# === SHORESH ENGINE (sidecar) ===
- name: shoresh-engine
image: shorashim/shoresh-engine:latest
volumeMounts:
- name: l1-torah
mountPath: /mnt/torah
readOnly: true
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
# === TALMUDIC ENGINE (sidecar) ===
- name: talmudic-engine
image: shorashim/talmudic-engine:latest
volumeMounts:
- name: l1-torah
mountPath: /mnt/torah
readOnly: true
- name: talmudic-socket
mountPath: /tmp/shorashim
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
# === KORBAN PROCESSOR (sidecar) ===
- name: korban-processor
image: shorashim/korban-processor:latest
volumeMounts:
- name: l1-torah
mountPath: /mnt/torah
readOnly: true
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
+43
View File
@@ -0,0 +1,43 @@
# L1 Torah Filesystem — Read-Only Volume
# Construction spec §1.2: SHA-256 verified, mounted read-only
#
# In production, L1 is a read-only filesystem (squashfs or similar)
# containing the Torah text. It is mounted into all pods that need it.
#
# For Exoscale SKS, this uses a PersistentVolume backed by
# Exoscale Block Storage. The L1 data is loaded once and never modified.
#
# Step 34: Mount L1 filesystem read-only
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: l1-torah-pv
labels:
app.kubernetes.io/name: l1-torah
spec:
capacity:
storage: 1Gi
accessModes:
- ReadOnlyMany
persistentVolumeReclaimPolicy: Retain
# For initial setup, use hostPath. In production, replace with
# Exoscale Block Storage CSI or pre-loaded ConfigMap/Secret.
hostPath:
path: /mnt/torah
type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: l1-torah-pvc
namespace: shorashim
spec:
accessModes:
- ReadOnlyMany
resources:
requests:
storage: 1Gi
selector:
matchLabels:
app.kubernetes.io/name: l1-torah
+16
View File
@@ -0,0 +1,16 @@
# Manna Provision Volume
# The kohen/treasurer writes today.json to this volume.
# The vav_pipeline reads it. Provision is external to the system.
# Shemot 16:4 — d'var yom b'yomo.
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: manna-pvc
namespace: shorashim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
+7
View File
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: shorashim
labels:
app.kubernetes.io/name: shorashim
app.kubernetes.io/part-of: shorashim
+17
View File
@@ -0,0 +1,17 @@
# Shorashim Secrets — template only
# NEVER commit actual secret values to git.
# Apply with: kubectl apply -f - after filling in values.
#
# The DATABASE_URL connects to Exoscale PostgreSQL (temple-council-db)
# in ch-gva-2 zone. Retrieve credentials from:
# exo dbaas show temple-council-db --zone ch-gva-2
apiVersion: v1
kind: Secret
metadata:
name: shorashim-secrets
namespace: shorashim
type: Opaque
stringData:
# PostgreSQL connection for L3 Oral Tradition
# Format: ecto://user:password@host:port/database?sslmode=require
DATABASE_URL: "REPLACE_WITH_ACTUAL_DATABASE_URL"
+48
View File
@@ -0,0 +1,48 @@
# Shorashim Services
# Operations spec §1.1: Four access tiers
# - Pe'ah (public, no auth)
# - Machaneh Leviyah (authenticated)
# - Chatzer (full access)
# - Kodesh (operator, mTLS)
#
# All tiers go through a single Service → vav-pipeline port 4000
---
apiVersion: v1
kind: Service
metadata:
name: shorashim
namespace: shorashim
labels:
app.kubernetes.io/name: shorashim
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: shorashim
ports:
- port: 80
targetPort: 4000
protocol: TCP
name: http
---
# External access via LoadBalancer
# For Exoscale SKS, this provisions an Exoscale NLB
apiVersion: v1
kind: Service
metadata:
name: shorashim-external
namespace: shorashim
labels:
app.kubernetes.io/name: shorashim
annotations:
# Exoscale NLB annotations
service.beta.kubernetes.io/exoscale-loadbalancer-zone: "ch-gva-2"
service.beta.kubernetes.io/exoscale-loadbalancer-name: "shorashim"
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: shorashim
ports:
- port: 80
targetPort: 4000
protocol: TCP
name: http