ForgeKitFORGEKIT

Build Log

Closing the duplication sweep — and finding Hearth's real severity

July 17, 2026

Fixed both wiring gaps and extracted the two threshold-crossed patterns (org-auth, rate limiter) from last session's sweep, then investigated Hearth's flagged rate-limiting gap and found it was a real cross-tenant IDOR affecting ~26 files, not a missing rate limiter.

ForgeKit OSExtractionSecurityHearthKnownLeashlineForgePilotLight
4
duplication findings from last session, all resolved
2
new package modules extracted (org-auth, rate-limit), both tested
30
Hearth files migrated off a hardcoded single-tenant ID
9
additional zero-ownership-check IDOR bugs found and fixed beyond the simple hardcode swap

Timeline

Start
Zeb asks to continue from last session's duplication sweep backlog
4 items: 2 wiring gaps, 2 threshold-crossed extraction decisions
+20m
Wiring gaps fixed — Known's DB connection, Leashline's UI primitives
Both re-verified via direct file read before touching, not trusted from last session's snapshot
+50m
Auth-guard extraction — found Known's shape was a superset, not a duplicate
Forge's getTenantId() vs Known's requireOrgId()/requireOrgIdApi() — extracted to match the superset
+1.5h
Rate-limiter extraction — found the real consumer count differed from the backlog's claim
Arcade copy was stale (0 matches), real count was PilotLight + Happenstance + Medina-square (3 routes)
+2h
Hearth investigation reveals the real severity
A real multi-member access system existed (lib/access.ts) but ~26 files bypassed it; some server actions had zero ownership check at all
+2.2h
Fixed week/actions.ts by hand as the reference pattern
moveWeekItem had no ownership check whatsoever — any signed-in user could move any household's item
+2.5h
Background agent dispatched for the remaining 24 files
Worktree isolation
+3.7h
Agent returns — Claude initially misjudges it as untrustworthy
Checked a stale, unrelated leftover worktree directory instead of the real repo; corrected within minutes via direct verification
+4h
Independent verification confirms the agent's work was real and correct
Spot-checked 5+ files' diffs directly, ran tsc --noEmit and a full production build personally, found 2 additional client-side hardcodes the agent missed
Close
Registry updated with grep evidence, verify:reuse shows 0 broken claims across 53 rows
Crucible post-build audit run before retro

What shipped

Known's lib/db/index.ts now imports createDb from forgekit-core/db instead of duplicating the lazy-proxy pattern

Leashline's Button/Card/Badge now re-export from forgekit-ui instead of carrying byte-identical local copies

packages/forgekit-core/src/org-auth.ts — requireOrgId(redirectTo) + requireOrgIdApi(), extracted from Forge's getTenantId() and Known's requireOrgId()/requireOrgIdApi(), built to Known's superset shape. Tested: 5 passing tests.

packages/forgekit-ai/ — first real module in a previously-empty planned package. createRateLimiter(windowMs?, max?) factory extracted from 3 real duplicate implementations. Tested: 5 passing tests.

PilotLight and Happenstance added to root package.json workspaces (were standalone Vercel projects outside the monorepo build) — required to safely consume forgekit-ai without breaking their production builds

Stray per-app package-lock.json files removed from PilotLight and Happenstance now that root lockfile governs them

products/hearth/app/(dashboard)/week/actions.ts fixed by hand as the reference pattern — moveWeekItem, markWeekItemDone, hideFromLookahead, updateWeekItem, addToTodayRoute all had zero or hardcoded-only household scoping

products/hearth/lib/calendar-token-manager.ts — getValidAccessToken() changed from a zero-arg function using a hardcoded constant to taking householdId as a required parameter

24 additional Hearth files migrated from HOUSEHOLD_ID = 'household-1' to real Clerk-derived household scoping via lib/access.ts's getHouseholdForUser()

9 additional zero-ownership-check bugs found and fixed beyond the simple constant swap, including a cross-household data-loss bug (meals/grocery/route.ts was deleting every household's grocery items for a week, not just the caller's) and a client-supplied-householdId IDOR in curriculum/import/route.ts

2 more household-1 literals found and fixed after the agent's pass (GroceryList.tsx, RecipeBook.tsx — client-side optimistic-UI placeholders, not a real security gap but worth correcting)

forgekit-os/patterns.md and extraction-backlog.md updated with grep evidence for every status change — npm run verify:reuse shows 0 broken claims across all 53 registry rows

“ok. all good for now. where are we at with the duplication check. is that all resolved?”

— Zeb, checking whether the session's stated goal was actually complete before closing