# SHARED CONTAINER LOGIC — Design (2026-09-04)

**Status:** DESIGN COMPLETE — awaiting Bekky's "compile" before any build.
**Approach:** Container-View middle path (NOT fused profile). Keep separate plant records; present a container view that makes roommates feel fused.
**Reversibility:** This is a JS-only OTA feature (no native modules). Revert = unlink `sharedContainerId` / re-ship prior OTA. All changes behind additive fields on existing plant records — no destructive migration. Backups taken before edits per house rule.

---

## 1. THE CORE INSIGHT

A shared container is a **physical fact that must feed the existing grouping/care engine**, not just a label. Two plants in one pot cannot be watered independently — water one, you water both. So roommates are treated as **inseparable in care**: a shared container is effectively a **forced cohort** (water + fertilize shared, hard rule).

The app is deeply plant-centric (every record/screen/cohort lookup keyed on individual `plantId`). A true fused profile would be a large refactor. **Container-View middle path** keeps separate records (all existing machinery works) but presents a container view that makes them feel fused.

---

## 2. DATA MODEL (simple, additive)

- Add `sharedContainerId?: string` (a UUID) to each participating plant's profile.
- Plants with the same `sharedContainerId` are roommates.
- **Symmetric:** adding plant B to A's pot gives both the same id.
- **Pending-roommate state:** a `sharedContainerId` can exist with a placeholder slot (roommate not yet in the app). This is the "Haven't added yet" / "Not in my garden yet" deferred state.
- No separate container entity for v1 — keep it lean.

---

## 3. ENTRY POINTS

### Primary: Setup, under "potted or in ground"
- A **"Shared container"** chip appears only when the plant is **potted** (gated — a shared container only exists if potted; in-ground = never, that's companion planting / neighbor tagging from Chunk 1, a different concept).
- Tapping it opens a **modal** (matches established PixieAlert / CohortSoilCheckModal patterns).

### Secondary: Editable from plant detail
- Setup is where you *first* declare it, but at setup time the roommate may not exist in the app yet. So it must also be **editable later from the plant detail page** (a "Container" section). This is why it can't live *only* in setup.

### Deferred (parked): quick plant-ID scan shortcut
- Clever but a whole extra scan flow for v1. Park it.

---

## 4. THE MODAL

- **No "none / just this plant" chip** — redundant, since the user already tapped "Shared container."
- Instead, deferred chips:
  - **"Haven't added yet"** — roommate exists in the app but not yet linked.
  - **"Not in my garden yet"** — roommate is a real plant but not yet in the app (placeholder slot).
- Otherwise: a picker of plants **in the same space** (roommates are necessarily in the same space) with photos + names. Tap to select roommates.

---

## 5. DELETE-ROOMMATE MODAL (3 outcomes — exhaustive)

When deleting plant A and it has roommate B, ask **"What happened to its roommate?"**:

1. **Delete B too** → whole container gone, both records removed.
2. **Make B standalone** → unlink, B keeps living independently. **Nudge is SOFT** (outcome-appropriate): "Do you need to update the setup?"
3. **I repotted B** → B is now in its own pot → B becomes standalone. **Two-button choice** (power to the user):
   - **Button 1 — "Complete repot"** (the "skip for now" path): finalizes the repot — B unlinked, repot recorded, setup untouched. For when the repot didn't change the pot/medium meaningfully.
   - **Button 2 — "Complete repot and update setup"**: finalizes the repot **and** jumps straight into B's setup screen. When setup is finished, the repot-to-JSON logic finalizes (repot state + updated setup persist together).

The nudge wording is written for the specific outcome — soft for standalone (maybe nothing changed), firm + actionable for repot (setup data is now definitely stale). A repot is a repot — it can't be skipped, only completed with or without the setup detour.

---

## 6. CARE — PER CONTAINER (hard rule)

- **Water + fertilize are shared** across the container. Completing one completes both.
- Reuses the existing cohort system: a shared container is a **forced cohort** (both plants in the same water cohort + same fertilize cohort). The engine already keys cohorts by `plantId:action`; a shared container just forces membership. **No new care machinery needed.**
- **Hard rule, not suggestion** — it's a physical fact; letting the AI split a shared pot would be the app being "smart" in a way that's actually wrong.

---

## 7. CONFLICT NOTE — ONE-TIME, IN ENRICHMENT PACKET

- When two species share a pot and their care conflicts, the AI **gently states it once** in a display area: "This isn't an ideal match — watch for X, Y, Z" where XYZ = the pests/disease/fungus most likely from this pairing.
- Generated **once with the initial enrichment packet**, **never refetched** (no proxy hammering).
- **EXCEPTION (Bekky 2026-09-04):** if the **roommates change** (add/remove a roommate), the conflict note **must be refetched** — the pairing changed, so the conflict assessment is stale. Refetch only on roommate-set change, not on every open.
- Transparency up front is good protocol — this is the kind of honesty that builds trust.

### Color-coded by pairing quality (Bekky's spec)
- **Red** (bad pairing) — red outline/box: "This isn't a good match — watch for X, Y, Z."
- **Amber/yellow** (neutral) — yellow/amber box: neutral note.
- **Green** (good pairing) — green box: a note about **why it's a good pairing** (complementary needs, etc.).

### Placement
- **Above the care section** (important that the user sees it), at the **top of the Container section**, above the roommate list.

---

## 8. CONTAINER VIEW (the "feel fused" part)

- Each plant's tile shows a small **"shares a pot with X"** badge.
- The **detail page** gets a **"Container" section** listing all roommates with photos — tap to jump between them.
- **Care is container-scoped** (one water task, one fertilize task for the whole pot).
- If they ever separate, it's just unlinking `sharedContainerId` — **no logic refresh needed**.

---

## 9. EDGE CASES

1. **Delete a roommate** → survivor un-links cleanly (no orphaned id pointing at nothing). Handled by the delete-roommate modal (Section 5).
2. **Move a plant to a different space** → if it's in a shared container and the user gave **no indication of separating it**, the roommates **move together** (with a confirm). Sneaky one — must be handled.
3. **In the ground** → no shared container, ever (Section 3).
4. **Care display** → when a roommate is due for water, the other shows a subtle "shares a pot with X" note, not a duplicate task.

---

## 10. FILES TOUCHED (expected, to be confirmed at build)

- `types/garden.ts` — add `sharedContainerId` to plant profile.
- `types/appTypes.ts` — re-exports.
- `services/gardenStorage.ts` — persist the field (normalizer-safe).
- `screens/ProfileScreen.tsx` — setup chip + modal, detail Container section, delete-roommate modal, tile badge.
- `components/` — new SharedContainerModal (or reuse PixieAlert pattern).
- `services/care/cohortCareService.ts` / grouping — force shared-container membership.
- `services/plantIntelligence/` — conflict note in enrichment packet.

---

## 11. OPEN QUESTIONS (for Bekky)

All three prior open questions are **RESOLVED** (2026-09-04):
- **Standalone nudge** → soft ("Do you need to update the setup?"); **repot nudge** → firm ("Don't forget to update setup" + tappable colored link to setup screen). ✅
- **Move-to-different-space** → roommates move together (with confirm) unless user indicates separation. ✅
- **Conflict note placement** → top of Container section, above roommate list, above care section; color-coded red/amber/green by pairing quality. ✅

**Remaining to confirm at build time:**
- Exact color tokens for red/amber/green boxes (match existing theme).
- Whether the conflict note needs a "dismiss" affordance or is always visible.
- Whether the setup link should deep-link to the specific plant's setup or the generic setup screen.
