Files
inter-hub/workplans/IHUB-WP-0016-build-infrastructure-and-error-loop.md
Bernd Worsch a6baab7080 feat(WP-0016): build infrastructure — ghcid standalone script and error-fix loop workplan
- scripts/compile-check: runs ghcid in isolation (no postgres/tailwind) for fast
  incremental compilation feedback; writes errors to /tmp/ihub-compile-errors.txt
- .ghci: add -fkeep-going so GHC reports all module errors in one pass
- WP-0016 workplan: documents module dependency layers, error-fix SOP,
  and autonomous ralph-loop approach for iterative error fixing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 09:46:56 +00:00

172 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: IHUB-WP-0016
type: workplan
title: "Build Infrastructure: Incremental Compilation and Autonomous Error-Fix Loop"
domain: inter_hub
repo: inter-hub
status: open
owner: custodian
topic_slug: inter_hub
created: "2026-04-10"
updated: "2026-04-10"
depends_on: []
---
# IHUB-WP-0016 — Build Infrastructure: Incremental Compilation and Autonomous Error-Fix Loop
## Goal
Make GHC compilation fast enough for iterative error fixing without blocking the
machine or requiring user involvement. The first full build is unavoidably slow
(Nix dep download + all 180+ modules), but subsequent rebuilds must be incremental
(seconds per changed file). An autonomous error-fix loop must allow Claude to iterate
on compilation errors independently.
## Background
### Why compilation is slow
IHP compiles the entire project as one GHC executable target containing ~180 Haskell
modules (Generated types + Web.Types + 12 helpers + 59 controllers + 120 views +
FrontController/Routes). GHC compiles modules sequentially (`.ghci` enforces `-j1`
for this constrained host) and caches each module's `.o`/`.hi` files. Once a module
is compiled and its dependencies have not changed, it is NOT recompiled.
**First build**: slow — GHC compiles all 180 modules from scratch, plus Nix fetches
deps. Unavoidable. Expected: 2060 min on constrained hardware.
**Subsequent incremental builds**: fast — only changed modules and their dependents
recompile. A single controller change: ~530 seconds. This is what we rely on.
### Module dependency layers (compilation order, bottom-up)
```
Layer 1 (stable core — compile once, never touch during error loops):
build/Generated/*.hs IHP auto-generated from Schema.sql
Web/Types.hs 500-line controller type definitions
Layer 2 (helpers — only touch if Layer 1 is clean):
Application/Helper/*.hs 12 files
Generated/ (IHP code-gen output, if present)
Layer 3 (working surface — most errors will be here):
Web/Controller/*.hs 59 controllers
Web/View/**/*.hs 120 views
Layer 4 (wiring — fix last):
Web/FrontController.hs
Web/Routes.hs
```
**Rule**: never modify Layer 1 during error-fix loops. Changes to Web/Types.hs or
Generated types invalidate all 59 controllers and 120 views simultaneously.
### Why `devenv up` is overkill for error checking
`devenv up` starts: PostgreSQL, file-change watcher, Tailwind CSS watcher, AND
ghcid. For compilation error fixing we only need ghcid. Running ghcid standalone
skips the database startup, port binding, and service orchestration overhead.
## Tasks
### C1 — Create `scripts/compile-check` script ✓
A shell script at `scripts/compile-check` that runs ghcid in isolation (no postgres, no tailwind):
```bash
#!/usr/bin/env bash
# scripts/compile-check
# Run ghcid standalone for fast compilation feedback.
# Outputs errors to stdout AND to /tmp/ihub-compile-errors.txt for monitoring.
# Does NOT start postgres or tailwind.
#
# Usage:
# scripts/compile-check # interactive, shows errors in terminal
# scripts/compile-check --bg # write to log only (for Claude monitoring)
#
# Pre-requisite: be inside `devenv shell` or have IHP_LIB set.
set -euo pipefail
LOGFILE="${IHUB_COMPILE_LOG:-/tmp/ihub-compile-errors.txt}"
: > "$LOGFILE" # truncate on start
echo "[compile-check] Writing errors to $LOGFILE"
exec ghcid \
--no-title \
--outputfile "$LOGFILE" \
--command "ghci"
```
This relies on `.ghci` (already present) which sets up `-j1` and loads the IHP config.
### C2 — Verify GHC object cache persistence
GHC stores compiled objects in IHP's `.devenv` or a project-local `dist-newstyle/`
equivalent. Verify the cache survives between `devenv up` restarts:
```bash
# After first successful build, check cache location:
find /home/tegwick/inter-hub -name "*.o" -newer Main.hs 2>/dev/null | head -5
```
If the cache is cleared on each `devenv up` restart, add `IHP_BUILD_CACHE` or
configure the Nix build dir to persist. Document the location here.
### C3 — Autonomous error-fix loop (ralph-workplan)
Configure a ralph-workplan loop:
1. `scripts/compile-check --bg` runs ghcid in background, writing to `/tmp/ihub-compile-errors.txt`
2. Monitor tool watches the log file for new error output
3. On error output: read errors → identify failing module → apply fix → ghcid auto-reloads
4. On "All good" output: loop exits, reports clean build
**Loop discipline**:
- Fix errors bottom-up (Layer 1 → Layer 2 → Layer 3 → Layer 4)
- Fix one module at a time; wait for ghcid reload before fixing the next
- Do NOT make speculative changes to stable layers while fixing working-surface errors
- Maximum 3 fix attempts per module before escalating to user
### C4 — Add GHC `-fwrite-interface` and `-keep-going` flags to `.ghci`
```
-- Continue past errors in other modules (report all errors in one pass)
:set -fkeep-going
-- Ensure interface files are written even on partial success
:set -fwrite-interface
```
`-fkeep-going` lets GHC report errors from all modules in one pass rather than
stopping at the first failure — critical for batch error fixing.
### C5 — Document module surface constraints in CLAUDE.md
Add a "Compilation Layers" section to CLAUDE.md noting:
- Never modify Layer 1 during error-fix loops
- Each layer's expected compile time after first build
- Cache location and how to verify it's warm
## Error-Fix Loop SOP (Standard Operating Procedure)
```
1. Ensure devenv shell is active (IHP_LIB must be set)
2. Run: scripts/compile-check --bg
3. Monitor /tmp/ihub-compile-errors.txt
4. Parse errors: group by module, order by Layer (1 → 4)
5. Fix Layer 1 errors first (rare; usually type/import issues in Web/Types.hs)
6. For each failing module in Layer 23:
a. Read current module state
b. Apply targeted fix
c. Wait for ghcid "Reloading..." + result
d. If still failing: re-read error, apply next fix
e. If 3 attempts fail: note module name, move on
7. After Layer 3 clean: fix Layer 4 (FrontController/Routes)
8. "All good (N modules)" in log = build clean
9. Commit fixes, update WP-0014/A1 status
```
## Exit Criteria
- `scripts/compile-check` script exists and runnable inside devenv shell
- `ghcid` produces output to `/tmp/ihub-compile-errors.txt` successfully
- GHC object cache location identified and documented
- ralph-workplan loop configuration in place
- Build reaches "All good" state without user intervention beyond starting the loop