# Build Constraints and Optimization Strategy

**Date:** 2025-11-27
**Critical Context:** This project has severe bandwidth constraints that make build optimization MANDATORY, not optional.

---

## Primary Constraint: Slow Network

**Measured download speed: ~265 kB/s (0.26 MB/s)**

### Impact on Build Times

| Stage | Download Size | Download Time | Total Time | Notes |
|-------|---------------|---------------|------------|-------|
| **stage0** | ~200 MB | 13 min | 18 min | Base Debian system |
| **stage1** | ~450 MB | 29 min | 37 min | Kernel + firmware |
| **stage2** | ~850 MB | 55 min | 65 min | Desktop + network tools |
| **stagePM3** | ~220 MB | 14 min | 59 min | PM3 build (downloads + compile) |
| **stageDangerousPi** | ~140 MB | 9 min | 12 min | Custom packages |
| **TOTAL** | **~1.86 GB** | **~120 min** | **~191 min** | **3+ hours** |

### Critical Implications

1. **Every failed build wastes 3+ hours**
2. **Stage0-2 alone = 2 hours of downloading**
3. **Cannot afford trial-and-error debugging**
4. **Pre-flight validation MUST be perfect**
5. **Incremental builds are MANDATORY for iteration**

---

## Build Optimization Strategy

### 1. QCOW2 Caching (MANDATORY)

```bash
# In pi-gen/config
USE_QCOW2=1  # NEVER disable this
```

**Why:** Enables copy-on-write snapshots. After stage2 completes once (2 hours), we can rebuild from that point in ~70 minutes instead of 3+ hours.

**Cache Location:** `/home/work/pi-gen-builder/work/*/stage*.qcow2`

### 2. Three-Tier Build Strategy

```bash
# Full build: Clean slate (3+ hours)
./build-image.sh full

# From PM3: Rebuild PM3 + customizations (70 min)
./build-image.sh from-pm3

# From DangerousPi: Rebuild only customizations (5 min)
./build-image.sh from-dtpi
```

**Daily workflow:**
- First build: `full` (one-time 3hr investment)
- Iterating on PM3 changes: `from-pm3` (70 min)
- Iterating on app/WiFi/config: `from-dtpi` (5 min)

### 3. Container vs Volume Management

**CRITICAL DISTINCTION:**
- **Container** (`docker rm pigen_work`): Safe to remove, just metadata
- **Volume** (`docker rm -v pigen_work`): ❌ NEVER DO THIS - nukes 2hr download cache

**Build script behavior:**
- `full` mode: Removes container AND volume (fresh start)
- `from-pm3` mode: Preserves cache, removes container
- `from-dtpi` mode: Preserves cache, removes container

---

## Pre-Flight Validation Requirements

### Philosophy

> **"Fail fast, fail loud, fail BEFORE downloading anything"**

With 3+ hour builds, we CANNOT afford to discover errors after stage0-2 completes.

### Current Checks (52 total)

✅ Pi-gen directory exists
✅ Docker available and accessible
✅ qemu-aarch64 registration
✅ Config file validation
✅ Stage structure (prerun.sh, EXPORT_IMAGE, substages)
✅ Build script syntax validation
✅ Dependency analysis (header → package mapping)
✅ Source file availability
✅ Build script validation

### Required Additions

The following checks MUST be added to prevent wasted builds:

#### A. Pre-Download Validation
- [ ] **Disk space check:** Require 15GB free before starting
- [ ] **Network connectivity:** Verify can reach deb.debian.org
- [ ] **Git repo accessibility:** Test clone URLs without cloning
- [ ] **Stage size estimation:** Warn if total download > threshold

#### B. Deep Script Analysis
- [ ] **File reference validation:** Grep for all file paths in scripts, verify they exist
- [ ] **Service file syntax:** Validate systemd .service files
- [ ] **Environment variables:** Check for undefined vars in scripts
- [ ] **Path existence:** Verify all mkdir -p targets don't conflict
- [ ] **Port conflicts:** Check for duplicate port assignments

#### C. Configuration Validation
- [ ] **STAGE_LIST ordering:** Ensure stages are in dependency order
- [ ] **EXPORT_IMAGE syntax:** Validate all EXPORT_IMAGE files
- [ ] **Duplicate substages:** Check for numbering conflicts (e.g., two 00-run.sh in same stage)
- [ ] **Username consistency:** Verify same user referenced across stages

