Porting www.babanuj.com from Next.js 15 (Vercel) to classic Shopify Hydrogen — React Router 7 + Vite — hosted on Vercel, in a new repo, with a parity-gated cutover.
⏸ Agent-side work COMPLETE — everything left needs MoeRunbook dry-run done (gate 1 PASSES today; gates 2–4 await you) · YOUR list: t3 window (order+refund, staging webhook, OTP) · real SHOPIFY_WEBHOOK_SECRET · callback URI · then DNS per docs/cutover-runbook.md
43 / 44 tasks
Claude (reviewer)873M tokens — 848M cached reads · 21.7M fresh in · 2.9M out ≈ $1,258 API-equivalent (runs on the Claude plan)Codex (executor)136M tokens — 128M cached · 7.2M fresh in · 1.2M out, 90 exec/resume runs · ChatGPT plan, not meteredAs of Jul 12 (v0.9 t4)
Reviewer
Claude (Fable 5)plans, reviews every PR, maintains this board
Executor
Codex · gpt-5.6 @ mediumcodex exec, one task per PR, never merges
Merge authority
Delegated to reviewerMoe's standing instruction Jul 11; local squash as Moe Ghashim + DCO; Moe retains override
Locked decisions
Target
Classic Hydrogen v2026.4
React Router 7 + Vite, Storefront API pinned 2024-10 for parity
Hosting
Vercel, not Oxygen
vercelPreset() + custom server entry; adapter is spike v0.1-t2
Repo
~/babanuj-hydrogen
new sibling repo; production repo untouched
Cutover
Parallel run + parity gate
noindexed staging, automated audit, attribution rehearsal, then DNS
URLs
1:1 path parity
no Shopify/PostHog/Meta config changes needed at cutover
Checkout
checkout.babanuj.com
invariant — cart.checkoutUrl is never rewritten
Cutover gate
DNS does not move until every step is green, in order.
1URL-parity audit (full sitemap + redirects)2Lighthouse: SEO 100, perf within 5 pts3Cart smoke (checkout host asserted)4Attribution rehearsal (real refunded order → PostHog)5Runbook dry-run + rollback proven
Milestones
v0.1
Scaffold & platform risk spikes
5/5 ✓ done
Skeleton builds and deploys to Vercel; the three platform risks — deployment adapter, caching without workerd, edge rewrites — proven before any product code.
t3Attribution rehearsal — real refunded order through PostHogAwaiting Moe
t4Cutover runbook + proven rollbackDone
t5Post-cutover cleanup after 2-week soakPlanned
Risk register
#
Risk
Severity
Mitigation
R1
No first-party Vercel adapter for classic Hydrogen — the glue is ours
Retired
Spike PASSED Jul 11: live Storefront SSR + streaming proven on a Vercel deployment. One residual: Hydrogen's POST Storefront proxy hits a Node duplex bug — tracked for v0.7 consent decision
R2
Losing tag-based revalidation → stale catalog
Mitigated
TTL matrix proven on CDN (s-maxage 900 + SWR 86400); /api/revalidate path preserved; final tuning in v0.8-t6. Found & fixed: Hydrogen's tracking-cookie default made responses uncacheable
R3
SEO regression at cutover (canonicals, redirects, sitemap)
Attribution chain breaks (PostHog revenue, Meta CAPI)
High
Byte-level HMAC test + full rehearsal with a real refunded order
R5
Hydrogen calver breaking changes quarterly
Medium
Pin exact versions; upgrades are explicit post-cutover tasks
R6
Shopify+Vercel's official direction is the new framework-agnostic Hydrogen (Next.js starter) — this port swims against that current
Medium
Acknowledged at sign-off; toolkit path documented as R1's fallback
Activity log
PR 045 merged — the cutover runbook exists, dry-run recorded. Agent-side v0.9 work is complete. Four hard gates up front with check commands and honest current states: the automated gate PASSES today (SEO 100, perf 98/98/100); the rehearsal sign-off, real webhook secret, and callback URI are correctly BLOCKED on Moe. The dry-run caught a live-fire bug: the old Vercel project is named babanuj-storefront, not babanuj — every rollback command was corrected before it could fail during a real incident. DNS baseline recorded (apex 308 → www holding), 30-minute rollback window with per-trigger checks, zero-downtime domain ordering. What remains is Moe's: the t3 window, the three cutover blockers, then DNS. PR #45
PR 044 merged — the attribution rehearsal is scripted down to the minute. docs/attribution-rehearsal.md walks the supervised window hop by hop with a verification command per hop (cookie → cart attribute → order → webhook 200 → PostHog receipt SQL → refund → teardown), and the read-only dry-run already proves today's expected-absent branches. Webhook plan: ADD a staging subscription from a dedicated custom app — the production signing secret never enters staging. What remains on t3 is exactly the Moe window: the test order + refund, the staging subscription, and OTP evidence. Task 004 (the cutover runbook itself) started in parallel. PR #44
PR 043 merged — the automated gate is live and PASSES on staging. One workflow, one verdict: parity (96/96 sitemap, 64 fixtures, 8/8 handlers) + Lighthouse (SEO 100 on all three page types; performance within 5 points of production measured in the same run: −2/−1/0) + a headless cart smoke that adds a real product, asserts every checkout link points at checkout.babanuj.com, and stops cold before payment. Codex's claim that noindex wouldn't affect the SEO score was disproven live (69!) and fixed per the planned contingency — only the is-crawlable audit is exempted, staging only, negative-tested. One deliberate delta accepted on review: the cart fragment now returns attributes so the gate and rehearsal can verify attribution. Task 003 (rehearsal runbook + tooling) started. PR #43
PR 042 merged — staging is now a safe parallel run. Every document on a non-production host carries X-Robots-Tag: noindex (server-entry decoration covering streamed and error documents; production exempt via a unit-tested Host predicate — the test that prevents cutover day shipping a noindexed production site). The runner's live check also exposed an ops gap: the staging project still carried live analytics keys, firing real PostHog beacons into the production project. Fixed under the locked default: keys removed, redeployed, HTML verified free of all PostHog/Meta/GA identifiers with noindex intact. Task 002 (the single-verdict gate workflow: parity + Lighthouse + cart smoke) started. PR #42
🏁 v0.8 milestone closed and merged to main (4972a81) — the cutover gate exists and passes. PR 41 delivered pnpm parity: full production-sitemap replay (96 pages, 200 + canonical + metadata tolerance), the 64-fixture redirect table, and the 8 legacy handler paths, with a CI-ready markdown report and non-zero exit on regression. Its very first live run earned its keep — two shipped regressions no per-task check had caught (sold-out PDPs 404ing where production serves 200 + OutOfStock schema; bespoke policy text leaking into meta descriptions), both fixed and re-verified. Deployment run PASS, production-baseline run PASS. v0.9 breakdown committed (5 tasks); task 001 (staging noindex + segregated analytics) started. PR #41
PR 040 merged — revalidation endpoint live, TTL budget proven on the CDN. /api/revalidate mirrors the old route's exact literals (including its HTTP-200-with-status-401 quirk, so Shopify's webhook registration never self-disables) with the locked 200 no-op made explicit. The staleness budget got the strong proof: a cached page served STALE at age 972s past s-maxage=900, then refreshed via stale-while-revalidate one second later — ≤15-min freshness observed end-to-end, no store mutation. Bonus: the ORIGINAL revalidation secret was retrievable and preserved, so that webhook needs no cutover change. Task 005 (pnpm parity — the cutover-gate CLI and milestone closer) started. PR #40
PR 039 merged — the #64 deltas are closed. Lowercase 308s live with correct exclusions; favicon.ico at exact 307 parity with production; PDP JSON-LD byte-identical including aggregateRating {3, 2 reviews} via server-side Judge.me; the document fingerprint provably derives from production source after the runner caught a self-referential hash. Task 006 (revalidation endpoint + TTL evidence) started; the parity CLI closes the milestone after it. PR #39
PR 038 merged — sitemap equality + a critical process catch. Sitemap URL sets 96=96 against live production; robots byte-identical with the staging noindex guard. The task also exposed that the local old-repo checkout was ONE COMMIT BEHIND GitHub (#64, the July SEO audit) — several earlier tasks ported from stale source, caught only because evidence always used live production as the oracle. Checkout synced; a gap-closure fix (lowercase-path 308, favicon.ico redirect, sku + server-side aggregateRating in PDP JSON-LD) is running before the parity CLI. PR #38
PR 037 merged — the complete redirect map, live-proven. 63 old rules → 63 generated rules with exact reconciliation; 62/62 testable fixtures passed on the deployment with exact status+Location; the apex→www rule oracle-confirmed against the real apex domain; generator hash-stable and drift-checked in CI. Task 004 (sitemap URL-set equality + the staging robots guard) started. PR #37
PR 036 merged — metadata byte-parity achieved. All six comparator URLs byte-equal against production (down to the trailing-slash homepage canonical and the Shopify-CDN og:image transform); JSON-LD parsed-diff identical on home/PDP/collection. The runner caught Codex comparing production against itself and drove two real fix rounds. Task 003 (the complete generated redirect map with CI drift-checking) started. PR #36
PR 035 merged — OG images at near-pixel parity. Programmatic diff vs production's own /opengraph-image: 0.248% (antialiasing only); exact old TTF bytes hash-verified inside the server bundle after a live-caught lambda ENOENT was fixed with Vite-inlined fonts. Task 002 (metadata byte-parity with the automated production comparator) started. PR #35
v0.8 breakdown approved — task 001 (OG images) started. Six tasks building the cutover gate: OG images, metadata byte-parity with absolute production canonicals on every environment, the fully-generated redirect map with CI drift-checking, sitemap URL-set equality + the staging robots guard, the URL-parity audit CLI, and the /api/revalidate no-op with TTL evidence. Execution order improved so the parity CLI audits finished surfaces.
🏁 v0.7 milestone closed and merged to main (e5d25c3) — every integration live at parity. Judge.me stars match production count-for-count (closing the port's last visible delta); the Meta pixel warning was root-caused as a port defect (fbq stub shape) and fixed; /reviews corrected to the featured carousel per production's own workaround. The milestone's ledger: revenue chain proven end-to-end, three silent-failure bugs caught live (cart-cache leak class, zero-hit gtag, double ViewContent), and three production discoveries (CAPI token, Inbox id, Judge.me extras were never set — all parity-inert). v0.8 (SEO & parity) breakdown drafting. PR #34
PR 033 merged — GA4 live behind the deferred loader. The fix round caught a silent-failure bug: the gtag stub pushed arrays, which gtag.js ignores — script loaded, zero hits dispatched. Fixed with arguments-object semantics + regression tests; both defer paths (interaction and 6.5s timer) proven live; all three analytics stacks coexist. Production discovery #3: Shopify Inbox never actually loaded on the old site (env absent) — the port correctly stays inert. Task 005 (Judge.me — the milestone closer) started. PR #33
PR 032 merged — Meta at parity, double-count eliminated. The fix round also caught (live) that PDP→PDP navigations fired zero ViewContent — resolved with a handle-keyed remount; final counts verified: exactly one pixel call + one beacon per product view, sharing one eventId. Task 004 (GA4 + the interaction/6.5s deferred loader) started. PR #32
PR 032 (Meta) reviewed — one fix in flight, one production discovery banked. Contract parity is field-for-field with live dedup proven (identical eventId on pixel + beacon). Discovery: META_CAPI_ACCESS_TOKEN is absent from the old project — production's server-side Meta CAPI has ALWAYS been inert, so parity is inert and token provisioning is an optional post-cutover activation for Moe. The reviewer blocked on a latent bug: hard PDP loads double-fire CAPI ViewContent with distinct eventIds (2× over-count once a token exists) — fix running. PR #32
PR 031 merged — the revenue chain is complete on the port. A signed synthetic orders/paid webhook flowed raw-body HMAC → distinct-id precedence → PostHog "Order Completed" with revenue 12.34, SQL-verified in the real project; a tampered byte bounced off 401. New cutover blocker recorded: the old SHOPIFY_WEBHOOK_SECRET is Vercel-sensitive/unretrievable — a verification-only secret is in place; the REAL Shopify signing secret must be pasted before DNS moves (401s or silent revenue loss otherwise). Task 003 (Meta pixel + CAPI) started. PR #31
PR 030 merged — PostHog live over the first-party proxy. Init options at 5/5 parity; SDK served from /ingest with zero direct posthog.com requests; pageview receipt confirmed by SQL against the real Babanuj project ($host-filterable). A genuine deploy failure (Node ESM vs posthog-js/react) was fixed with ssr.noExternal plus a post-build server-bundle guard — now CI-caught forever. Task 002 (the orders/paid revenue webhook) started. PR #30
v0.7 breakdown approved — task 001 (PostHog provider) started. Five tasks: PostHog client stack over the proven /ingest proxy (posthog-js is the milestone's one authorized dependency), the orders/paid revenue webhook with raw-body HMAC fixtures, Meta pixel + CAPI with shared-eventId dedup, GA4 behind the 6.5s deferred loader, and Judge.me — filling the review-star seams at last. Hydrogen analytics formally stays off; the PostHog stack is the production-parity answer.
🏁 v0.6 milestone closed and merged to main (22228e5). Customer accounts complete: bespoke OAuth (sessions survive cutover), param-verified live login redirect, all five account pages behind production URLs with all 12 Customer Account GraphQL documents byte-identical. One recorded deferral: live OTP login evidence awaits the two admin items, due by the v0.9 rehearsal. v0.7 (analytics — the revenue-chain milestone) breakdown drafting. PR #29
PR 028 merged — account reads live behind the guard. Five Customer Account GraphQL documents byte-identical to production; anonymous account routes now 302 to sign-in with exact return paths, no-store, zero cookie leakage; scoped order lookups return private 404s; status links carry the checkout-host regression test. Task 004 (profile + address mutations — the v0.6 closer) started. PR #28
PR 027 merged — auth routes live. /account/login's real 302 to Shopify OAuth verified parameter-for-parameter (exact redirect URI, S256 PKCE, full scope, 10-min HttpOnly state cookies); bogus-state callbacks land on the legacy auth_error convention; logout POST-only per production; return paths hardened with malicious-fixture tests. Task 003 (overview/orders/order detail — makes the sign-in guard live on real routes) started. PR #27
PR 026 merged — OAuth decision: bespoke port. Evidence across all four factors, including one new find: Hydrogen's client couples the Customer Account API to calver 2026-04 vs our pinned 2024-10. Sessions survive cutover; refresh returns committed cookies; 5-test PKCE protocol suite green. Moe's actions when ready: register https://babanuj-hydrogen.vercel.app/account/authorize as a Customer Account API callback URI in Shopify admin, and provide a test-customer email for OTP login evidence. Task 002 (auth routes + guard) started. PR #26
v0.6 breakdown approved — OAuth spike started. Four tasks: the auth decision spike (Hydrogen's client vs the bespoke 751-line port; reviewer prior is bespoke for session continuity at cutover), auth routes + guard, orders views, profile/address mutations. Two items only Moe can unlock: registering the preview callback URI in Shopify admin, and a test customer for live-login evidence — everything else is machine-verified and proceeds without waiting.
🏁 v0.5 milestone closed and merged to main (6f2e0f8) — the port is a browsable store. PR 025 landed the content routes with precedence proven live, exact FAQ JSON-LD parity on both SEO landings, and even a 404 verified as production parity (no shipping policy exists in the shop). All 17 public pages now serve at production-identical URLs with CDN-cached, cookie-free documents. v0.6 (customer accounts) breakdown drafting. PR #25
PR 024 merged — brand pages at parity. All 8 brand ids live; the facts strip's Lines value derives to the same '24 products' as production; identical grid; the seed-mode empty-grid quirk verified identical in the old repo before acceptance. Task 006 (content routes — the v0.5 closer, with route-precedence tests guarding the CMS catch-all) started. PR #24
PR 023 merged — search at contract-level parity; halfway point reached. /api/search diffed live against production: identical 17-field shape, byte-identical first result, same cache header; /search renders the same 68 products and identical filtered sets; the nav typeahead restored from old-source evidence (debounced suggestions with keyboard selection). Task 005 (brands) started. PR #23
PR 022 merged — card quick-add restored. The hover overlay is line-for-line vs the old card with byte-identical positioning vs production's live DOM; click adds optimistically and opens the drawer, exactly as production does. Clean useOptionalCart() keeps provider-less contexts graceful. Task 004 (search + typeahead) started — the /api/search JSON gets diffed field-for-field against production's live endpoint. PR #22
PR 021 merged — collections at parity; card quick-add fix fired. Same 7 live products/order/prices as production; legacy 308s verified for both mapping types. Accepted the task-specified improvement (valid-empty collections render empty rather than the old seed-fallback quirk). The reviewer escalated the missing card hover quick-add — present in production, unblocked since v0.4 — as a dedicated fix before the remaining grids land. PR #21
PR 020 merged — PDP at parity. Loader order mirrors legacy (stale 308 → lookup → 404), both redirect target types verified live; gallery/facts/tabs/recommendations visually match production; the variant picker's absence matches production's own behavior for the same products — parity preserved, not 'fixed'. Task 003 (collections) started. PR #20
PR 019 merged — the home page is live at full parity. Wholesale section ported with byte-identical mailto CTAs; home documents CDN-cached cookie-free (MISS→HIT); cart hydrates client-side. This PR also banked the port's most important fix: RR7 single-fetch responses were inheriting the public cache policy, publicly caching user cart JSON — caught live, fixed with a headers() export + regression test. Task 002 (PDP) started. PR #19
PR 019 (home) reviewed — one blocker, and a serious catch banked. The runner's live verification found RR7 single-fetch responses inheriting the public cache policy — the CDN was caching a user's cart JSON (privacy-grade bug; fixed with a headers() export + module test). Visual parity reached across hero/categories/carousels/brands/promo/how-it-works after three fix rounds. Reviewer then caught the missing wholesale-catalog section (the /#wholesale anchor target) — port in flight. PR #19
v0.5 breakdown approved — task 001 (home) started. Six route tasks with the Q1 refactor bound to home: cart moves to client hydration so catalog documents ship cookie-free with CDN caching (MISS→HIT re-proof required on the home page itself). Every route PR carries a same-URL visual side-by-side against production.
🏁 v0.4 milestone closed and merged to main (5fe6cf7). The cart works end-to-end on the live store: click-through smoke passed every step (add → drawer → badge → qty ± → remove → checkout.babanuj.com landing), attribution proven via direct Storefront query, and the live smoke caught a real nav wiring bug unit tests missed. Q1 answered: the cart moves to client fetch in v0.5-t1 so catalog documents stay CDN-cacheable. v0.5 (all 17 routes) breakdown drafting. PR #18
PR 017 merged — attribution proven on a live cart. A synthetic PostHog cookie posted to /api/cart/add became a posthog_distinct_id attribute readable via a direct Storefront query — the first link of the orders/paid revenue chain, verified end-to-end. Response contract byte-identical to production. Task 004 (drawer + cart page + full click-through smoke) started — the v0.4 closer. PR #17
PR 016 merged — cart actions live-verified; open question Q1 filed. Full round-trip on the deployment: add (cookie at exact legacy attributes) → update (totals recompute) → remove → 302 to the real checkout.babanuj.com permalink. Reviewer filed Q1 in dev/open-questions.md: cart-in-root-loader forces documents private, conflicting with v0.5's CDN-cached catalog pages — recommendation is client-fetched cart, decided at v0.5 kickoff. Task 003 (/api/cart/add attribution endpoint) started. PR #16
PR 015 merged — cart context live. The codebase's single useOptimistic sits in the provider with a CI guard test scanning the source; the Bag badge reads useCart(); deferred cookie-cart reads never set cookies (deployment-verified). Task 002 (the /cart action: add/update/remove/checkout with userErrors surfaced and checkoutUrl untouched) started. PR #15
v0.4 breakdown approved — task 001 (cart context) started. Four tasks: the single-useOptimistic provider fed by a deferred cookie cart, intent-based /cart actions with checkout-host protection, the /api/cart/add compatibility endpoint with PostHog attribution stamping (JSON contract pinned key-for-key), and the drawer/cart page with a REQUIRED live add-to-cart smoke against the real store.
🏁 v0.3 milestone closed and merged to main (c1e9642). The port now looks like babanuj: exact-parity styling foundation, computed-style-identical primitives, full chrome with the newsletter's checkout-host invariant live-tested, and a DOM-verified portal mobile menu pixel-equivalent to production (with real HTTP 404 error surfaces). PR 014 closed the milestone. v0.4 (cart) breakdown drafting. PR #14
PR 013 merged after the cat-bar fix. The verbatim 9-item production list restored with active-link boundary matching and route-change centering via a keyed useMountEffect child (repo effect-ban honored); new SSR test pins the list and semantics. Task 004 (mobile menu portal, branded 404/error boundary with real HTTP 404 status, deferred Sonner toaster) started — the v0.3 closer. PR #13
PR 013 reviewed — changes requested on the cat-bar. The chrome passed rigorous parity checks (nav computed styles byte-identical, footer text programmatically equal, newsletter posting field-for-field to the literal checkout host with a live 200), but the reviewer caught the cat-bar rendering raw CATEGORIES data where production hardcodes a curated 9-item list (Shop All → /search … Wholesale → /#wholesale). Codex is applying the verbatim port now. PR #13
PR 012 merged — primitives computed-style-identical. Product card compared against the live /search grid property-by-property (radius, border, chip pill, typography, price weight) — all identical; Hydrogen Image emits proper Shopify CDN srcsets; zero new dependencies; Judge.me stars correctly left as the v0.7 seam. Task 003 (chrome + newsletter with the checkout-host invariant) started. PR #12
PR 011 merged — styling foundation at exact parity. The 938-line globals.css diffs EMPTY against production after normalization; all 7 font files hash-identical; browser verification confirmed Bricolage/DM Sans/DM Serif and the full token palette match www.babanuj.com, no FOUT. New /dev/tokens route is the visual-parity harness for the rest of v0.3. Task 002 (shared primitives) started. PR #11
v0.3 breakdown approved — task 001 (styling foundation) started. Four tasks: Tailwind v4 + the 938-line token sheet + self-hosted fonts, shared primitives (photo → Hydrogen Image), the site chrome with the newsletter's checkout-host invariant, and the portal-based mobile menu + branded error surfaces. Every UI PR now requires a visual comparison against production.
🏁 v0.2 milestone closed and merged to main (1997279). The entire data layer is ported and proven: /dev/data ran all 13 live checks OK against the real store (11 client reads, adapter with GID preservation, full cart cycle with the checkout.babanuj.com assertion). Notable catch this task: the vitest glob was silently skipping .tsx tests — fixed, protecting every future component test. v0.3 (design system & chrome) breakdown drafting. PR #10
PR 009 merged — adapter boundary + seed fallback in. shopifyProductToBabanuj and the reverse bridge differ from production only in import paths (zero logic hunks); every env-fallback branch mapped 1:1; the no-network guarantee is enforced by a fetch-stubbed test. Task 005 (/dev/data health route — the milestone's live proof) started. PR #9
PR 008 merged — Storefront client ported, live-tested. All 16 legacy exports carried (cookie ownership moved to callers as designed); live integration tests against the real store passed: hidden-product filtering, menu/policies, and a real cart round-trip preserving the variant GID and the checkout.babanuj.com host. Reviewer independently confirmed cookie-attribute parity against production source. Task 004 (adapter boundary + seed fallback) started. PR #8
PR 007 merged — all GraphQL documents byte-identical. 22 template literals verified equal to production by an independent scanner; 19 exported documents pinned to a SHA-256 fingerprint recomputed from the old repo's own sources — any future query edit fails CI. Task 003 (the 647-line Storefront client, with an explicit cookie seam and env-gated live integration tests incl. the checkout-host assertion) started. PR #7
PR 006 merged — domain data ported with byte-parity. All seven pure modules verified byte-identical to production after quote normalization (data.ts 636 lines, redirects, shipping, contact, constants, type-guards); sole deviation is a one-line Next type substitution in utils.ts. Three-ID rule now enforced by unit tests in CI. Task 002 (GraphQL documents, byte-identical with a SHA-256 fingerprint test) started. PR #6
v0.2 breakdown approved — task 001 (domain data) started. Five task files on feat/v0.2-data-layer match PLAN §9 with criteria intact and the v0.1 learnings baked in (bespoke-client boundary, CACHE_NONE discipline). Task 001 ports the pure domain layer — brands, categories, vendor mappings, redirect data, seed products — value-for-value, with a unit test enforcing the brand/category three-ID rule.
🏁 v0.1 milestone closed and merged to main (d23b909). PR 005 (CI + guardrails) merged after its own CI ran green and the pre-push hook proved it blocks tracked .env files. DoD walked line by line: adapter ✓, caching ✓, edge routing ✓, test floor ✓, invariants preserved, open questions drained. v0.2 (data layer) breakdown now being drafted by Codex on feat/v0.2-data-layer. PR #5
Edge-routing spike passed — PR 004 merged (287f881); task 005 started. PostHog /ingest proxies live (real PostHog responses, SDK served first-party), redirects fire before RR7 routes, apex→www rule staged for cutover. Live-caught defect: Vercel ':path*' misses trailing slashes — /ingest/e/ 404'd until switched to '(.*)' captures. Task 005 (CI workflow, husky pre-push, Vitest + smoke floor) closes v0.1.
Merges delegated; PR 003 merged; task 004 started. Moe: "Merge and don't wait for me" — recorded in the Decisions log. PR 003 squash-merged locally as 95759d1 under Moe Ghashim <mohanadgh@gmail.com> (GitHub API squash stamps the wrong identity, so merges are local from now on). Task 004 is the last platform spike: PostHog /ingest reverse proxy + representative redirects (incl. apex→www rule) coexisting with React Router on Vercel.
Caching spike passed — PR 003 approved. CDN caching proven cookie-free on Vercel (MISS→HIT, identical timestamps). Real find: Hydrogen 2026.4 forwards Shopify tracking cookies onto every document by default, silently defeating CDN caching — disabled (matches production behavior; revisit pinned to v0.7). TTL matrix: catalog 15-min staleness + 24h SWR; cart private/no-store; /api/revalidate stays at its path as a secret-guarded no-op. Awaiting merge. PR #3
PR 002 merged (by Claude, on Moe's instruction) — task 003 started. Caching spike: named Cache-Control policies (catalog TTL/SWR within the ≤15-min staleness budget, cart private/no-store), a cache-demo route to prove MISS→HIT on Vercel's CDN, the TTL matrix mapping the old cache tags, and the /api/revalidate disposition decision.
Vercel adapter spike PASSED — PR 002 approved. A Vercel deployment of the new project server-rendered a live product ("Zaitoune Baklava With Honey 500g") from the Storefront API 2024-10 and streamed the deferred chunk ~228ms later. R1 retired. One finding carried to v0.7: Hydrogen's built-in POST Storefront proxy fails on Node (duplex) — documented with remedies. Awaiting Moe's merge. PR #2
PR 001 merged by Moe — task 002 started. The Vercel adapter spike is running: Codex wires vercelPreset() + createHydrogenContext(), then the runner creates the new babanuj-hydrogen Vercel project (separate from production) and must prove live Storefront SSR + streaming on a preview URL. This is the R1 abort-criterion task.
PR 001 approved. Codex applied both review fixes (branch-naming scheme corrected to the hyphen form in AGENTS.md, node engines widened to ^22 || ^24); re-verified on origin, typecheck + build still green. Mergeable — waiting on Moe to squash-merge, then task 002 (Vercel adapter spike) begins. PR #1
PR 001 opened and reviewed — changes requested. Scaffold verified independently (build, typecheck, dev-server 200; Hydrogen 2026.4.4 + RR 7.16 pinned; no Oxygen config; commits authored Moe Ghashim + DCO). Two findings sent back to Codex: AGENTS.md documented a git-impossible branch scheme (slash under an existing branch ref → amended to hyphen), and node engines should allow ^24. PR #1
v0.1 breakdown approved; task 001 started. Codex produced 5 task files matching PLAN.md §9 with acceptance criteria intact — approved after independent verification (commits authored Moe Ghashim + DCO, protected paths untouched). Repo pushed to GitHub. Notes: executor model is gpt-5.6-terra (gpt-5.6/sol rejected on this ChatGPT plan; Decisions log updated), and Codex's sandbox can't write .git, so the runner performs commits/PRs with Codex-authored content verbatim.
Phase 2 handoff fired. Private repo moeghashim/babanuj-hydrogen created on GitHub; Codex (gpt-5.6 @ medium) invoked to generate the v0.1 task breakdown under dev/milestones/. It stops for review before any code.
Plan signed off by Moe. All defaults locked (bespoke shopifyFetch, API 2024-10, @vercel/og, CDN-TTL caching, Vercel-alias staging, 2-week soak). PLAN.md status → LOCKED.
Plan drafted. Codebase inventoried (17 pages, 8 handlers, 51 components), Hydrogen-on-Vercel research returned conditional GO, 44 tasks across 9 milestones written to PLAN.md. Awaiting Moe's sign-off — nothing handed to Codex yet.