# Spec 002: Contract

## Wave 1 Acceptance Criteria

### Deliverables
- [ ] `templates/root/databricks.yml.j2` — declares `pipeline_target_schema` and `schema` variables with `"default"` defaults
- [ ] `templates/lakehouse/resources/jobs/data_generation_job.yml.j2` — single `setup_catalog` task only (no fake notebook references)
- [ ] `templates/lakehouse/resources/jobs/ml_training_job.yml.j2` — tasks commented out, no `${var.schema}` references
- [ ] `templates/lakehouse/resources/pipelines/main_pipeline.yml.j2` — has `target: ${var.pipeline_target_schema}`
- [ ] `templates/root/pyproject.toml.j2` — has `[tool.hatch.build.targets.wheel]` + ruff Databricks ignores
- [ ] `templates/root/requirements.txt.j2` — new file with universal deps
- [ ] `core/scaffold.py` — no `_STATIC_FILES`, no `_copy_static_files_from()`, `INDUSTRY_DISPLAY_NAMES` dict, fixed `display_name`, new stub dirs
- [ ] `templates/static/` directory deleted entirely (3 dashboard stubs removed)
- [ ] Updated tests: `test_template_rendering.py`, `test_scaffold.py`, `test_integration.py`

### Quality Gate
```bash
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/exokit/
uv run pytest tests/ -v --cov=src/exokit --cov-report=term-missing
# Coverage >= 80%
```

### Success Criteria
- Rendered `databricks.yml` YAML has `pipeline_target_schema` and `schema` in `variables:`
- Rendered data_generation_job has exactly 1 task: `setup_catalog`
- Rendered ml_training_job parses as valid YAML with no `${var.schema}`
- Rendered pipeline YAML has `target:` key
- Rendered pyproject.toml has `[tool.hatch.build.targets.wheel]`
- No `_STATIC_FILES` or `_copy_static_files_from` in scaffold.py
- `INDUSTRY_DISPLAY_NAMES` maps "fsi" → "Financial Services"
- When `company=""` and `industry="fsi"`, no rendered file contains "FSI FSI"
- `.claude/agent-memory/{lakehouse-dev,app-dev,dashboard-dev,reviewer}` dirs created by scaffold
- `resources/dashboards/` dir created by scaffold

---

## Wave 2 Acceptance Criteria

### Deliverables
- [ ] `templates/lakehouse/src/data_generation/setup_catalog.py.j2` — Databricks notebook format, creates catalog + default schema + volumes
- [ ] `templates/lakehouse/src/data_generation/CLAUDE.md.j2` — data gen patterns and pitfalls
- [ ] `templates/lakehouse/src/pipelines/CLAUDE.md.j2` — DLT patterns and pitfalls
- [ ] `templates/lakehouse/src/ml/CLAUDE.md.j2` — ML patterns (Decimal casting, feature discovery)
- [ ] `templates/scripts/deploy-all.sh.j2` — orchestrator calling lakehouse + app deploy
- [ ] `templates/scripts/deploy-lakehouse.sh.j2` — full lifecycle: deploy → data gen → pipeline → ML
- [ ] `templates/scripts/deploy-app.sh.j2` — build → deploy → SP permissions
- [ ] `templates/docs/TALK_TRACK.md.j2` — stub with structure
- [ ] `templates/scripts/deploy.sh.j2` — redirects to `deploy-lakehouse.sh` (backward compat)
- [ ] `templates/root/.env.example.j2` — consolidated vars for all deploy scripts
- [ ] `templates/root/CLAUDE.md.j2` — updated with new file references, fixed naming
- [ ] `templates/docs/LESSONS_LEARNED.md.j2` — pre-populated with universal gotchas
- [ ] Updated tests for all 9 new templates

### Quality Gate
```bash
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/exokit/
uv run pytest tests/ -v --cov=src/exokit --cov-report=term-missing
# All new templates render without Jinja2 errors
# Python templates (setup_catalog.py) compile successfully
# Shell script templates start with #!/usr/bin/env bash
```

