# SPDX-License-Identifier: Apache-2.0
# Rosie Operator Console — Docker runtime (mirrors a11oy winning pattern).
# HF Spaces sdk: docker runs this CMD, which executes our uvicorn __main__ block,
# serving BOTH the 11-tab Gradio UI (root) AND the mirrored /v1/* FastAPI contract
# (root + /api/rosie + /api/a11oy) on a single port. Under sdk: gradio, HF would
# auto-launch only `demo` and drop the FastAPI POST/DELETE routes — root cause of
# the 405s. Docker hands control to app.py so the full hybrid app is served.
FROM python:3.12-slim

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PORT=7860 \
    HOME=/home/user \
    GRADIO_SERVER_NAME=0.0.0.0 \
    GRADIO_SERVER_PORT=7860

# HF Spaces best-practice: run as a non-root user (uid 1000).
RUN useradd -m -u 1000 user
WORKDIR /home/user/app

COPY --chown=user requirements.txt ./
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir -r requirements.txt

COPY --chown=user app.py rosie_v2_additions.py ./
# ADDITIVE (Doctrine v10/v11): shared agentic-RAG service (organ=all; rosie inherits everything).
COPY --chown=user szl_rag.py ./
# H-backplane (ADDITIVE, Doctrine v10/v11): lean-kernel proxy + /lean page.
COPY --chown=user lean_wire.py ./
# Anatomy substrate (ADDITIVE): portable formulas+composer + Gradio tabs module.
COPY --chown=user szl_formulas.py rosie_anatomy_tabs.py ./

USER user
EXPOSE 7860

# Executes the uvicorn __main__ block in app.py -> serves Gradio UI + FastAPI /v1/*.
COPY --chown=user szl_brain.py szl_wire.py szl_jack.py szl_formulas.py ./
# ADDITIVE (Yachay / Provenance Hardening): Wire D + DSSE/Cosign real-signing modules.
# Explicit per-file COPY (this Dockerfile never uses `COPY . .`), else the modules
# never enter the image and szl_provenance import fails at boot.
COPY --chown=user szl_dsse.py szl_provenance.py ./
COPY --chown=user rosie_brain_tab.py rosie_dinn_tab.py rosie_moat_tabs.py rosie_upgrades_tab.py ./
COPY --chown=user thesis_corpus_171.csv ./
COPY --chown=user OUROBOROS_RUN_ALL.py run_all_json.py cursor_reinstill.json lean_wire.py ./
# ADDITIVE (Live 3D Wires / PURIQ Doctrine v12, Yachay): explicit per-file COPY.
# rosie Dockerfile never uses `COPY . .`; without these the `import szl_live_wires`
# in app.py raises ModuleNotFoundError and /live-wires 404s under the Gradio mount.
COPY --chown=user szl_live_wires.py live_wires.html live_wires_3d.js ./
# ADDITIVE (Rosie v3.0.0 Operator Console, Yachay / Perplexity Computer Agent):
# explicit per-file COPY (this Dockerfile never uses `COPY . .`). Without these
# `import rosie_v3` raises ModuleNotFoundError and every /api/rosie/v2/* 404s.
# ./data is created at runtime for the persisted sqlite chain + ECDSA signing key.
COPY --chown=user rosie_v3.py console.html .rosie_build_sha ./
# Persisted chain + signing key live under the user-owned home (uid 1000 owns
# /home/user via `useradd -m`). rosie_v3 creates ROSIE_DATA_DIR at runtime.
ENV ROSIE_DATA_DIR=/home/user/data
# ── UNAY + Khipu-LMDB v2 organs (ADDITIVE, Yachay / Perplexity Computer Agent).
# Explicit per-file COPY (this Dockerfile never uses `COPY . .`). Without these
# `import szl_unay_routes` raises ModuleNotFoundError and every /api/rosie/v2/unay
# + /api/rosie/v2/khipu/lmdb path 404s. Real sqlite-vss + real lmdb.
COPY --chown=user szl_unay.py szl_khipu_lmdb.py szl_khipu_replicate.py szl_unay_routes.py ./
# ADDITIVE (UNAY persistence proof, Yachay): committed LMDB snapshot restored at
# boot by szl_unay_routes._restore_snapshot — survives rebuilds via git object store
# (this Space has no persistent disk; the repo IS the durable layer).
COPY --chown=user _unay_snapshot/ ./_unay_snapshot/
# ADDITIVE (Warhacker aliases, Yachay 2026-06-01): /khipu/* + /api/rosie/v3/doctrine + /wires/D.
COPY --chown=user szl_warhacker_aliases.py ./szl_warhacker_aliases.py
# ADDITIVE (Understudy Parity, Yachay / Perplexity Computer Agent 2026-06-01):
# Rosie as a11oy's failover understudy — full LLM router / agentic RAG / MCP /
# PURIQ organs / 23 formulas / AYNI / WAYRA / understudy-promote under
# /api/rosie/v2/*. Explicit per-file COPY (this Dockerfile never uses `COPY . .`);
# without it `import szl_understudy` raises ModuleNotFoundError and every
# /api/rosie/v2 understudy path 404s. Imports szl_dsse/szl_brain/szl_rag/
# szl_formulas already COPYd above; honest 503 fallback if any are absent.
COPY --chown=user szl_understudy.py ./szl_understudy.py
# ADDITIVE (Sentra mesh immune filter, Yachay / Perplexity Computer Agent 2026-06-01):
# Rosie routes every command payload through Sentra's /sentra/rosie/filter before
# dispatch. Explicit per-file COPY (this Dockerfile never uses `COPY . .`); without
# it `import szl_sentra_client` raises ModuleNotFoundError and the dispatcher's
# immune hook fails open silently. httpx already in requirements.txt.
COPY --chown=user szl_sentra_client.py ./szl_sentra_client.py
CMD ["python", "app.py"]
