ifrs9-ecl-copilot / Dockerfile
Preetomsorkar's picture
Dockerfile: restore freddie/mdd COPY lines (context now includes them)
5210d23 verified
Raw
History Blame Contribute Delete
6.46 kB
# IFRS 9 ECL Copilot β€” single-container deploy (HF Spaces Docker SDK, port 7860).
#
# Stage 1 builds the Preact/ECharts SPA; stage 2 is a python:3.13-slim runtime
# installing the EXACT locked versions via requirements.docker.txt, generated
# from uv.lock with:
#
# uv export --no-dev --no-hashes --no-emit-project --prune torch \
# -o requirements.docker.txt
#
# torch is pruned deliberately: it is used only by the offline challenger
# study (challenger/, not shipped); no runtime module imports it, and its
# CUDA payload would add ~5 GB to the image.
#
# NOTE (2026-07-19): a Space build hit a persistent LFS/context-resolution
# race on outputs/freddie and outputs/mdd right after those directories'
# first upload ("failed to calculate checksum ... not found" despite the LFS
# objects resolving fine over HTTP, and list_repo_files confirming every file
# present at the failing commit SHA) β€” same class of issue as the prior
# "queue wedge" fix, but more persistent: it survived plain restart_space(),
# a content-change re-push, and even restart_space(factory_reboot=True).
# See outputs/gate/mdd_freddie_gate.md for the full retry timeline and the
# eventual resolution (longer wall-clock wait for backend propagation, not
# more aggressive cache-busting).
#
# SECURITY: no .env, no data/raw, no secrets are ever baked into the image
# (.dockerignore enforces this; the CI check greps the saved image for key
# prefixes). OPENROUTER_API_KEY is injected at RUN time:
# docker run -e OPENROUTER_API_KEY -p 7860:7860 ifrs9-ecl-copilot
# Without a key the app still serves β€” the deterministic fallback router
# answers offline and refuses out-of-scope questions (a demoed feature).
# ---------------------------------------------------------------- stage 1: UI
FROM node:22-alpine AS ui
WORKDIR /build
COPY app/ui/package.json app/ui/package-lock.json ./
RUN npm ci --no-audit --no-fund
COPY app/ui/index.html app/ui/vite.config.js ./
COPY app/ui/src ./src
COPY app/ui/scripts ./scripts
RUN npm run build
# ----------------------------------------------------------- stage 2: runtime
FROM python:3.13-slim AS runtime
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_CACHE_DIR=1
WORKDIR /app
# locked third-party deps first (best layer-cache behaviour)
COPY requirements.docker.txt ./
RUN pip install --no-cache-dir -r requirements.docker.txt
# HF Spaces convention: run as non-root uid 1000
RUN useradd -m -u 1000 appuser
# runtime code β€” engine/{hazard,lgd,ead,staging,ecl}.py are the FROZEN five
COPY engine ./engine
COPY agent ./agent
COPY app/__init__.py ./app/__init__.py
COPY app/api ./app/api
COPY analysis ./analysis
# Tier-3 (query_model_docs) retrieval sources: the model-development wiki
# (pages + the pre-built typed graph) and the indexed IFRS9 credit-risk
# notes corpus β€” both read-only at runtime, no LLM/network involved.
COPY wiki ./wiki
COPY knowledge/corpus ./knowledge/corpus
COPY knowledge/index ./knowledge/index
# the two retrieval scripts agent/tier3_retrieval.py loads by file path
# (importlib.util.spec_from_file_location, never copy-pasted) β€” same
# relative paths as in the repo; wiki_query.py needs wiki_graph.py
# alongside it (sys.path sibling import)
COPY .claude/skills/llm-wiki/scripts/wiki_query.py .claude/skills/llm-wiki/scripts/wiki_graph.py ./.claude/skills/llm-wiki/scripts/
COPY .claude/skills/pageindex-plus/scripts/pageindex_query.py ./.claude/skills/pageindex-plus/scripts/
# runtime data: the loan panel, the DFAST scenario CSVs and their loader
COPY data/__init__.py ./data/__init__.py
COPY data/ingest ./data/ingest
COPY data/processed/panel.parquet ./data/processed/panel.parquet
COPY data/scenarios/*.csv ./data/scenarios/
# pre-fitted model cache (joblib warm start ~9s; a fingerprint mismatch β€”
# e.g. fresh file mtimes on HF Spaces β€” triggers a one-off ~50s refit in the
# FastAPI lifespan, after which every tool call answers in seconds)
COPY outputs/models ./outputs/models
# App v2 consultant exhibits: the /api/model/*, /api/policy/* and
# /api/exhibits/* endpoints parse these markdown reports and serve these
# PNGs (StaticFiles mount over the whole of outputs/) for the Executive
# Overview / The Model / Policy tabs. Also includes the scenario_ecl and
# vasicek CSVs the tools/exhibits read (z_path.csv, scenario_ecl_summary.csv
# etc). Read-only reference material, no code executes from here.
COPY outputs/variable_dictionary.md ./outputs/variable_dictionary.md
COPY outputs/hazard ./outputs/hazard
COPY outputs/lgd ./outputs/lgd
COPY outputs/staging ./outputs/staging
COPY outputs/eda ./outputs/eda
COPY outputs/vasicek ./outputs/vasicek
COPY outputs/scenario_ecl ./outputs/scenario_ecl
COPY outputs/challenger ./outputs/challenger
# Rung 3 (SFLLD real-data study) + the compiled Model Development Document:
# the /api/freddie/* endpoints parse outputs/freddie/**'s reports/CSVs/JSON
# and StaticFiles mounts serve outputs/freddie/** (Freddie tab exhibits) and
# outputs/mdd/** (the MDD.html + assets) β€” same read-only pattern as above.
#
# TEMPORARILY DISABLED (2026-07-19): 9 consecutive Space build attempts
# (plain restarts, factory_reboot, content-change repush, atomic delete+
# re-add) all failed identically on these two COPY lines alone β€” "failed to
# calculate checksum ... not found" β€” despite outputs/freddie|mdd verifiably
# present and their LFS objects resolving fine over HTTP at every attempted
# commit (see outputs/gate/mdd_freddie_gate.md for the full timeline). Every
# other COPY in this file, including long-standing ones, succeeded every
# time. Commenting these two out restores the Space to RUNNING (the guarded
# `if FREDDIE_DIR.exists()` / `if MDD_DIR.exists()` mounts in app/api/main.py
# mean the app boots fine without them; only the Real Data tab's own calls
# would 404/500 until this is re-enabled). Both directories are already
# pushed to the Space's git repo (`outputs/freddie/`, `outputs/mdd/`) β€”
# re-enable these two lines once the platform-side build issue clears.
COPY outputs/freddie ./outputs/freddie
COPY outputs/mdd ./outputs/mdd
# the built SPA (served by FastAPI at /)
COPY --from=ui /build/dist ./app/ui/dist
# outputs/ must be writable: agent audit trail + possible cache refresh
RUN mkdir -p outputs/agent_log && chown -R appuser:appuser /app/outputs
USER appuser
EXPOSE 7860
CMD ["uvicorn", "app.api.main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]