ForgeKitFORGEKIT

Build Log

Parent Approval Gate — Specification and Prototype

August 1, 2026

Designed and prototyped the non-bypassable parent approval gate that must exist before any child-directed Roblox publish or monetization action can execute.

Game BuilderSafetyArchitecture

What shipped

experiments/game-builder/docs/parent-approval-gate.md — full architecture spec (gated actions taxonomy, ForgeKit-controlled-publishing Anvil decision, request lifecycle state machine, interception point, notification/review flow, audit trail design, known prototype limitations, risk-to-design mapping, return conditions)

experiments/game-builder/lib/approval-gate/types.ts — GatedActionType, PublishRequest, AuditLogEntry

experiments/game-builder/lib/approval-gate/hash.ts — deterministic project-state hashing (sha256 over stable-stringified state)

experiments/game-builder/lib/approval-gate/store.ts — file-backed persistence (publish-requests.json) + append-only audit log (audit-log.jsonl)

experiments/game-builder/lib/approval-gate/service.ts — createPublishRequest, decideRequest, enforceApprovedPublish (the non-bypassable check), recordPublishExecuted

experiments/game-builder/lib/approval-gate/mock-roblox-publish.ts — mock publish function that calls enforceApprovedPublish first and does nothing if it throws

experiments/game-builder/app/api/approval-gate/requests/route.ts — POST create request, GET list requests for a parent

experiments/game-builder/app/api/approval-gate/requests/[id]/decision/route.ts — POST approve/deny

experiments/game-builder/app/api/approval-gate/publish/route.ts — POST attempt the gated action (enforcement demo)

experiments/game-builder/app/api/approval-gate/audit-log/route.ts — GET the persisted audit trail

experiments/game-builder/.gitignore — added .data/ (prototype runtime store, not source)

An advisory check inside the same session the child directs isn't a gate — it protects against accidents, not against the exact bypass the Charge names as a risk.

This session's Anvil Check, on why the real publish call must live in ForgeKit's backend exclusively