### Success Criteria
- `setup_catalog.py.j2` renders as syntactically valid Python containing `CREATE CATALOG`
- 3 directory CLAUDE.md files exist after scaffold at `src/data_generation/CLAUDE.md`, `src/pipelines/CLAUDE.md`, `src/ml/CLAUDE.md`
- `deploy-all.sh` references both `deploy-lakehouse.sh` and `deploy-app.sh`
- `deploy-lakehouse.sh` references `bundle_name` job names
- `deploy-app.sh` references `app_name` and SP permissions flow
- `.env.example` contains `DATABRICKS_CONFIG_PROFILE`, `CATALOG`, `APP_NAME`, `DATABRICKS_SQL_WAREHOUSE_ID`
- `LESSONS_LEARNED.md` pre-populated with ≥5 known gotchas
- Root `CLAUDE.md` references directory CLAUDE.md files and new deploy scripts
- Test count increases by ≥20

---

## Wave 3 Acceptance Criteria

### Deliverables
- [ ] `core/apx_bridge.py` — overlay fails fast if `src/{slug}/backend/` doesn't exist (no silent fallback)
- [ ] `core/apx_bridge.py` — `_postprocess_apx_config()` removes `database_instances`, aligns profile/host/warehouse
- [ ] `core/apx_bridge.py` — `_install_shadcn_components()` pre-installs common shadcn/ui components (graceful failure)
- [ ] `core/apx_bridge.py` — `_postprocess_app_env()` ensures app .env has warehouse/catalog/profile vars
- [ ] `core/apx_bridge.py` — `_write_app_readme()` replaces APX's default README with setup instructions
- [ ] `core/apx_bridge.py` — enhanced `_APP_CLAUDE_MD` with SP vs OBO, SQL warehouse, shadcn/ui guidance
- [ ] `templates/claude/commands/build-next.md.j2` — Step 0.6: Apply Plan to Placeholders
- [ ] `templates/claude/commands/deploy.md.j2` — references new deploy scripts
- [ ] `templates/scripts/validate.sh.j2` — enhanced with bundle validate + structure checks
- [ ] `templates/docs/IMPLEMENTATION_PLAN.md.j2` — marked as "replaced by /build-next"
- [ ] Updated tests: `test_apx_bridge.py`, `test_template_rendering.py`

### Quality Gate
```bash
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/exokit/
uv run pytest tests/ -v --cov=src/exokit --cov-report=term-missing
# Coverage >= 80% for apx_bridge module
```

### Success Criteria
- When APX creates `src/{slug}/backend/`, overlay dirs go there — never at app root
- When APX doesn't create backend dir, `APXScaffoldError` is raised
- APX-generated `databricks.yml` has no `database_instances` after post-processing
- APX-generated `databricks.yml` has correct profile/host/warehouse from scaffold context
- App README contains .env setup, local dev, and deploy instructions
- `build-next.md` contains "Step 0.6" between Phase 0 approval and Phase 1
- `deploy.md` references `deploy-all.sh`, `deploy-lakehouse.sh`, `deploy-app.sh`
- `validate.sh` checks `databricks bundle validate` and file existence

---

## Wave 4 Acceptance Criteria

### Deliverables
- [ ] `tests/test_integration.py` — `TestBundleValidateReady`: all `${var.X}` in YAMLs declared in databricks.yml
- [ ] `tests/test_integration.py` — `TestDisplayNameNoDuplication`: no "FSI FSI" in any rendered file
- [ ] `tests/test_integration.py` — `TestDirectoryStructureComplete`: all expected dirs and files exist
- [ ] `docs/PROGRESS.md` — Spec 002 status recorded
- [ ] `whiteboard.md` — Decisions captured (hello-world exit criteria, deploy script split, display_name fix, APX post-processing)

### Quality Gate
```bash
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/exokit/
uv run pytest tests/ -v --cov=src/exokit --cov-report=term-missing
# Coverage >= 80% overall
# Zero "FSI FSI" in any rendered template output
```

### Success Criteria
- Full test suite passes
- Generate a test scaffold: grep for "FSI FSI" finds zero matches
- Generated project has: `requirements.txt`, `src/data_generation/setup_catalog.py`, 3 directory CLAUDE.md files, `scripts/deploy-all.sh`, `scripts/deploy-lakehouse.sh`, `scripts/deploy-app.sh`
- All YAML structurally valid (no undeclared vars, no missing fields)
- Generator's own quality gates pass (ruff, mypy, pytest ≥ 80% coverage)
