From d16a567a3ca7446b111f36ef42c08c5368566ed4 Mon Sep 17 00:00:00 2001 From: Keysat Date: Fri, 19 Jun 2026 17:17:33 -0500 Subject: [PATCH] docs: mark P3b committed in Current state (handoff) --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index b0d7bcc..bc85781 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -110,7 +110,7 @@ Subsystem rules live in `docs/guides/` and lazy-load in Claude Code via `.claude _**Box live at v0.1.0:94**; `main` ahead by mobile Phases 0–6 + P3b name/pill edit + drag-reorder views — **all deploy-pending** (no s9pk built yet). **The fundraising grid + email capture is the canonical system of record.** Active thread: **mobile-first redesign** — **all 4 surfaces + light theme + P3b (name/pill edit) done; BRIEF §3a editable set complete**. **Plan (Grant, 2026-06-19): finish features first — P3b done → Phase 7 design-conformance pass next — then Grant does device testing + deploy** (NOT before; everything is unverified on a real phone). Per-phase detail + backlog: `ROADMAP.md` / `EVALUATION.md`; history: git log + `start9/0.4/startos/versions/`._ - **Mobile redesign — all 4 core surfaces built + committed (Grid · Contacts · Pipeline · Reminders).** Each is a rules-of-hooks-safe `useIsMobile()` wrapper → `Mobile*`/`Desktop*` pair (**desktop untouched**), re-authored against the real API on shared primitives ``/`useIsMobile()`/`StageChip`/`MobileDetailRow`. Foundation: bottom-tab bar + `:root` mobile vars (P1); 4-stage enum + read-only derived grid signals (`existing_investor`/`last_activity_at`/`staleness`/`opportunity_id`) injected on GET, **stripped on write at both points** (P0/P3a `_computed_row_values` + `stripComputedRows`). **Mobile writes use one-row endpoints only — never whole-grid PUT** (BRIEF §3a): log-communication, pipeline link/stage, reminders, and now **`POST /api/fundraising/update-row`** (P3b name/pill edit). Per-phase detail in `ROADMAP.md`. -- **This session — P3b investor name + contact-pill edit (frontend + backend; not yet committed at write time → see git log).** New **version-safe `POST /api/fundraising/update-row`** (`handle_update_fundraising_row`) — the one-row read-fresh-modify-write twin of `handle_log_fundraising_communication`: reads the canonical grid blob server-side, mutates ONLY the target row's `investor_name`/`contacts`, writes back with a version bump + `sync_fundraising_relational`. Never a whole-grid payload → can't clobber concurrent edits to other rows (BRIEF §3a). Server-side `_sanitize_fundraising_contacts` (9-field whitelist; drops name+email-empty pills) is the trust boundary. Frontend: `MobileFundraisingGrid` detail gains an **Edit** bottom-sheet (investor-name input + pill add/edit/remove of name·email·title, preserving each pill's location/LinkedIn fields, **client-side dedup** by email→name) → saves through update-row → reloads; money stays desktop-only. Pill removal is **soft** on the classic `contacts` directory (only the grid pill + `fundraising_contacts` row drop). New CSS is theme-var-only (`.pill-edit*`/`.sheet-addbtn`/`.fs-detail-edit`). Verified: **`backend/test_fundraising_update_row.py`** (24 assertions over real HTTP — rename/add/edit/remove, other-row-untouched, relational + classic-contacts sync, soft-remove, name-only-pill kept, 5 guards); full suite **37/37**; render-smoke green; throwaway jsdom-375px harness drove the real edit flow (14/14: open→edit→rename→remove→add→save, asserted `POST update-row` + **no whole-grid PUT** + preserved fields). Reviewer-passed (nits were deliberate sibling-pattern parity). **No real-phone check.** +- **This session — P3b investor name + contact-pill edit (committed `3f93daf`, frontend + backend).** New **version-safe `POST /api/fundraising/update-row`** (`handle_update_fundraising_row`) — the one-row read-fresh-modify-write twin of `handle_log_fundraising_communication`: reads the canonical grid blob server-side, mutates ONLY the target row's `investor_name`/`contacts`, writes back with a version bump + `sync_fundraising_relational`. Never a whole-grid payload → can't clobber concurrent edits to other rows (BRIEF §3a). Server-side `_sanitize_fundraising_contacts` (9-field whitelist; drops name+email-empty pills) is the trust boundary. Frontend: `MobileFundraisingGrid` detail gains an **Edit** bottom-sheet (investor-name input + pill add/edit/remove of name·email·title, preserving each pill's location/LinkedIn fields, **client-side dedup** by email→name) → saves through update-row → reloads; money stays desktop-only. Pill removal is **soft** on the classic `contacts` directory (only the grid pill + `fundraising_contacts` row drop). New CSS is theme-var-only (`.pill-edit*`/`.sheet-addbtn`/`.fs-detail-edit`). Verified: **`backend/test_fundraising_update_row.py`** (24 assertions over real HTTP — rename/add/edit/remove, other-row-untouched, relational + classic-contacts sync, soft-remove, name-only-pill kept, 5 guards); full suite **37/37**; render-smoke green; throwaway jsdom-375px harness drove the real edit flow (14/14: open→edit→rename→remove→add→save, asserted `POST update-row` + **no whole-grid PUT** + preserved fields). Reviewer-passed (nits were deliberate sibling-pattern parity). **No real-phone check.** - **Prior session (`e6a8945`) — P6 light theme (frontend-only).** App-wide light theme behind `:root[data-theme="light"]` (dark default; pre-paint boot script reads `localStorage.venture_crm_theme`); toggle in desktop sidebar footer + mobile top bar off one `App` `theme` state. 44 themed `:root` slots (dark == originals byte-for-byte), 319 hex→`var()` migrated, `StageChip` className-based. **Mobile light complete; desktop-light rough edges** (bespoke `