Skip to content

Design redesign (dark-first) — long-lived integration PR#89

Draft
zwrose wants to merge 256 commits into
mainfrom
claude-design-redesign
Draft

Design redesign (dark-first) — long-lived integration PR#89
zwrose wants to merge 256 commits into
mainfrom
claude-design-redesign

Conversation

@zwrose
Copy link
Copy Markdown
Owner

@zwrose zwrose commented May 28, 2026

Long-lived draft integration PR for the dark-first redesign migration. Lands surface-by-surface in chunks; stays in draft until the final squash merge into main.

  • Spec: docs/superpowers/specs/2026-05-28-design-redesign-migration-design.md
  • Progress ledger: docs/superpowers/plans/redesign-progress.md
  • Design bundle: docs/design/weekly-eats-redesign/

Per-chunk manual-test checklists are posted as their own slot comments (from Chunk 2 onward).

Chunk 1 — Foundation

Dark-first token + theme + typography + icon foundation; light mode dropped (plumbing preserved); one-time redesign setup.

  • src/lib/design-tokens.ts — canonical dark tokens
  • src/lib/theme.ts — single dark MUI theme bridging tokens + custom palette keys/typography variants (src/types/mui.d.ts); responsiveDialogStyle preserved; tabular-nums applied app-wide
  • Fonts: Bricolage Grotesque + Outfit via next/font; Material Symbols via stylesheet <link> (next/font lacks the face)
  • src/components/ui/Icon.tsx — decorative-by-default Material Symbols icon (real SxProps)
  • Light-mode removal: theme-context always-dark, ThemeColorMeta hard-dark, Settings → placeholder
  • One-time setup: CI branch trigger, review-code --base override, Vercel beta deployment

Existing screens render with new tokens/fonts (rough/mixed look interim — expected; surfaces land in later chunks). Server-side approval enforcement is handled separately.

🤖 Generated with Claude Code

zwrose and others added 21 commits May 28, 2026 13:55
…t allowlists (Chunk 0c)

Pre-redesign security hardening surfaced by the audit sweep, behavior-
preserving for legitimate clients:

- Critical: /api/ably/token had no auth check and minted a wildcard-
  capability token, letting any caller subscribe to any store's
  shopping-store:<id> channel (cross-user data leak). Now requires a
  session and scopes capability to the user's owned + accepted-invitation
  stores (subscribe+presence only; server still publishes via the API key).
- ObjectId.isValid guards on meal-plans/[id] (GET/PUT/DELETE),
  food-items/[id] (PUT/DELETE), and admin approve/toggle-admin body userId
  — malformed ids now return 400 instead of 500.
- Mass-assignment allowlists: recipes/[id] PUT no longer spreads the raw
  body into $set (blocks createdBy/createdAt/_id injection; isGlobal stays
  client-settable as the recipe-sharing mechanism); user/settings POST
  writes only themeMode + defaultMealPlanOwner via dot-notation, so a
  crafted body can't forge sharing-invitation grants.

Adds regression tests for each, including a new ably/token test file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Backfill behavior-preserving tests for the untouched data layer, per the
audit sweep — golden-master for pure transforms, MSW path coverage for
fetch wrappers, and 401/400/ownership/500 coverage for the sharing/store
API routes.

Utils (lib):
- meal-plan-utils: golden-master for findNextAvailableMealPlanStartDate
  skip-advance loop + checkMealPlanOverlap edge cases (vi.setSystemTime)
- shopping-list-position-utils: new (pure position math + MSW)
- shopping-list-utils: cover all remaining fetch wrappers (MSW)
- recipe-sharing-utils, meal-plan-sharing-utils, recipe-user-data-utils: new MSW
- recipe-utils, pantry-utils: new (array/paginated normalization)
- user-utils: getCurrentUserAdminStatus; date-utils: day/next-day arms;
  auth.ts: redirect/session/jwt callbacks

API routes (14 sharing/store routes, previously untested):
- stores/[id], stores/[id]/invite, stores/[id]/invitations/[userId],
  stores/invitations, shopping-lists/[storeId]/positions
