Sprint 12 (commit 11b4595) wires the "Search the web" toggle on
/recipes to Spoonacular complexSearch, with a per-result Import
button that pulls the full recipe info (1 point) and writes a
local Recipe row. No pre-existing WIP files touched.
This commit updates the 6 running docs that track the sprint:
- .agent/plan.md — Sprint 12 section (S12.1-S12.5) added.
- .agent/context.md — Sprint 12 (D1-D9, Q1-Q3) added; file:line
references; key takeaways.
- Review/sprint12-verification.md — new file: 4-step browser
smoke + 2 API curls + quota test + a11y check + 5-risk table
+ future work section.
- Review/ui-nielsen-audit.md — Sprint 12 status block (T6.1-T6.5)
at the top, after the Sprint 11 block.
- fix-ui-audit.md — Sprint 12 section (T6.1-T6.6) added after
the Sprint 11 section, including the D-fix for the 5
pre-existing tsc errors.
- Review/handoff-ui-audit.md — Batch H added to the deploy
instructions; Sprint 12 section added after Sprint 11; TL;DR
table row 12 added; Last-updated footer updated.
- docs/HANDOFF.md — Sprint 12 section added after the Sprint 11
section, with a D-fix paragraph and a path-forward paragraph
for F9.
All 6 docs now reflect Sprint 12. §Future backlog remaining: F9
(Ollama local LLM) — a full backend proposal that plugs into the
same handleGenerateFirstPlan (Sprint 11) + recipe_search.import
(Sprint 12) seams.
Sprint 11 (commit 41154e9) wires the previously-dead
"Generate Meal Plan" empty-state CTA on the Dashboard to two
existing endpoints (POST /api/meals + POST /api/meals/{id}/fill-
empty-slots). No backend changes; no new dependencies. The
handler lives on the client for now; future F8 (Spoonacular) +
F9 (Ollama) will swap the fillEmptySlots call for an LLM call
without changing the DOM. F8 + F9 remain in the §Future backlog.
This commit updates the 6 running docs that track the sprint:
- .agent/plan.md — Sprint 11 section (S11.1-S11.3) added.
- .agent/context.md — Sprint 11 (D1-D6, Q1-Q3) added; file:line
references; key takeaways.
- Review/sprint11-verification.md — new file: 4-step browser
smoke + race test + 2 API curls + a11y check + risks + future
work section.
- Review/ui-nielsen-audit.md — Sprint 11 status block (T5.1-T5.3)
at the top, after the Sprint 10 block.
- fix-ui-audit.md — Sprint 11 section (T5.1-T5.5) added after the
Sprint 10 section.
- Review/handoff-ui-audit.md — Batch G added to the deploy
instructions; Sprint 11 section added after Sprint 10; TL;DR
table row 11 added; Last-updated footer updated.
- docs/HANDOFF.md — Sprint 11 section added after the Sprint 10
section, with a path-forward paragraph for F8/F9.
All 6 docs now reflect Sprint 11. §Future backlog remaining: F8
(Spoonacular) + F9 (Ollama) proposals, both full backend work.
Sprint 9 (commit 6e386ba) shipped a working OnboardingTour but a
broken dismiss path: clicking X / Skip / Esc / "Got it" did
nothing. Root cause: useOnboarding().reset() was wired to the
dismiss handler at App.tsx, but reset() does the inverse of
dismiss — it clears the localStorage key and flips isComplete to
FALSE, so the tour re-rendered, the early-return did not fire,
and the dialog stayed visible. Fix: commit 1562929 split the
dismiss and reset paths into two distinct callbacks (onComplete
and onReset). User confirmed browser smoke passes.
This commit updates the 6 running docs that track Sprint 9:
- .agent/plan.md — S9.4.1 sub-task (post-deploy fix) added.
- .agent/context.md — D9 (root cause + fix) + Q4 (Vitest?) added.
- Review/sprint9-verification.md — full post-deploy fix section
appended (root cause, fix, post-fix verification, lessons).
- Review/handoff-ui-audit.md — Sprint 9 status banner + Last
updated footer updated to reference the fix commit.
- fix-ui-audit.md — T3.4.1 sub-task added under the T3.4
verification gate.
- docs/HANDOFF.md — post-deploy fix paragraph added to the
Sprint 9 section.
All 6 docs now reflect the post-deploy reality. No code changes.
User-driven follow-up to Sprint 8: surface the Sprint 1-3 NeverSuggest
infrastructure on the Recipes surface so a family can pre-emptively
mark a recipe as never-suggest before it appears in a plan.
Backend (3 changes):
- POST /api/never-suggest (public, webui-facing). Idempotent on
(family, recipe, reason). Returns the row joined with recipe_name.
- DELETE /api/never-suggest/{ns_id} (public, webui-facing). Row-level
ownership check (403 if cross-family), 404 if absent.
- NeverSuggestRead.recipe_name + .ingredient_name server-side joins
via _attach_names() helper (one LEFT OUTER JOIN per kind).
- Admin path (POST/DELETE /api/admin/never-suggest) unchanged.
Frontend (4 changes):
- New NeverSuggestButton component (~290 lines). Two variants: card
(overlay on RecipeCard) and detail (text buttons in RecipeDetail
top bar). Popover with Allergy (red, window.confirm) + Dislike
(neutral, no confirm). Undo toast via showToast.undo() (Sprint 3
B12 pattern, 6s window). Pre-existing block detection shows a
Blocked state with an Unblock path.
- mealPlannerApi.neverSuggest.list/add/remove in api/index.ts.
- Recipes.tsx overlay: RecipeCard has position: relative; button is
opacity-0 group-hover:opacity-100 focus:opacity-100. e.preventDefault
+ e.stopPropagation prevents accidental navigation.
- RecipeDetail.tsx top bar: new Deny forever button group to the left
of Add to Plan.
Build: npm run build green (tsc 0 errors, vite 0 errors) on
docker-willester. Bundle 487 -> 495 kB. No new dependencies. No
migration (NeverSuggest table exists from prior sprints).
Tracking: Review/sprint10-verification.md (9-step browser smoke +
5 API curls + undo test + a11y check).
Hand-rolled 4-step tour (no react-joyride) anchors to existing
[data-tour="<id>"] attributes. localStorage key
mealplanner:onboarding-complete is the source of truth; ?reset-tour=1
clears the key and re-shows.
Steps: Dashboard / Pantry / Recipes / Shopping List. Keyboard: 1-4 jump,
←/→ step, Esc dismiss. Off-route fallback renders a centered card with
an 'Open <page>' CTA. A11y: role=dialog, aria-modal=true, focus captured
on open and restored on close.
5 lines of code across 4 pages; 1 new component (~420 lines). No new
dependencies. No backend changes. No migration. Frontend-only deploy.
Tracking: Review/sprint9-verification.md (8-step browser smoke + a11y
check + reset-link test).
User policy decision (2026-06-05, exact): 'Hard filter. If it is denied
this week twice, it should be considered denied for good.'
The planner had no cross-week memory of denials: a denial on
meal_plan_item.approval_status was never consulted by the planner,
and NeverSuggest (the per-family permanent blocklist) was empty for
the user. The 'Roasted Sweet Potato and Chickpea Bowl' the user
denied on 2026-05-15 was still in the planner's pool 3 weeks
later.
Implements C + Z (explicit two-button model + soft-decay +
hard-filter escalation):
- Approve: untouched.
- Deny this week (1st in 90d): denial_expires_at = now() + 90d.
- Deny this week (2nd in 90d, server-side auto-escalation):
denial_expires_at = NULL + a NeverSuggest row written.
- Never again (explicit): same as the 2nd-time auto-escalation.
Both soft and permanent denials are hard filters in the planner
(per user). A denied recipe never reappears until either the 90d
window expires or the user un-blocks via the NeverSuggest API.
Changes:
- Migration 0016: meal_plan_item.denial_expires_at (partial index)
and meal_plan_vote.denial_scope.
- 3 backend helpers (_apply_denial, _ensure_never_suggest_recipe,
_has_prior_active_soft_denial) — single source of truth for the
deny path.
- POST /api/meals/items/{id}/deny?scope=this_week|never_again
(default this_week). Returns promoted_to_permanent.
- POST /api/meals/vote/{id} extended: vote=approve|deny|never_again.
Returns denial_scope + promoted_to_permanent.
- GET /api/meals/vote/{id} HTML page renders 3 buttons; supports
one-click ?scope=... for email direct-action links.
- Email template (step_email): 3 direct-action links per recipe
plus a secondary 'open vote page' link.
- Planner: _load_blocklists returns 3 sets; soft_denied_recipes
is hard-filtered (union with blocked_recipes at the call site).
- Frontend: MealCard renders 3 buttons (Approve / Deny this week
/ Never again) for pending items. handleDeny is scope-aware;
toast reflects promoted_to_permanent. window.confirm on
'Never again' prevents accidental permanent blocks.
Verification:
- npm run build green.
- 21/21 planner tests pass (1 pre-existing test_filter_blocks_by_cost
failure is NOT introduced by Sprint 8 — verified via git stash).
- Review/sprint8-verification.md: 11-step browser smoke + 4 API
curls + email-render procedure + rollback.
Files:
- backend/alembic/versions/0016_denial_decay_and_scope.py (new)
- backend/app/models/__init__.py:221-242, 250-269
- backend/app/schemas/__init__.py:204-219, 248-269
- backend/app/api/meals.py:30-138 (helpers), 240-330 (HTML page),
380-455 (submit_vote), 486-552 (deny_meal_item)
- backend/app/services/orchestrator/steps.py:283-300
- backend/app/services/planner/generate.py:59-99, 150-194
- frontend/src/api/index.ts:48-58
- frontend/src/pages/Dashboard.tsx:38-50, 385-410
- Review/{sprint8-verification,ui-nielsen-audit,handoff-ui-audit}.md
- fix-ui-audit.md
- docs/HANDOFF.md
- .agent/{plan,context}.md
Deploy (user runs on deployment host):
cd ~/MealPlanner && git pull
docker compose exec backend alembic upgrade head
docker compose -f docker-compose.yml up -d --build backend frontend
User report 2026-06-05: 'webui Meal Planner page is empty' on Friday
morning after the Friday email went out. Root cause: the orchestrator
keyed plans by the most-recent-Friday while the frontend's isoMonday()
returned the most-recent-Monday — a 7-day mismatch on Fridays.
Fixes (one semantic across the stack):
- runner._current_week_start() returns the upcoming Monday (today if
Mon, else the next Mon). The Friday email subject
('Meal plan for week of <date>') automatically picks up the new
value via run.week_start_date.
- frontend isoMonday -> upcomingMonday (same logic; renamed for
intent). isoMonday kept as a deprecated alias.
- New WeekRangeNav component (Dashboard + ShoppingList share it).
Renders [<] Jun 8 - Jun 14 [>] with clickable chevrons and a
clickable range label that jumps to the upcoming week. Replaces
the Sprint 5 inline segmented control on both pages.
- New formatWeekRange(mondayIso) helper (UTC-stable; uses
timeZone: 'UTC' so the rendered date matches the stored ISO date
regardless of viewer TZ; closes a latent bug in formatIsoDate too).
- New SQL fix script that retargets the user's 3-pending-items plan
from 2026-06-05 (Friday-keyed) to 2026-06-08 (upcoming Monday).
Idempotent + transaction-wrapped. Optional block for 2026-05-29.
No backend migration. No new dependencies. Deploy is git pull +
run the SQL fix + docker compose up -d --build backend frontend.
See Review/sprint7-verification.md for the full deploy + smoke flow.
Files:
- backend/app/services/orchestrator/runner.py:20-35
- backend/scripts/fix_2026_06_05_to_2026_06_08.sql (new)
- frontend/src/lib/utils.ts:43-130
- frontend/src/components/WeekRangeNav.tsx (new)
- frontend/src/pages/Dashboard.tsx (3 call sites + 1 segmented control)
- frontend/src/pages/ShoppingList.tsx (5 call sites + 2 segmented controls)
- Review/{sprint7-verification,ui-nielsen-audit,handoff-ui-audit}.md
- fix-ui-audit.md
- docs/HANDOFF.md
- .agent/{plan,context}.md
Sprint 6 (F3 + F4) is now documented across the project:
- Review/sprint6-verification.md: new deploy + smoke-check doc.
Backend + frontend deploy (no migration). 5 smoke-check
sections: A) ShoppingList bulk-add end-to-end, B) F3 partial-
failure edge case, C) F4 'Plan the week' button + dropdown,
D) F4 edge cases (no empty slots, all recipes used, invalid
meal_types), E) Sprints 1-5 regression spot-check. Rollback
section covers revert (no migration to undo).
- fix-ui-audit.md: new Sprint 6 section (S6.1 F3, S6.2 F4,
S6.3 verification gate). 'Done when' block updated to 6
sprints / 10 commits / 20 findings closed.
- Review/handoff-ui-audit.md: updated to a 6-sprint cycle. TL;DR
table includes the 8ad4ef6 row. File list includes sprint6-
verification.md. File-level diff summary gains 8 new rows for
Sprint 6 (F3 backend + F4 backend + 3 new schemas + 2 api
bindings + 2 page changes). §Future list now strikethroughs
F3 and F4. Follow-up tickets section added: the no-op
'Generate Meal Plan' empty-state CTA, the (now-narrower) Pantry
bulk-add ticket, and the 'Sprints 2-5 + Sprint 6 separate
batch' deploy note.
- Review/ui-nielsen-audit.md: new Sprint 6 status block at the
top. F3 + F4 documented with the design-decision context
(ShoppingList-only scope; dropdown for All/Dinners; partial-
success with detailed report).
- docs/HANDOFF.md: Last-updated line bumped to 6 sprints / 10
commits / 20 findings / 6 §Future items. Header commit list
gains the 8ad4ef6 row. New 'Sprint 6' subsection in the
2026-06-04 session block. Commit table gained the 8ad4ef6 row.
Files-modified + Files-added lists updated.
No code changes; the 3 pre-existing WIP files (backend/app/api/
recipes.py, schemas/recipe.py, nginx/nginx.conf) are deliberately
not staged.
Sprint 5 (F5 + F2 + 0015 cast fix) is now documented across the project:
- Review/sprint5-verification.md: new deploy + smoke-check doc.
Backend + frontend deploy (one batch with Sprints 2-4). Migration
0015 MUST be run as part of this deploy (the cast fix is what
makes it runnable). 7 smoke-check sections: A) curl tests for
?week_start=, B/C/D) URL week nav on Dashboard and Shopping List
with query-key isolation, E) keyboard shortcut matrix, F) post-
migration canonical-aisle verification query, G) Sprints 1-4
regression spot-check. Rollback section covers reverts + the
persist_aisle_backup recovery path.
- fix-ui-audit.md: new Sprint 5 section (S5.0 critical 0015 fix,
S5.1 F5 implementation, S5.2 F2 implementation, S5.3 verification
gate). 'Done when (overall)' block updated to 5 sprints + 9
commits + 18 findings closed + the 0015 fix unblocks Sprint 2.
- Review/handoff-ui-audit.md: updated to a 5-sprint cycle. TL;DR
table includes the d78bd18 + f740f40 rows with the CRITICAL 0015
fix callout. file-list includes the new sprint5-verification doc.
file-level diff summary gains 16 new rows (S5 backend + frontend +
0015 + hooks/components). §Future list now strikethroughs F2 and
F5. Quick-start deploy commands list Sprints 2-5 as a single
batch (backup → migrate → rebuild backend + frontend).
- Review/ui-nielsen-audit.md: new Sprint 5 status block at the
top. F5 + F2 + the 0015 fix all documented. Cross-ref to
Review/sprint5-verification.md.
- docs/HANDOFF.md: Last-updated line bumped to 5 sprints / 9
commits / 18 findings / with the 0015 fix CRITICAL callout.
Header commit list gains the two Sprint 5 commits. New 'Sprint
5' subsection in the 2026-06-04 session block. Commit table
gained the d78bd18 + f740f40 rows. Files-modified list now
includes all 5 sprints' changes. New 'Files added by Sprint 5'
subsection for the 3 new files in hooks/ + components/.
No code changes; the 3 pre-existing WIP files (backend/app/api/
recipes.py, schemas/recipe.py, nginx/nginx.conf) are deliberately
not staged.
Sprint 4 (F7 + F6) is now documented across the project:
- Review/sprint4-verification.md: new 100-line deploy + smoke-check
doc. Frontend-only deploy (git pull + docker compose up -d --build
frontend). 5 smoke-check tables: A) success toasts still work for
all 11 actions, B) error path shows FastAPI detail (network-down
is the easiest test; full Pydantic 422 verification via curl +
DevTools 'Edit and resend'), C) pre-flight toasts still fire
without a network call, D) plan-status Badge has correct
aria-label in DevTools, E) Sprint 1-3 regression spot-check.
Includes rollback instructions (single-commit revert).
- fix-ui-audit.md: new Sprint 4 section with full per-task notes
(S4.1 F7 implementation details, S4.2 F6 aria-label, S4.3
verification gate). 'Done when (overall)' block updated to 4
sprints + 7 commits + 16 findings closed. No new commit in
fix-ui-audit.md for the F8/F9 §Future addendum (those are noted
in Review/handoff-ui-audit.md but live in the doc/proposals/
tree, not in the UI-audit plan).
- Review/handoff-ui-audit.md: updated to a 4-sprint cycle. TL;DR
table includes the d71b67a row, file-list includes the new
verification doc, file-level diff summary gains 5 new rows for
Sprint 4, §Future list now strikethroughs F6 and F7, and the
Quick-start deploy commands list Sprint 4.
- Review/ui-nielsen-audit.md: new Sprint 4 status block at the
top with the F7/F6 changes, the no-backend-changes note, and
a cross-ref to the new verification log.
- docs/HANDOFF.md: Last-updated line bumped to 4 sprints / 7
commits / 16 findings. New 'Sprint 4' subsection in the
2026-06-03 session block. Commit table gained the d71b67a row.
Files-modified list gained the lib/toast.tsx, App.tsx, and
three pages changes for Sprint 4 (with B-tags preserved).
No code changes; the 5 pre-existing WIP files (backend/app/api/
meals.py, recipes.py, schemas/recipe.py, frontend/src/api/index.ts,
nginx/nginx.conf) are deliberately not staged.
- Update 'Last commits before handoff' list with the four UI-audit
commits (f3e4a44, ccc70aa, f5fb755, e90a9d6) plus the handoff doc
itself (427d8ac) and the docs commit (36038bb).
- Bump handoff date from 2026-05-14 to 2026-06-03 and add a cross-ref
to the focused Review/handoff-ui-audit.md so a fresh agent can
choose which doc to start with.
- New 'Last updated' line summarizes the UI-audit cycle (Sprint 1
deployed; Sprints 2 and 3 awaiting deploy; migration 0015 not yet
run on prod).
- Add a 'New session: 2026-06-03' section with the commit table, the
Sprint 2 deploy commands (including the container-based psql
incantations since the deployment host has no host psql), the
Tailscale dev-vs-deploy gotcha, the .gitignore/lib/ quirk, and the
file-level add/modify summary for the UI-audit work.
- Correct the 'Current open proposals' line under 'Final words' — the
feedback-driven discovery proposal still awaits user approval; it
is NOT implemented and verified.
- Update implementation-plan.md: mark unit conversion complete
- Update HANDOFF.md: add session notes for 2026-05-24 unit conversion
- Update README.md: list Unit Conversion as a feature
Backend:
- POST /api/ingredients now checks name_lower and aliases before inserting
- Returns existing ingredient on 409 instead of throwing error
Frontend:
- Removed fragile 409-recovery logic from Pantry.tsx handleAdd
- Added aliases field to Ingredient type for case-insensitive matching
Fixes pantry add for ingredients like 'Carrots' whose canonical name is 'Carrot'
Bring docs in line with the post-AM-6 state so a fresh agent can pick
up cleanly without first reconciling stale numbers:
- pytest count: 88/59/31 → 92 across all references
- live scrape: 9,960 rows / 36s → 9,980 rows / 44s (latest run, 2026-05-06)
- migrations applied: 0001-0005 → 0001-0007 in both docs
- verification gate updated with auto-minted JWT detail and the 29,779
ingredient_grocery_match rows produced post-scrape
- "What is real" / Backend: added swiftly_auth.py bullet describing
get_token() / mint_anonymous_token() / cache semantics + the
10,928-item live verification
- file map: added services/swiftly_auth.py, services/matcher.py,
services/planner/, mentioned scraper_service runs matcher post-scrape
- file map: alembic versions 0001 → 0007, tests/ count = 92, marked
config.py as no-longer-carrying SWIFTLY_BEARER_TOKEN
- spec map line for swiftly-token-auto-mint: "next-up" → "Implemented"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Breaks the auto-mint spec into 6 ordered, sized tasks with an explicit
halt-for-approval boundary at AM-2 (live scrape verification before
removing the env var). Restates the verified prerequisites (config.json
publicly readable; Firebase signUp returns valid JWT with proper headers;
Swiftly accepts the minted token) so a fresh agent doesn't have to
re-discover them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Discovery: luckysupermarkets.com/config.json is publicly readable and
exposes firebaseApiKey. With proper Origin/Referer headers, Firebase
Identity Toolkit's anonymous-signup REST endpoint mints the same JWT
shape (iss=swiftly-lu-prod, aud=swiftly-lu-prod, anon provider, 3600s
TTL) that Swiftly accepts. Verified end-to-end on 2026-05-06.
This eliminates the manual hourly token-capture toil and supersedes
the seleniumbase-based scripts/refresh_swiftly_token.py (commit
ccfb38a) which had partial UI selector issues.
- New spec: docs/specs/2026-05-06-swiftly-token-auto-mint.md
- HANDOFF.md TL;DR refreshed (Phase 9 shipped); caveat #2 + #3
rewritten to point to the auto-mint redesign; suggested-next-move
reordered to put the redesign first
- ORIENTATION.md env-var section flags SWIFTLY_BEARER_TOKEN as
scheduled-for-removal; "Where to look" lists both specs;
last-updated footer refreshed
Implementation deferred — this commit captures the design and routing
only. Estimated 2-3 hours of focused work to ship per the spec.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8-task TDD plan covering planner package (config, types, cost,
filter, score, select, generate orchestrator), generate/regenerate/
get endpoints, and end-to-end smoke test against seeded data.
Builds on the thin phase 4 plan; uses NeverSuggest for blocklists,
ingredient_grocery_match for sale-aware cost estimation, top-K=20
set enumeration with diversity penalty for protein/cuisine repeats.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15-task TDD plan covering migration 0006 (ingredient.aliases,
recipe.calories_per_serving, ingredient_grocery_match), CRUD endpoints
for ingredient/recipe/never-suggest, rapidfuzz matcher service hooked
into scrape success, manual match override, resolve-ingredient assist,
and migration 0007 seeding 30 starter recipes.
Reuses existing NeverSuggest table for ingredient + recipe blocking
rather than adding a new family_ingredient_block table.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures brainstorm decisions for the meal-planner algorithm and the
minimum recipe-engine surface needed to feed it:
- 6 hard constraints (blocklist, never_suggest, recency N=4, calories
+/-20%, time <=45min, cost <=$30)
- Top-K=20 set enumeration with diversity penalty for protein/cuisine
- Ingredient<->grocery_item matching as a cacheable layer (rapidfuzz +
manual override) rather than per-run fuzzy work
- Thin phase 4: recipe CRUD, ingredient CRUD, resolve-ingredient
assist, manual match override, match job, 30-recipe seed
- Recipe ingestion source pros/cons (TheMealDB + Spoonacular + manual)
documented; decision deferred until phase 4 + phase 9 work end-to-end
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updates ORIENTATION.md and HANDOFF.md to reflect actual state as of
commit 8e89f79: phases 1/2/3/7 complete (verified, not just claimed),
phases 4/5/6/8/9/10/11 not started. Documents the auth model, the
bootstrap login hatch, the SWIFTLY_BEARER_TOKEN expiration handling,
the Swiftly JSON API ingestion path that replaced Playwright, the
canonicalized API paths, and the verification commands to reproduce
the 31/31 pytest gate locally and in CI.
HANDOFF.md is intended for fresh agents and points at .agent/
phase-summaries for the per-phase write-ups. Surfaces 10 caveats and
traps the next agent will hit if they skim, and recommends Phase 9
(meal-planner generation algorithm) as the next move.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>