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
| Rule | Why |
|---|---|
Write files to /tmp first — never directly to FUSE path | FUSE 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+grep | Shell 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 commit | TS6133 = Cloudflare Pages build failure — not caught locally |
App.tsx at src/App.tsx — NOT src/components/App.tsx | main.tsx imports ./App from src root — wrong path = TS2307 |
| Parent commit = last PUSHED SHA — hardcode it | Unpushed intermediate commit as parent pulls bad trees into push pack — GitHub rejects |
| Verify blob line count immediately after hashing | FUSE 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
| Item | Path |
|---|---|
| Project root | E:\Claude_Projects\sonan-trackers\caretaker-portal-Claude\caretaker-portal\ |
| Bash path | /sessions/*/mnt/sonan-trackers/caretaker-portal-Claude/caretaker-portal/ |
| Worker | worker/index.ts (856 lines) |
| Frontend entry | src/main.tsx → src/App.tsx (29 lines) — showEmployee state controls EmployeeApp routing |
| Global state | src/context/AppContext.tsx (523 lines) — includes getSecureNotes, saveSecureNotes |
| Admin shell | src/components/AdminApp.tsx (88 lines) — sidebar color driven by cfg?.primary_color || '#1a3050' inline style |
| Employee shell | src/components/EmployeeApp.tsx (271 lines) — renders EmployeeLogin when not logged in; shows appointment list after login |
| Public site | src/components/PublicSite.tsx (219 lines) — accepts onEmployeePortal prop; "Employee" button in nav triggers it |
| API layer | src/api.ts (108 lines) — includes getBlockedDays, createBlockedDay, deleteBlockedDay, getSecureNotes, saveSecureNotes |
| D1 migrations | migrations/0001_init.sql through 0006_blocked_days.sql |
| Last HEAD (push pending) | b2767bfbfca5631fcd1370de3c79b701b41c55a6 — Employee login nav + color fallback fixes |
| Last confirmed pushed | 3fb1df1 — TypeScript fix getSecureNotes/saveSecureNotes |
| DB color setting | INSERT OR REPLACE INTO settings (key, value) VALUES ('primary_color', '#1a3050') — sidebar reads from DB, NOT from CSS variables |