- user/meal-plan-sharing/* and user/recipe-sharing/* (invitations,
  invitations/[userId], invite, owners, shared-users)

Full suite: 1304 tests across 125 files, green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
review-code (base main) returned READY FOR PR (0 Critical/Important).
Applied the informational Minor/Nit fixes that harden Chunk 0's own work:

- meal-plans/[id] invalid-id guard returns API_ERRORS.BAD_REQUEST (was a
  "not found" message with a 400 status) — consistent with food-items/[id]
- auth.test: add jwt happy-path + missing-user coverage (was catch-path only)
- meal-plan-sharing invitations/[userId]: assert the $pull filter/shape on
  owner-remove and self-leave (was bare toHaveBeenCalled)
- recipe-sharing tests: drop no-op collection name-branching

npm run check green: 1306 tests, lint clean, build OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Chunk 0 closed (tag redesign-chunk-00). Next up: Chunk 1 Foundation.
Records the green baseline, audit disposition, and the #76/#83 carryovers
for Chunk 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Chunk 0 hardening shipped to main via PR #87 and back-merged into this
branch. Server-side approval (#83) is being handled on its own branch, so
Chunk 1 verifies it via main rather than re-implementing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Chunk 1

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hemeChange wiring

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…m Providers

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ree + light theme dep

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removes theme Select, defaultMealPlanOwner dropdown, and dead
window.dispatchEvent(themeChange) coupling. Route stays; renders
"Nothing to settle right now — light mode will return." placeholder.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cope icon-font lint disables)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
weekly-eats Ready Ready Preview, Comment Jun 5, 2026 2:43am

Request Review

…rred

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rrides)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zwrose
Copy link
Copy Markdown
Owner Author

zwrose commented May 28, 2026

Manual Test Plan — chunk-01-foundation

Validate locally — localhost + the local dev DB (mongodb://localhost:27017/weekly-eats-dev). This is the chunk gate (per spec §5). The beta deploy is a separate parallel dogfooding path and is not what you validate here.

Setup applied via npm run test:manual:apply claude-design-redesign chunk-01-foundation (seeded to your local dev DB, attached to zwrose@gmail.com):

  • food items — apple, bread, egg, milk + 6 global + 3 user-owned (food-items)
  • 4 user recipes with star ratings + tags (recipes)
  • 5 pantry items (pantry)
  • 2 stores with item positions (stores)
  • a partial shopping list — 5 items, ~2 checked (shopping-list)
  • 3 purchase-history records (purchase-history)
  • 1 unapproved user "Beta Gate Test (unapproved)" for the approval/admin surfaces (pending-approval-user)
  • (your zwrose@gmail.com already has a real meal-plan template + plans, so /meal-plans has content too)

Pre-flight

  • Confirm .env.localMONGODB_URI=mongodb://localhost:27017/weekly-eats-dev (local, not prod). It is.
  • Start the app: npm run dev → open the URL it prints (default http://localhost:3000).
  • Sign in with Google as zwrose@gmail.com (the seeded data is attached to this account) → you should land on /meal-plans.

A. Global dark theme + fonts

  • A1 — Dark surfaces. On /meal-plans, the page background is near-black (#0f1115) and cards / the top bar are dark charcoal (#181b21). Nothing renders on a white/light background.
  • A2 — No light flash. Hard-refresh (Cmd-Shift-R). There is no flash of a light/white theme before dark paints.
  • A3 — Display vs body fonts. Page titles/headings render in Bricolage Grotesque (geometric display face); body text + labels render in Outfit. (Quick check: DevTools → Network → filter font → you should see Bricolage + Outfit served by next/font, and a request to fonts.googleapis.com for Material Symbols Outlined.)
  • A4 — Tabular numerals. Find two numbers with different digits (e.g. the recipe count on /recipes vs a quantity, or stacked quantities in the shopping list) — the digits are monospaced and line up in columns (tabular-nums), not proportional.
  • A5 — Status-bar color (optional). DevTools → Elements → <head> contains <meta name="theme-color" content="#0f1115">.

B. Each surface renders dark (visual shell only — full per-surface redesign comes in later chunks)

  • B1 — /meal-plans. Your real plan/day data renders dark + readable; primary buttons use the plans-blue accent (#7aa7ff). No broken/white panels. (Don't expect the Chunk-3 layout yet — just dark + legible.)
  • B2 — /recipes. The 4 seeded recipes show as dark rows. Star ratings render gold (#f0c674 filled stars); tags are visible. Open one recipe → the view is dark. Recipe count is tabular.
  • B3 — /shopping-lists. Two stores present; one has a partial list. Checked vs unchecked items are visually distinguishable on dark; quantities are tabular.
  • B4 — /pantry. The 5 seeded pantry items render as a dark flat checklist, readable.
  • B5 — /food-items. Seeded items (apple/bread/egg/milk + global + user) render dark; Private/Shared chips are legible. Click + Add → the add dialog opens dark (visual only — don't save unless you want a real item).
  • B6 — Icons not broken. Most in-app icons are still the old @mui/icons-material SVGs — this is expected (icon call-site migration happens in later chunks). Just confirm no missing/garbled icon glyphs anywhere.

C. Settings placeholder + light-mode removal

  • C1 — Reach settings. The current (old) top nav still has a Settings link (the nav rewrite is Chunk 2) — click it, or go directly to http://localhost:3000/settings.
  • C2 — Placeholder only. /settings shows a dark card titled "Settings" with the text "Nothing to settle right now — light mode will return." There is no theme dropdown and no default-meal-plan-owner dropdown.
  • C3 — No theme toggle anywhere. Confirm there is no light/dark toggle in the app — it's dark-only now.

D. Server-side approval gate — REMOVED from this chunk (now owned by #83)

The interim server-side approval gate was reverted from the redesign branch (commit 3004858). Prod and beta share the same prod DB + client-only gating, so a beta-only gate added no incremental protection while duplicating the dedicated #83 effort (fix/83-unapproved-users-access-issue), which is more complete (middleware + requireApprovedSession() + per-route enforcement) and lands for prod and beta via main → back-merge. Skip the gate verification here — it belongs to #83's own test plan.

  • D1 — Admin surface renders (visual only). /user-management shows the seeded "Beta Gate Test (unapproved)" user in the pending list, rendered dark. (Just confirms the surface themes correctly — full redesign is Chunk 8.)
  • D2 — Client gate mount locked (automated). AuthenticatedLayout.test.tsx asserts the client useApprovalStatus mount survives, so Chunk 2's layout rewrite can't silently drop it. No manual step.

E. Destructive-path smoke (optional — data layer is unchanged this chunk)

  • E1. Toggle a shopping-list item checked→unchecked→checked; add then remove a pantry item. Confirm they still work and render dark. (No write-logic changed in Chunk 1; this is just a sanity smoke.)

Cleanup

npm run test:manual:clean claude-design-redesign chunk-01-foundation

Generated by /manual-testing for Chunk 1 (Foundation). Re-run to update. Validate on localhost + local dev DB — beta is a separate dogfooding path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zwrose and others added 3 commits June 1, 2026 08:51
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Recipes/Food items labels were both emitted up-front, stacking them at
the top of the list above every row instead of "Food items" sitting before
the first food row. Dormant in pantry (allowRecipes=false → no labels);
surfaced when recipes became the first allowRecipes consumer. Render each
label inline before its group's first row; lock the order with a test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A list-above dropdown grows upward in flow, pushing the input DOWN the page;
with the soft keyboard up on a phone, the input lands behind it. On phone
widths, force list-below so the input stays pinned (results grow downward,
away from it) and seat the field near the top of the scroll area on focus so
results have room above the keyboard. Desktop keeps the upward dropdown.

A richer full-screen mobile search-sheet treatment is deferred (own artboard).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zwrose and others added 3 commits June 2, 2026 21:52
The field used list-above on desktop, so the input visibly jumped down when
results loaded. Switch to list-below: the input stays pinned and results open
beneath it (matches the mobile behavior, which already forces list-below).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ws the viewport

A list-below field low on the page opens its dropdown past the bottom of the
viewport. On desktop, when the list opens (or grows as results arrive), scroll
the field+results box fully into view if its bottom is below the fold — guarded
so it's a no-op once visible (no scroll-on-every-keystroke), with a 16px
scroll-margin so it lands with breathing room rather than flush to the edge.
Phones keep the focus-time scroll. Locked with a test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Set the viewport interactive-widget to resizes-visual so the soft keyboard
overlays content instead of resizing the layout viewport. The fixed bottom nav
(position:fixed; bottom:0) then stays pinned to the screen bottom under the
keyboard rather than riding up above it. App-wide; browsers still auto-scroll
the focused input into the visual viewport so inputs stay reachable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zwrose and others added 2 commits June 3, 2026 07:33
The desktop scroll-into-view effect's deps are complete, so the
react-hooks/exhaustive-deps disable directive was unused — and
eslint --max-warnings=0 fails on unused directives. Remove it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The interactive-widget=resizes-visual meta did not stop the fixed bottom nav
from riding up with the keyboard on-device, so revert it (back to the default
viewport) and handle the nav deterministically instead: hide it whenever a text
field is focused (keyboard up), keying off focusin/focusout. Works regardless of
how a browser treats the virtual keyboard (resize vs. overlay).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keying the bottom-nav hide off input focus left it stuck hidden: a user can
dismiss the keyboard (back gesture / down-chevron) while the field keeps focus,
so focusout never fires and the nav stayed invisible until a blur (dialog close
/ refresh). Switch to the VisualViewport API — the viewport shrinks when the
keyboard slides up and grows back when it slides down, independent of focus.
Hide when it compresses past a 150px threshold vs. its tallest seen height;
reappear as soon as it grows back.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…iles

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zwrose and others added 2 commits June 3, 2026 08:33
…on to a + Group affordance

Retire the hand-rolled CombinedSearch combobox in the meal editor and migrate
MealEditorDialog onto the shared ItemSearchField (allowRecipes, list-below).
The create-food flow (useFoodItemCreator + AddFoodItemDialog) moves into the
dialog; onItemCreated routes the new food through addLooseFood so it lands in
the active search-target group. The combobox's in-dropdown "new group" option
is replaced by a caller-owned + Group button (recipes-aligned) that appends an
empty untitled group and auto-targets it via the existing pendingTargetRef
machinery. CombinedSearch + its test are deleted; the combobox interaction is
locked in the ItemSearchField suite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Phase 4

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zwrose and others added 2 commits June 4, 2026 22:03
…e shared field; drop FoodItemAutocomplete

Extend the shared ItemSearchField with an opt-in retain-on-pick mode
(clearOnPick=false) plus a showSelection() imperative handle, then migrate
the shopping ItemEditorDialog onto it as a single-select form. Default
clear-on-pick behavior is unchanged, so pantry/recipes/meal-plans are
unaffected (their suites pass). Deletes the orphaned FoodItemAutocomplete.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…done

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zwrose
Copy link
Copy Markdown
Owner Author

zwrose commented Jun 5, 2026

Manual Test Plan — item-search-field

Branch: claude-design-redesign | Manifest ID: claude-design-redesign.item-search-field

Seeded docs live in the shared dev DB and are name-stamped [claude-d·item-search-field] — look for that prefix to identify the store/recipes belonging to this plan. Seeded food items (searchable everywhere): avocado, asparagus, almond butter, basmati rice, black beans, blueberries, cilantro, coconut milk, extra firm tofu, sweet potato. The first few (avocado, asparagus, …) are pre-loaded into the seeded pantry and shopping list so you can exercise the "already added" exclusion.

Setup applied via npm run test:manual:apply claude-design-redesign item-search-field:

  • 10 food items ensured (food-items)
  • 4 recipes, user-scoped, with ratings/tags (recipes)
  • 4 pantry items (pantry)
  • 1 store with item positions (stores)
  • 1 shopping list — partial, 4 items, 2 checked (shopping-list)

Scope: this plan covers the shared ItemSearchField combobox and all four surfaces it now powers — pantry, recipes, meal-plans, shopping — across desktop (≈1440) and mobile (≈430). Run each section at both widths (resize the window or use device emulation). 📱 marks mobile-only checks.

Steps

A. Shared combobox — quick sanity (do once on desktop, e.g. via Pantry → Add)

  • Results appear after a short debounce as you type; the first result is highlighted and shows a single hint on its right (never two hints at once).
  • ↓ / ↑ move the highlight; Enter activates the highlighted row; hovering a row moves the highlight to it.
  • Esc (or clicking away / blurring the input) dismisses the results list; the field is otherwise unaffected.
  • The results render below the input on every surface (desktop and mobile).

B. Pantry — Add to Pantry (PantryAddDialog) · single add + close

  • Desktop: Pantry → open the Add dialog. The search field is auto-focused; results open below it.
  • Type avo → pick Avocado (Enter or click) → it's added to the pantry and a confirmation toast appears clear of the top nav; the dialog behaves per its single-add flow.
  • Reopen Add → type an item already in your pantry (e.g. avocado / asparagus, seeded) → the row is greyed and labeled "Already in pantry", is not clickable, and arrow-nav skips it.
  • Type a brand-new name (e.g. zzgadget) → the "Add "zzgadget" as new food item" row appears → click it → the Add Food Item dialog opens prefilled with that name. (Cancel to avoid creating junk, or complete it and confirm the new item lands in the pantry.)
  • 📱 Mobile (430): repeat the add flow. As you type with the soft keyboard up, the search input stays visible above the keyboard (results grow downward, never pushing the input off-screen).
  • 📱 While the keyboard is open, the bottom navigation bar is hidden; it reappears when the keyboard dismisses.

C. Recipes — ingredient editor (RecipeIngredientsEditor) · multi-add, recipes allowed

  • Desktop: open Manual Test Recipe [claude-d·item-search-field] 1Edit recipe. The "Add ingredient or recipe…" field shows the recipes accent (orange) and opens below.
  • Type b (or co) → results show a RECIPES section (rows with an emoji) above a FOOD ITEMS section; each section label sits directly above its group (labels are NOT stacked together at the top).
  • Pick a food item → appended as an ingredient row with quantity + unit chips; the field clears ready for the next add (multi-add).
  • Pick a recipe (sub-recipe) → appended showing × qty, no unit chip; field clears.
  • Search for an ingredient already in this recipe → it's marked excluded and can't be re-added.
  • Type a new name → "Add … as new food item" → create it → the new item is appended to the current group (it must not silently vanish).
  • Click + Group → a new group card appears. Add an item into it. With two groups present, focus one group's add-field and confirm only that group's dropdown is open (the other group's list stays closed).
  • With the editor scrolled so the field is low in the viewport, open the list → confirm the page scrolls the field + results fully into view (nothing clipped past the bottom).
  • 📱 Mobile: repeat in the recipe editor — list opens below, input stays above the keyboard, bottom nav hidden while typing.
  • Discard (don't save) unless you intend to keep the edits.

D. Meal plans — meal editor (MealEditorDialog) · multi-add + groups

  • Desktop: open your current-week meal plan → Add dinner (or edit a meal). The "Add item or recipe…" field shows the plans accent (blue), opens below, with a + Group button just above it.
  • Type a query → RECIPES + FOOD ITEMS sections render. Pick a recipe → added as a loose item (× qty chip, no unit); pick a food → added with qty + unit. Field clears after each.
  • Click + Group → an empty, untitled group appears and becomes the "Adding to: …" target; Done is disabled while the group has no title.
  • Give the group a title, then search + pick an item → it lands inside that group (qty + unit). Click × / "Stop adding to group" (or click empty space in the body) → adds return to loose.
  • Use the "Add … as new food item" row while a group is targeted → the created item routes into that group.
  • Remove group → confirm dialog names the item count → group + its items are removed.
  • 📱 Mobile: repeat in the bottom-sheet editor — results open below, input above the keyboard, bottom nav hidden while typing; + Group and targeting work the same.

E. Shopping — Add / Edit item (ItemEditorDialog) · single-select, retain-on-pick (new behavior)

  • Desktop: Shopping → open the store Manual Test Store [claude-d·item-search-field] 1Add item. The dialog shows a FOOD ITEM label, the search field (shop accent, green), and Quantity / Unit below. Add is disabled (nothing selected yet).
  • Type avo → results appear inline below the input (no floating popup). Pick Avocado → its name stays in the field, the list closes, and Add becomes enabled. ✅ This is the new retain-on-pick behavior.
  • Now type a different term (e.g. ban) → the list reopens and Add disables again (the previous selection is dropped — guards against saving a stale item while the box shows a different word). Pick a new item to re-enable Add.
  • Set Quantity / Unit, then Add → the item is added to the store's list.
  • Open Edit on an existing list row → the dialog opens with the field pre-filled with that item's name and its qty/unit, and shows Remove from list.
  • Search for an item already on this list (e.g. avocado / asparagus, seeded onto the list) → it's marked "Already on list" and can't be picked.
  • Type a brand-new name → "Add … as new food item" → create it → the new item becomes the selection (its name fills the field) → Add commits it.
  • 📱 Mobile: repeat at 430px in the full-screen sheet — inline results below, retain-on-pick name display, Quantity/Unit, and a sticky Cancel / Add bar at the bottom; input stays above the keyboard.

F. Regression sweep (no behavior should have drifted on the three "clear-on-pick" surfaces)

  • Pantry, Recipes, and Meal-plans still clear the field after each pick (only Shopping retains the name). Shopping is the only single-select surface.
  • No JavaScript errors in the console while searching / picking / creating on any surface.

Cleanup

npm run test:manual:clean claude-design-redesign item-search-field

Generated by /manual-testing. Re-run to update.

…wiring

Restores coverage lost when CombinedSearch (+ its test) was deleted in the
ItemSearchField migration. Mocks useFoodItemCreator to capture onItemCreated,
invokes it with a new food item, and asserts it routes into the meal as a loose
item — the load-bearing wiring whose absence would silently drop created items.
From /review-code finding test-001.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Seeds food items, recipes, pantry, a store, and a partial shopping list for the
cross-cutting ItemSearchField manual test plan (posted to PR #89). Mirrors the
existing per-chunk manifests; tagged to its own slot so cleanup is isolated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

recipe link opens web view instead of staying in PWA UI overhaul

1 participant