#### D. Build Artifact Validation
- [ ] **Post-stage verification:** After each stage, check expected files exist
- [ ] **Binary executability:** Test compiled binaries actually run
- [ ] **Python import test:** Verify Python modules can be imported
- [ ] **Service enable test:** Verify systemd services are enabled

---

## Development Workflow Optimizations

### 1. Test Changes Locally First

Before modifying stage scripts, test commands locally:

```bash
# Test PM3 dependency installation
docker run --rm -it debian:trixie bash
> apt-get update && apt-get install -y gcc-arm-none-eabi
> which arm-none-eabi-gcc

# Test Python package installation
docker run --rm -it debian:trixie bash
> apt-get update && apt-get install -y python3-pip
> pip3 install --break-system-packages fastapi==0.115.0
```

**Saves:** Hours of build time by catching errors early

### 2. Use Build Log Analysis

During builds, monitor for early warning signs:

```bash
# Watch for errors in real-time
docker logs -f pigen_work 2>&1 | grep -i "error\|fail\|fatal"

# Check what stage we're on
./scripts/build-status.sh

# Estimate completion based on download speed
docker logs pigen_work 2>&1 | grep "Fetched.*in.*(" | tail -5
```

### 3. Parallel Development

While a build runs, prepare next iteration:

```bash
# Terminal 1: Build running
./build-image.sh full

# Terminal 2: Test next changes
cd /tmp/test-changes
# Test scripts, validate syntax, etc.
```

---

## Failure Recovery Procedures

### If Build Fails During stagePM3 or Later

**DO NOT KILL CONTAINER**

1. Let it fail completely
2. Check what stage completed:
   ```bash
   ls -la /home/work/pi-gen-builder/work/*/stage*.qcow2
   ```
3. If stage2.qcow2 exists, you have cache:
   ```bash
   ./build-image.sh from-pm3
   ```

### If Build Fails During stage0-2

**Only kill if you know stage will fail:**

```bash
# Check if we have partial cache
ls -la /home/work/pi-gen-builder/work/*/stage*.qcow2

# If no .qcow2 files, killing wastes nothing
# If stage1.qcow2 exists, let it finish stage2
```

---

## Cost-Benefit Analysis

### Why Pre-Flight Validation Matters

**Without perfect validation:**
- Change PM3 script
- Start 3hr build
- Discover typo at hour 2.5
- Fix typo
- Restart 3hr build
- **Total time wasted: 6 hours**

**With perfect validation:**
- Change PM3 script
- Run pre-flight (30 seconds)
- Catch typo immediately
- Fix typo
- Run pre-flight again (30 seconds)
- Start build with confidence
- **Total time wasted: 60 seconds**

**ROI: 360x time savings**

---

## Questions for Future Optimization

1. **Network caching:** Should we set up apt-cacher-ng to cache Debian packages locally?
   - Pro: Rebuilds wouldn't re-download same packages
   - Con: Setup complexity, disk space (20GB+)

2. **Disk space monitoring:** Add alerts when cache disk < 10GB free?

3. **Build checkpointing:** Should we export stage2.qcow2 as a baseline artifact?

4. **Parallel builds:** Can we test multiple variants simultaneously?

5. **Common errors database:** Should we maintain a list of known failure patterns to check for?

---

## Action Items

### Immediate (Before Next Build)
- [ ] Add disk space check to pre-flight
- [ ] Add network connectivity check to pre-flight
- [ ] Document common failure patterns we've seen
- [ ] Test local command validation workflow

### Short-term (This Week)
- [ ] Add deep script validation (file references, env vars)
- [ ] Create build artifact verification
- [ ] Set up build time estimation based on network speed
- [ ] Document recovery procedures for each failure type

### Long-term (Future Optimization)
- [ ] Consider apt-cacher-ng for package caching
- [ ] Automated build artifact testing
- [ ] Build time alerting/monitoring
- [ ] Stage baseline export/import

---

## Key Takeaway

> **Every validation check we add to pre-flight saves potentially 3+ hours of wasted build time.**
>
> **Spending 5 minutes improving pre-flight can save hours of debugging.**
>
> **This is not premature optimization - it's mandatory survival strategy.**
