Files
session-history/ecomm/0009/SESSION-0009.0-TRANSCRIPT-2026-06-01.md

10 KiB

SESSION-0009.0 — Real ecomm build: R01 + Auth + R02 + GraphQL/BFF + replan

Date: 2026-06-01 Driver: Ben (ben@wiggleverse.org) Repos touched: wiggleverse-ecomm (impl, branch r01-store-settings), wiggleverse-ecomm-meta (plan, branch replan-v2-resequence) Outcome: First real releases shipped (code-complete, on a branch, unmerged); GraphQL+REST-BFF architecture established; release plan reassessed.

Transcript-honest per the engineering guide — wrong turns included.


What happened (in order)

  1. "Implement the first ecomm release per the BDD tool." Investigated; the throwaway prototype had R01/R04/R06. Asked which track. Ben: "We didn't end up needing the prototype. Build Real Build R01, based on the OHM concepts at ohm.wiggleverse.org." → Pivot: prototype retired, real product begins.

  2. R01 — Store profile & settings (13.06.0001-0010). Wrote SPEC.md v0.1 first (binding), every mechanic citing the OHM concept it serves (§5 traceability table = Transparency & Traceability applied to our own code). Read the live OHM corpus via https://ohm.wiggleverse.org/api/rfcs (39 rows; 7 are known dash-less dupes; only human/RFC-0001 is graduated, rest are super-draft pitches). Stack: FastAPI + stdlib sqlite3 (WAL) + forward-only .sql migrations + Vite/React. Grounded the model in Participants (Store controlled by a Merchant/Human-in-role), No Retroactive Harm (units/currency/tz are display-only, stored canonically; order numbers stamped-at-mint and immutable), Privacy & Data Minimization, Agency & Anti-Manipulation (frictionless pause/reactivate). 11 tests + browser verified. Commit 9f397b0.

  3. "Block any user who hasn't been invited — logging in creates the user in an Uninvited state, invite later, exactly like ohm-rfc-app." Read rfc-app's auth.py/otc.py/invites.py first, then mirrored its permission_state model (pending=Uninvited / granted / revoked). Ben chose OTC, email stubbed. A sign-in provisions rather than rejects; require_granted gates writes; owner invites/grants/revokes. 11 tests + full browser flow. Commit 9843e56.

  4. Ben: "Is this R01 or R02?" — a fair correction. I'd framed the auth gate as "R01 substrate"; it's really R02 (Staff & permissions). Honest answer given; then "Finish R2."

  5. R02 — Staff & permissions (13.15.0001-0009), full release on the auth foundation: per-section permission scopes, invite-with-scopes → accept → Active, section-limited access, revoke-preserving audit log, owner protection, store-wide 2FA mandate (gate real, second factor stubbed), ownership transfer, time-limited collaborators, subset-rule on granting. 10 tests + browser. Commit 0bbe37b.

  6. "Everything available via a GraphQL API (full surface + relationships); plus REST BFFs for the UI." Established the standing two-layers-over-one-core architecture (SPEC §A). GraphQL (Strawberry) = canonical complete graph + all mutations; REST = screen-shaped BFF; both share store.py/staff.py and the factored auth.assert_* gates. Ben chose full read+write + "UI may also use GraphQL" → the Team page loads via one GraphQL relationship query. 6 GraphQL tests (38 total) + browser. Commit 16c3f1c.

  7. "Reassess the releases and shuffle." Replan v2 (see below). Meta branch replan-v2-resequence, unpushed.

  8. Working mode set: "trust and verify." Proceed autonomously; announce what + why before each chunk; verify + commit to a branch; never merge/push. NO SECRETS — never handle secret bytes; hand Ben the gesture.

Wrong turns / gotchas (honest record)

  • Mis-labeled the auth gate as R01 substrate — it's R02. Ben caught it.
  • OTC 60-second cooldown makes rapid same-email re-login in the browser flaky (silently no-ops, leaves the prior session — once made a GraphQL check look like a bug when it was just the owner session lingering). Workaround: drive the login via an in-page .click() + poll loop, or wait it out. pytest is unaffected (fresh DB/email per test). Not a product bug.
  • First mkdir for the backend landed in the wrong dir (cwd was the ecomm working root, not the repo) — corrected.
  • One GraphQL test asserted the wrong seed name ("Owner" vs the Merchant entity "Store Owner") — fixed.

Replan v2 — release reassessment

Two structural defects fixed in roadmap/RELEASE-PLAN.md:

  1. R03 Locations was un-buildable as sequenced — 5/9 scenarios depend on Inventory/Checkout/Orders/Fulfillment. Slimmed R03 to its dependency-free core (13.07.0001/0002/0003/0006); moved 0008→R07, 0007→R13, 0004/0005/0009→R23.
  2. POS was gated behind the whole online stack (R22→R15→R13→storefront…). Re-rooted: the Order is a shared spine born from manual/draft creation (R25 pulled forward); online checkout (R13) and POS (R22) are two channels onto it; R15/R16 re-root on R25; R22 depends R16, not the online stack → Hasan's in-person-payment MVP reachable without any storefront/theme/shipping. Pulled Customers + Taxes(R12) into the shared foundation. Two MVP finish lines: Hasan=R22, Connie=R14. Authoritative build-order table added at the top of the plan; R-codes kept stable (now non-monotonic). Validated: no id duped, counts match.

