Last updated: 2026-07-12

🤖
AI Session Handoff — Castle Checkers (Caretaker Portal)

Read this before making any code changes. The FUSE-safe commit pattern is mandatory — deviating from it causes silent corruption.

Critical Rules

RuleWhy
Write files to /tmp first — never directly to FUSE pathFUSE mount silently truncates large file writes — both disk and git blob end up identically truncated so verification passes on a corrupted blob
Always use git --git-dir GIT pattern — never git -C <FUSE_path>FUSE git config is unreadable — git commands fail or return empty silently
Strip null bytes before hashing: raw.rstrip(b'\x00')Edit/Write tools append null bytes to files on FUSE mounts
Use Python ls_tree/mktree helpers — never shell printf+grepShell pipe approach creates duplicate tree entries — GitHub rejects the push pack
Get tree SHAs by walking root → src → components → admin; NOT via git ls-tree HEAD src/git ls-tree HEAD src/ returns file contents, not the tree SHA — using .split()[2] on multi-line output grabs a random blob SHA, silently dropping all other files from the tree
TypeScript strict: remove ALL unused vars before commitTS6133 = Cloudflare Pages build failure — not caught locally
App.tsx at src/App.tsx — NOT src/components/App.tsxmain.tsx imports ./App from src root — wrong path = TS2307
Parent commit = last PUSHED SHA — hardcode itUnpushed intermediate commit as parent pulls bad trees into push pack — GitHub rejects
Verify blob line count immediately after hashingFUSE can silently corrupt even /tmp writes on some operations — always run git cat-file -p sha | wc -l and compare to /tmp file line count before proceeding
Every new portal repo first push: delete lock, rewrite config, add remote, then push.git/config is always corrupted on FUSE and a .git/config.lock is left behind

Where Things Live

ItemPath
Project rootE:\Claude_Projects\sonan-trackers\caretaker-portal-Claude\caretaker-portal\
Bash path/sessions/*/mnt/sonan-trackers/caretaker-portal-Claude/caretaker-portal/
Workerworker/index.ts (856 lines)
Frontend entrysrc/main.tsxsrc/App.tsx (29 lines) — showEmployee state controls EmployeeApp routing
Global statesrc/context/AppContext.tsx (523 lines) — includes getSecureNotes, saveSecureNotes
Admin shellsrc/components/AdminApp.tsx (88 lines) — sidebar color driven by cfg?.primary_color || '#1a3050' inline style
Employee shellsrc/components/EmployeeApp.tsx (271 lines) — renders EmployeeLogin when not logged in; shows appointment list after login
Public sitesrc/components/PublicSite.tsx (219 lines) — accepts onEmployeePortal prop; "Employee" button in nav triggers it
API layersrc/api.ts (108 lines) — includes getBlockedDays, createBlockedDay, deleteBlockedDay, getSecureNotes, saveSecureNotes
D1 migrationsmigrations/0001_init.sql through 0006_blocked_days.sql
Last HEAD (push pending)b2767bfbfca5631fcd1370de3c79b701b41c55a6 — Employee login nav + color fallback fixes
Last confirmed pushed3fb1df1 — TypeScript fix getSecureNotes/saveSecureNotes
DB color settingINSERT OR REPLACE INTO settings (key, value) VALUES ('primary_color', '#1a3050') — sidebar reads from DB, NOT from CSS variables

Known Gotchas (Learned the Hard Way)