ForgeKitFORGEKIT

Build Log

Build Log Ingest API — All 5 Charge Phases

August 2, 2026

Implemented the full v9-approved Build Log Ingest API design end to end: a shared contract package, forgekit-website's ingest endpoints, Alloy's delivery outbox, a real backfill of all 210 historical sessions, and the database-backed read-path cutover — so a Bank-closed Arc appears on forgekits.build/build-log with zero redeploy.

ForgeKit OSAlloyforgekit-websitePlatformDatabase
5/5
Charge phases completed (Contract Inventory, Shared Package, Website API, Alloy Delivery, Backfill+Cutover)
38
real-DB tests written this session, all passing, zero mocks
210/210
historical sessions backfilled successfully through the fail-closed projector
171
legacy static URLs verified still resolving after cutover
0
content regressions against the 84/78 Council-Review/Crucible-Wrap sessions named in design §2.5

Timeline

Start
Charge written against the v9-approved design
docs/platform/build-log-ingest-api-charge.md — 5 phases, each with acceptance criteria/tests/rollback/evidence
Phase 0
Real field-bound scan across all 210 real session JSONs
forgekit-os/scripts/build-log-phase0-scan.mjs — replaced every design-doc placeholder number with an observed-data-backed limit
Phase 1
packages/forgekit-retro-contract built and tested
Fail-closed projector, canonical content hash, shared Zod schemas — 12 tests, including a test that plants disqualifying markers in every excluded field and asserts none survive
Phase 2
Dedicated Neon project provisioned; ingest API built
5 endpoints (publish/withdraw/restore/status/status-batch), hashed API-key auth, rate limiting — 15 real-DB tests, live-curled end to end, caught a real Turbopack .js-extension bundling bug tsc/vitest both missed
Phase 3
Alloy's outbox pipeline wired into bankArc
12-step crash-safe sequence, publisherRef credential resolution at send time — genuine E2E publish proven against the live ingest API
Phase 4
All 210 sessions backfilled; exception manifest built
First manifest run found 64 false UNEXPECTED entries, all traced to bugs in the comparison script itself (em-dash splitting, HTML-entity decoding) and fixed — final result: 0 real defects, 664 approved differences
Phase 5
Read-path cutover: database-backed index + [slug] route
build-session.mjs no longer writes public static HTML; live-verified a DB insert appears on the running site with zero restart
+
Added the missing Phase 5 regression test on Zeb's explicit request
read.test.ts — proves the Lifecycle Consistency Gate check (withdrawn sessions never surface) and legacy-file preservation as committed test coverage, not just a one-time manual check
Close
Full suite re-verified green, committed as one Charge-scoped commit
9355d07 — 61 files, 5518 insertions

What shipped

packages/forgekit-retro-contract — public-retro.schema.ts, ingest-request/response schemas, project-public-retro.ts (fail-closed projector), content-hash.ts (canonical semantic hash), 12 tests

A dedicated Neon Postgres project for forgekit-website (id shy-thunder-87278705), separate from Alloy's own database per design §14

forgekit-website's ingest API: 6 DB tables (publishers, publisher_api_keys, retro_sessions, retro_session_revisions, retro_ingest_receipts, retro_ingest_security_events), 5 route handlers, hashed API-key auth with a non-reversible credentialFingerprint, rate limiting via forgekit-ai's createRateLimiter

Alloy's retro-publication-outbox.ts — the exact 12-step sequence from design §6, wired into bankArc as an additive step after the existing local retro pipeline

forgekit-os/scripts/build-log-phase0-scan.mjs, backfill-retro-sessions.mjs, backfill-exception-manifest.mjs, verify-no-content-regression.mjs — real, re-runnable migration tooling, not one-off scripts

The database-backed /build-log index (app/build-log/page.tsx, rewritten) and new /build-log/[slug] detail route

Retired build-session.mjs's updateIndex() source-text-splice mechanism and its public static HTML write, keeping only the internal full-chapter HTML generation

forgekit-website/lib/retro-ingest/read.test.ts — the Phase 5 regression test Zeb explicitly asked for after the manual verification pass, proving withdrawn-session exclusion and legacy-file preservation as committed coverage

Fixed a real forgekit-website/.gitignore gap found during commit staging — .env* was blanket-ignoring .env.example too, unlike every other app's .gitignore (which has an explicit !.env.example exception)