Artifacts / state at end of session

  • Impl wiggleverse-ecomm, branch r01-store-settings, 4 commits unmerged: 9f397b0 R01 · 9843e56 auth · 0bbe37b R02 · 16c3f1c GraphQL+BFF. SPEC.md v0.4. 38 tests pass. Working tree clean.
  • Plan wiggleverse-ecomm-meta, branch replan-v2-resequence, replan commit 6b785b8 (+ this transcript). Unpushed.
  • Operator follow-ups (Ben): merge/push the impl branch; review + push the replan branch (push re-ingests the live BDD app); optionally physically reorder the plan's sections to match the build-order table. Still stubbed: real outbound email, real TOTP.

NEXT-SESSION RESUME PROMPT — R03 Locations (core)

Paste the block below into a fresh session.

Build R03 — Locations (core) — the next release in the real wiggleverse-ecomm
product. Read your memory first ([[ecomm-real-build]], [[ecomm-bdd-release-planner]],
[[ecomm-business-context]]).

WORKING MODE — "trust and verify": proceed autonomously on the right things; tell me
what you'll do and why before each meaningful chunk, then go. Verify with tests + a
browser pass, and commit to the branch (do NOT merge or push — those are mine).
NO SECRETS, EVER — never type/paste/generate/echo a secret value; build around it and
hand me the gesture. Code reads secrets from env / Secret Manager only.

WHERE THINGS ARE:
- Impl repo: ~/projects/wiggleverse/ecomm/git/wiggleverse-ecomm (branch
  r01-store-settings — keep working on it; it has R01 + auth + R02 + GraphQL/BFF,
  unmerged). Backend: backend/app/{main,db,deps,store,staff,auth,units,graphql_api}.py,
  backend/migrations/000X_*.sql, backend/tests/test_*.py. Frontend: frontend/src/.
  venv at repo-root .venv/. Run backend: cd backend && ECOMM_DB=backend/var/ecomm.db
  ECOMM_OWNER_EMAIL=owner@wiggleverse.test ../.venv/bin/python -m uvicorn app.main:app
  --port 8000. Tests: cd backend && ../.venv/bin/python -m pytest -q. Frontend preview:
  launch.json config "ecomm-frontend" (port 5173, proxies /api -> :8000).
- SPEC.md (binding, v0.4): read §A (GraphQL+BFF architecture), §1 (model), §5
  (concept→mechanic traceability — ADD ROWS for R03), §7-§8 (auth/staff gates).
- Scenarios: wiggleverse-ecomm-meta/research/shopify/settings/locations.md (feature
  13.07). Plan: wiggleverse-ecomm-meta/roadmap/RELEASE-PLAN.md (R03 was slimmed to
  the core on branch replan-v2-resequence — build ONLY these 4):
    13.07.0001 add a new location with fulfillment enabled
    13.07.0002 edit an existing location's details
    13.07.0003 set a location as the primary fulfillment location
    13.07.0006 cannot delete the only remaining location
  DO NOT build 0004/0005 (need inventory+orders → R23), 0007 (checkout → R13), 0008
  (inventory → R07), 0009 (fulfillment → R23). They moved out by design.

GROUND IT IN OHM (the discipline): fetch the relevant concepts from
https://ohm.wiggleverse.org/api/rfcs/<slug> and cite each mechanic in SPEC §5.
Likely hooks: a Location is the embodied, physical venue of the Commercial
Relationship (commerce where humans actually meet); "can't delete the only location"
and "set primary" protect the merchant's operational integrity (Dignity in Commerce /
Duty of Care — never strand a store with nowhere to fulfill from). Decide and cite.

THE ARCHITECTURE TO FOLLOW (every release lands in BOTH layers on the shared core):
1. Domain: a Location entity, store-scoped (store_id). Fields: name, address_*,
   fulfillment_enabled, local_pickup_enabled, is_primary, active. New module
   app/locations.py (mirror staff.py shape: primitive params, raise HTTPException).
   Invariants: setting primary unsets the others; cannot delete/deactivate the only
   active location (0006). Migration 0004_locations.sql. Seed one primary location
   for the store in db._seed so 0006 has something to protect.
2. Auth: gate location management under the 'settings' section
   (require_section('settings')) — consistent with where Shopify files Locations.
   (Or add a 'locations' section to staff.SECTIONS if you think it earns its keep —
   your call; if you add it, update the staff scope UI + tests.)
3. GraphQL (canonical): add Location type + Store.locations relationship + mutations
   (addLocation, updateLocation, setPrimaryLocation, deleteLocation) in
   app/graphql_api.py. Reuse the _require_section/_run gate helpers.
4. REST BFF: screen-shaped endpoints under /api/stores/{sid}/locations.
5. Tests: backend/tests/test_r03.py — one test per scenario id (0001/0002/0003/0006),
   plus a GraphQL test for the locations relationship + a mutation. Keep the full
   suite green.
6. Frontend: a Locations admin section (list, add, edit, set-primary, delete-guarded).
   Verify in the browser via the preview tool (sign in as owner@wiggleverse.test; OTC
   code is returned in dev — watch the 60s cooldown; drive login via an in-page click
   + poll if it stalls).

DELIVERABLES: migration 0004, app/locations.py, GraphQL + REST + gate wiring, tests
(all green), frontend Locations UI, SPEC §5 rows + a short "## 9. Locations" section,
README "Shipped" bump, commit to r01-store-settings. Update memory. Then give the
resume prompt for the next release (R04 Product create & lifecycle) and a session
transcript.