Fixing Recurring CI Build Failures in v0.3.2
Fixing Recurring CI Build Failures in v0.3.2
Release v0.3.2 resolves a pattern of unrecoverable CI build failures that were blocking the implementation agent. This post explains what was wrong, what changed, and what it means for future development.
Background
The implementation agent was failing CI builds repeatedly under fingerprint 86718f75f6704c7e with a generic CI checks failed: build error. Because the errors were unclassified, the agent could not self-correct — it was producing TypeScript that didn't compile and had no accurate reference to recover from.
Root cause analysis identified two independent problems:
- ARCHITECTURE.md was inaccurate — it referenced Stripe instead of Calmony Pay, lacked exact import paths and type signatures, and had no documentation of common TypeScript pitfalls specific to this stack.
- CI was missing environment variables — external service env vars (
BLINC_UK_API_KEY,BLINC_UK_API_URL,SIGNABLE_API_KEY,SIGNABLE_API_URL,NEXT_PUBLIC_SAAS_FACTORY_URL) were absent fromci.yml, which can cause build-time failures when Next.js statically evaluates modules that referenceprocess.env.
What Changed
1. ARCHITECTURE.md Rewrite
The architecture document is now written with AI implementation agents as the primary audience. Every section is optimised for accuracy and copy-paste correctness.
Tech stack corrections:
- Billing: Calmony Pay (not Stripe). Client lives at
src/lib/calmony-pay/. - Zod: v3.23+ resolving to Zod 4. This matters because Zod 4 changed the
z.record()signature. - Auth: Auth.js v5 beta.30 via OIDC (SF Auth), not Clerk.
Exact import paths are now documented for every major module:
// Database
import { db } from "@/db";
import { tableName } from "@/db/schema";
// tRPC procedures
import { router, orgProcedure, adminProcedure } from "@/lib/trpc/trpc";
// Utilities
import { logProductAudit } from "@/lib/product-audit";
import { captureError } from "@/lib/capture-error";
import { paginationInput, paginatedResult } from "@/lib/pagination";
Complete code patterns are provided for:
- tRPC router (list + create, with audit logging)
- Registering a router in
root.ts - Inngest function with
registerBatch,trackBatchRun, andstep.run - Server page with
force-dynamic - Client component with
trpcanduseOrg
2. Common TypeScript Pitfalls Section
A new section in ARCHITECTURE.md documents seven specific mistakes that cause build failures on this stack.
Zod 4 z.record() syntax is the most common. Zod 4 requires two arguments:
// WRONG (Zod 3 syntax — type error in Zod 4)
z.record(z.unknown())
// RIGHT
z.record(z.string(), z.unknown())
Drizzle chained .where() does not stack conditions — use and() instead:
// WRONG
db.select().from(t).where(eq(t.a, 1)).where(eq(t.b, 2))
// RIGHT
db.select().from(t).where(and(eq(t.a, 1), eq(t.b, 2)))
Missing force-dynamic causes Next.js to statically render pages that depend on auth or DB context:
// Required on every authenticated or DB-reading page
export const dynamic = "force-dynamic";
The remaining pitfalls cover Inngest Jsonify type casts, Drizzle raw SQL with arrays, nullable query results, and shell import rules.
3. CI Environment Variables
Five variables have been added to the env block in .github/workflows/ci.yml with dummy values:
NEXT_PUBLIC_SAAS_FACTORY_URL: "https://dummy.example.com"
BLINC_UK_API_KEY: "dummy-blinc-key-for-ci"
BLINC_UK_API_URL: "https://dummy-blinc.example.com"
SIGNABLE_API_KEY: "dummy-signable-key-for-ci"
SIGNABLE_API_URL: "https://dummy-signable.example.com"
These join the existing dummy values for DATABASE_URL, INNGEST_SIGNING_KEY, SF_AUTH_CLIENT_SECRET, SF_AUTH_ISSUER_URL, and CALMONY_PAY_SECRET_KEY. Dummy values are sufficient for a build — they prevent module-level process.env accesses from returning undefined during static analysis, without requiring real credentials in CI.
4. Middleware Matcher Fix
The Next.js middleware matcher now excludes robots.txt and sitemap.xml. Previously these files were passed through the auth middleware, which could result in them being blocked or redirected incorrectly. Public static files should never be auth-gated.
Impact
Future implementation agent runs will:
- Have an accurate, up-to-date reference for every pattern used in the codebase
- Avoid the seven documented TypeScript pitfalls that previously caused unclassified build errors
- Build successfully in CI even when new code references the Blinc-UK, Signable, or SaaS Factory platform env vars
No production application behaviour changes in this release.