Build Log · August 25, 2026

Game Builder's Parent Approval Gate Gets Real Persistence, and Witness Gets Its First Real Test

Replaced Game Builder's file-backed, race-prone parent-approval-gate store with real Neon/Drizzle persistence and a genuinely atomic concurrency fix, while running the ForgeKit Strategic Validation Sprint H2 protocol (Witness at the commitment boundary) for the first time on real, non-OS-diagnostic product work.

  • Game Builder
  • Database
  • Concurrency
  • Witness Experiment
  • Child Safety
real safety-critical race condition fixed
1

real safety-critical race condition fixed

Witness invocation, 1 real CHALLENGE
1

Witness invocation, 1 real CHALLENGE

cheaper-verifier classifications made before any Witness call
5

cheaper-verifier classifications made before any Witness call

control-plane infrastructure built (by design)
0

control-plane infrastructure built (by design)

Timeline

  1. Start

    Charge received: test Witness at the commitment boundary, on real product work outside OS diagnostics

    Two research agents surveyed Forge/Hearth/Leashline/PilotLight/MedinaCHF (excluded)/experiments/civic/Known for real, stated, unshipped work with genuine judgment

  2. ~30m

    Chose Game Builder's approval-gate persistence gap

    Self-documented twice by its own author (store.ts header, docs/parent-approval-gate.md §7): file-backed store won't survive a Vercel deploy, and has a named TOCTOU race

  3. ~1h

    Concurrency-semantics question resolved via RETRIEVAL, not Witness

    Read @neondatabase/serverless's own installed README directly — confirmed neon-http (what forgekit-core's createDb uses) does not support held locks/interactive transactions, ruling out SELECT...FOR UPDATE and pointing to a single atomic conditional UPDATE instead

  4. ~1.5h

    Schema, store, and service rewritten; app typechecks and builds clean

    publish_requests + audit_log tables added; decideRequest's TOCTOU replaced with one atomic UPDATE...WHERE status='pending'...RETURNING

  5. ~2h

    Real regression test written (unrun — no live DB configured)

    Promise.allSettled racing two decideRequest calls with no await between them; confirmed it fails honestly (clear missing-DATABASE_URL error), not silently

  6. ~2.25h

    Witness invoked on the atomicity claim — real CHALLENGE

    Witness correctly identified the claim rested on documentation/general-ORM reasoning, not on inspecting the actual generated SQL for this exact query shape

  7. ~2.5h

    Obtained the missing primary evidence directly

    Introspected the real query via Drizzle's own .toSQL() — confirmed one single UPDATE statement, no hidden read. Recorded verbatim in store.ts's own comment.

  8. End

    Doc updated honestly, second Witness opportunity considered and declined

    No second genuinely distinct consequential commitment existed in this build — did not force a second Witness call to hit the 'up to 2' allowance

What shipped

  • experiments/game-builder/lib/db/schema.ts — new publish_requests and audit_log Postgres tables, replacing publish-requests.json and audit-log.jsonl

  • experiments/game-builder/lib/db/index.ts — createDb wiring, same pattern as Hearth/Forge

  • experiments/game-builder/lib/approval-gate/store.ts — rewritten for real DB access; decideAtomically() replaces the old read-then-write decideRequest logic with one atomic conditional UPDATE

  • experiments/game-builder/lib/approval-gate/service.ts — decideRequest() now distinguishes 'lost the race' from 'not found' honestly via decideAtomically()'s null return, not a thrown generic error

  • experiments/game-builder/lib/approval-gate/service.test.ts — real-DB concurrency regression test (Promise.allSettled, no vi.mock), verified to fail honestly without a live DB, not yet run against one

  • experiments/game-builder/drizzle.config.ts, package.json (added @neondatabase/serverless, drizzle-orm, drizzle-kit, forgekit-core, forgekit-testing, dotenv, tsx; added db:push and test scripts)

  • experiments/game-builder/docs/parent-approval-gate.md §7 — items 1 and 3 marked RESOLVED with what was verified and what remains a real deployment-time gap (no live Neon DB provisioned yet)