Commit Graph

131 Commits

Author SHA1 Message Date
c8f348621f Speed up tests. 2025-12-31 20:08:20 +00:00
768a3e4352 feat: redesign navigation with responsive sidebar
- Simplify bottom nav from 6 to 4 items (Eggs, Feed, Move, Menu)
- Add persistent sidebar on desktop (hidden on mobile)
- Add slide-out menu drawer on mobile
- Rename Egg to Eggs with Harvest/Sell tabs (matching Feed pattern)
- Redirect /sell to /?tab=sell for consistency
- Role-gate Admin section (Locations, Status Correct) in sidebar
- Add user badge to sidebar showing username and role

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 19:45:39 +00:00
c6a87e35d4 feat: complete CLI, Docker & deployment docs (Step 10.3)
- Add comprehensive CLI tests for seed and serve commands
- Create README.md with development setup, deployment guide,
  and environment variable reference
- Mark Step 10.3 as complete in PLAN.md

This completes the final implementation step.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 18:21:14 +00:00
49871f60c5 docs: mark Step 10.2 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 17:50:08 +00:00
229842fb45 feat: implement location events & error handling (Step 10.2)
- Add LocationService with create/rename/archive methods
- Add LocationProjection for event handling
- Add admin-only location management routes at /locations
- Add error response helpers (error_response, error_toast, success_toast)
- Add toast handler JS to base template for HX-Trigger notifications
- Update seeds.py to emit LocationCreated events per spec §23
- Archived locations block animal moves with 422 error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 17:48:16 +00:00
5ba068b36a feat: implement E2E tests #1-5 (Step 10.1)
Add comprehensive E2E acceptance tests for stats progression:
- Test #1: Baseline eggs/feed/costs with 13 ducks
- Test #2: Mixed group proration with juveniles
- Test #3: Split flock per-location stats
- Test #4: Backdated eggs use historical roster
- Test #5: Event edit with revision tracking

Tests use cumulative fixtures building on each other.
Note: Some cost_per_egg_layers values differ from spec due to
integer bird-day truncation in implementation vs fractional
in spec calculations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 15:03:39 +00:00
340a9a2e1e docs: mark Step 9.3 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 14:36:52 +00:00
719d1e6ce7 feat: implement user defaults persistence (Step 9.3)
Add user_defaults table and repository for persisting form defaults
across sessions. Feed and egg forms now load/save user preferences.

Changes:
- Add migration 0009-user-defaults.sql with table schema
- Add UserDefault model and UserDefaultsRepository
- Integrate defaults into feed route (location, feed_type, amount)
- Integrate defaults into egg route (location)
- Add repository unit tests and route integration tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 14:35:27 +00:00
d89c46ab51 docs: mark Step 9.2 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 14:18:15 +00:00
0eef3ed7cb feat: implement product-sold route (Step 9.2)
Add POST /actions/product-sold route for recording product sales.

Changes:
- Create web/templates/products.py with product_sold_form
- Create web/routes/products.py with GET /sell and POST /actions/product-sold
- Wire up routes in __init__.py and app.py
- Add "Record Sale" link to Egg Quick Capture page
- Add comprehensive tests for form rendering and sale recording

The form allows selling any sellable product with quantity and price,
and calculates unit_price_cents using floor division. Defaults to
egg.duck product as per spec.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 14:16:12 +00:00
943383a620 docs: mark Step 9.1 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 13:47:06 +00:00
29ea3e27cb feat: complete Step 9.1 with outcome, status-correct, and quick actions
- Add animal-outcome route with yield items section for harvest products
- Add animal-status-correct route with @require_role(ADMIN) decorator
- Add exception handlers for AuthenticationError (401) and AuthorizationError (403)
- Enable quick action buttons in animal detail page (Add Tag, Promote, Record Outcome)
- Add comprehensive tests for outcome and status-correct routes (81 total action tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 13:45:06 +00:00
3acb731a6c feat: implement animal-tag-add and animal-tag-end routes (Step 9.1)
Add selection-based tag actions with optimistic locking:
- GET /actions/tag-add and POST /actions/animal-tag-add
- GET /actions/tag-end and POST /actions/animal-tag-end
- Form templates with selection preview and tag input/dropdown
- Diff panel for handling selection mismatches (409 response)
- Add TagProjection to the action service registry
- 16 tests covering form rendering, success, validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 12:50:38 +00:00
99f2fbb964 feat: add Promote Animal action route (Step 9.1 continued)
- Add /actions/promote/{animal_id} GET and /actions/animal-promote POST routes
- Add promote_form() template with nickname, sex, repro_status fields
- Add AnimalRepository.get() method for single-animal lookup
- 10 new tests for promote form rendering and submission

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 09:41:17 +00:00
f9e89fe5d6 feat: implement Cohort and Hatch action routes (Step 9.1 partial)
- Add /actions/cohort GET and /actions/animal-cohort POST routes
- Add /actions/hatch GET and /actions/hatch-recorded POST routes
- Add cohort_form() and hatch_form() templates
- Add Cohort and Hatch icons and navigation items
- Add list_active() method to SpeciesRepository
- Register action routes in app.py
- 26 new tests for cohort and hatch actions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 08:41:48 +00:00
301b925be3 feat: implement Animal Detail page with timeline (Step 8.3)
Add GET /animals/{animal_id} route to display individual animal details:
- Header summary with species, location, status, tags
- Event timeline showing all events affecting the animal (newest first)
- Quick actions card (Move functional, others disabled for now)
- Merge info alert for animals that have been merged

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 20:14:12 +00:00
bce4d099c9 feat: implement Event Log Projection & View (Step 8.2)
- Add migration 0008 for event_log_by_location table with cap trigger
- Create EventLogProjection for location-scoped event summaries
- Add GET /event-log route with location_id filtering
- Create event log templates with timeline styling
- Register EventLogProjection in eggs, feed, and move routes
- Cap events at 500 per location (trigger removes oldest)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 15:15:06 +00:00
8e155080e4 feat: implement Animal Registry view with filtering and pagination (Step 8.1)
- Add status field to filter DSL parser and resolver
- Create AnimalRepository with list_animals and get_facet_counts
- Implement registry templates with table, facet sidebar, infinite scroll
- Create registry route handler with HTMX partial support
- Default shows only alive animals; status filter overrides

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 14:59:13 +00:00
254466827c docs: mark Step 7.5 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 14:33:10 +00:00
ff4fa86beb feat: implement Move Animals UI with optimistic locking (Step 7.5)
Add Move Animals form with selection context validation and concurrent
change handling via optimistic locking. When selection changes between
client resolution and submit, the user is shown a diff panel and can
confirm to proceed with the current server resolution.

Key changes:
- Add move template with form and diff panel components
- Add move routes (GET /move, POST /actions/animal-move)
- Register move routes in app
- Fix to_xml() usage for HTMLResponse (was using str())
- Use max(current_time, form_ts) for confirmed re-resolution

Tests:
- 15 route tests covering form rendering, success, validation, mismatch
- 7 E2E tests for optimistic lock flow (spec §21.8)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 14:31:03 +00:00
b1bfdfb05c refactor: move route handlers to module level for idiomatic FastHTML
- Routes are now at module level, accessible for import by templates
- Templates accept action parameter (route function or URL string)
- Routes pass themselves to templates for type-safe form actions
- Changes DB access pattern from app.state.db to request.app.state.db
- Registration uses rt(...)(func) pattern instead of @rt decorator

This enables the idiomatic FastHTML pattern where forms can use
action=route_function instead of action="/path/string", providing
type safety and refactoring support.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 11:11:08 +00:00
600d5003ed docs: mark Step 7.4 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 10:44:48 +00:00
68e1a59ec7 feat: implement Feed Quick Capture form (Step 7.4)
Add /feed page with tabbed forms for Give Feed and Purchase Feed:
- GET /feed renders page with tabs (Give Feed default, Purchase Feed)
- POST /actions/feed-given records feed given to a location
- POST /actions/feed-purchased records feed purchases to inventory

Also adopts idiomatic FastHTML/HTMX pattern:
- Add hx-boost to base template for automatic AJAX on forms
- Refactor egg form to use action/method instead of hx_post

Spec §22 compliance:
- Integer kg only, min=1
- Warn if inventory negative (but allow)
- Toast + stay on page after submit
- Location/type stick, amount resets to default bag size

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 10:43:28 +00:00
3ce694b15d docs: mark Step 7.3 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 21:19:09 +00:00
e9804cdac8 feat: implement Egg Quick Capture form (Step 7.3)
Add the Egg Quick Capture functionality at GET / with POST /actions/product-collected.

Changes:
- Add list_active() to LocationRepository for active locations only
- Create web/templates/eggs.py with MonsterUI form components
- Create web/routes/eggs.py with GET and POST handlers
- Add CSRF bypass in dev_mode for easier development/testing
- Resolve ducks at location server-side for egg collection
- UX: location sticks after submit, quantity clears

Tests: 9 new tests covering form rendering and submission

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 21:17:18 +00:00
85b5e81e35 feat: implement serve command with dev mode support
- CLI serve command now runs uvicorn with migrations
- Add dev_mode setting to bypass auth with default admin user
- Add bin/animaltrack wrapper for Nix environment
- Add bin/serve-dev for quick local development
- Update flake.nix shellHook for PYTHONPATH and bin PATH

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 21:00:00 +00:00
352fa387af docs: mark Step 7.2 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 20:37:25 +00:00
6cdf48fc32 feat: add health endpoints, static serving, and base template (Step 7.2)
- Add /healthz endpoint with DB writable check
- Add /metrics endpoint with Prometheus-compatible format (enabled by default)
- Configure static file serving at /static/v1/... with immutable cache headers
- Create base page template with MonsterUI slate theme
- Create industrial farm aesthetic bottom navigation with custom SVG icons
- Add StaticCacheMiddleware for adding cache-control headers

Changes:
- src/animaltrack/web/routes/health.py: Health and metrics endpoints
- src/animaltrack/web/templates/: Base template, nav, and icons
- src/animaltrack/web/app.py: Integrate theme, routes, static serving
- src/animaltrack/config.py: metrics_enabled defaults to True

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 20:35:57 +00:00
52bc33891c docs: mark Step 7.1 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 19:53:58 +00:00
84225d865f feat: implement FastHTML app shell with auth/CSRF middleware (Step 7.1)
Add web layer foundation:
- FastHTML app factory with Beforeware pattern
- Auth middleware validating trusted proxy IPs and X-Oidc-Username header
- CSRF dual-token validation (cookie + header + Origin/Referer)
- Request ID generation (ULID) and NDJSON request logging
- Role-based permission helpers (can_edit_event, can_delete_event)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 19:52:15 +00:00
eb9dc8eadd docs: mark Step 6.3 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 19:21:52 +00:00
1153f6c5b6 feat: implement animal lifecycle events (Step 6.3)
Add 5 animal lifecycle event handlers with TDD:
- HatchRecorded: Creates hatchling animals at brood/event location
- AnimalOutcome: Records death/harvest/sold with yields, status updates
- AnimalPromoted: Sets identified flag, nickname, optionally updates sex/repro_status
- AnimalMerged: Merges animal records, creates aliases, removes merged from live roster
- AnimalStatusCorrected: Admin-only status correction with required reason

All events include:
- Projection handlers in animal_registry.py and intervals.py
- Event-animal linking in event_animals.py
- Service methods with validation in animal.py
- 51 unit tests covering event creation, projections, and validation
- E2E test #7 (harvest with yields) per spec §21.7

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 19:20:33 +00:00
da95e85452 docs: mark Step 6.2 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 18:45:18 +00:00
282d3d0f5a feat: add event deletion with tombstone creation and cascade rules
Implement event deletion per spec §10 with role-based rules:
- Recorder can delete own events if no dependents exist
- Admin can cascade delete (tombstone target + all dependents)
- All deletions create immutable tombstone records

New modules:
- events/dependencies.py: find events depending on a target via shared animals
- events/delete.py: delete_event() with projection reversal

DependentEventsError exception added for 409 Conflict responses.
E2E test #6 implemented per spec §21.6.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 18:44:13 +00:00
f733a067e2 feat: add event editing with revision storage
Implements Step 6.1 of the plan:
- Add edit_event() function in events/edit.py
- Store old version in event_revisions before editing
- Increment version on edit
- Update projections via revert/apply pattern
- Add EventNotFoundError and EventTombstonedError exceptions

Tested with:
- Unit tests for revision storage and version increment
- Fast-revert tests for FeedGiven/FeedPurchased events
- Unbounded replay tests for AnimalMoved events
- E2E test #5: Edit egg event 8→6 with stats verification

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 16:03:17 +00:00
e9d3f34994 feat: add selection validation with optimistic locking
Implements Step 5.3 - selection validation for optimistic locking:

- SelectionContext: holds client's filter, resolved_ids, roster_hash, ts_utc
- SelectionDiff: shows added/removed animals on mismatch
- SelectionValidationResult: validation result with diff if applicable
- validate_selection(): re-resolves at ts_utc, compares hashes, returns diff
- SelectionMismatchError: exception for unconfirmed mismatches

Tests cover: hash match, mismatch detection, diff correctness, confirmed bypass,
from_location_id in hash comparison.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 15:46:19 +00:00
c80d9f7fda feat: add historical state resolver with point-in-time queries
Implement resolve_filter() to resolve animals matching FilterAST at ts_utc.
Uses interval tables for historical location, sex, life_stage, and tags.
Includes roster hash computation using xxhash64.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 15:31:07 +00:00
6e9fd17327 feat: add selection filter DSL parser
Implement parser for filter strings like "species:duck sex:female -tag:old".
Supports AND (space), OR (|), negation (-), and quoted values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 15:19:11 +00:00
457f403e32 docs: mark Step 4.5 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:41:20 +00:00
b48fab5dde feat: add product sold event handling
Add sell_product() service method that creates ProductSold events
with calculated unit_price_cents (floor division of total/qty).
Update ProductsProjection to handle PRODUCT_SOLD events.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:40:34 +00:00
c82104b029 docs: mark Step 4.4 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:26:34 +00:00
c08fa476e0 feat: add 30-day egg stats computation service
Implement compute-on-read egg statistics per spec section 9:
- Create egg_stats_30d_by_location table (migration 0007)
- Add get_egg_stats service with bird-days calculation
- Calculate layer-eligible days (adult female + matching species)
- Implement feed proration formula with INTEGER truncation
- Cache computed stats with window bounds

Verifies E2E test #1 baseline values:
- eggs_total_pcs = 12
- feed_total_g = 6000, feed_layers_g = 4615
- cost_per_egg_all = 0.600, cost_per_egg_layers = 0.462
- layer_eligible_bird_days = 10

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:25:39 +00:00
8334414b87 docs: mark Step 4.3 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:08:59 +00:00
d53decdb66 feat: add product collection event handling
Implements Step 4.3 from the plan:
- Add selection/resolver.py with basic resolve_selection for validating
  animal IDs exist and are alive
- Add ProductsProjection placeholder (stats tables added in Step 4.4)
- Add ProductService with collect_product() function
- Add PRODUCT_COLLECTED to EventAnimalsProjection for linking events
  to affected animals
- Full test coverage for all new components

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:08:13 +00:00
fa3c99b755 feat: add feed given event handling
- Add FEED_GIVEN to FeedInventoryProjection with apply/revert
- Add give_feed method to FeedService
- Block feed given if no purchase exists <= ts_utc
- Validate feed type and location existence
- 13 new tests for give_feed functionality

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 08:11:36 +00:00
ff8f3bb3f5 docs: mark Step 4.1 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 08:03:22 +00:00
5c10a750ce feat: add feed inventory schema and purchase service
Implement FeedPurchased event handling:
- Add migration for feed_inventory table
- Create FeedInventoryProjection to track purchases
- Create FeedService with purchase_feed method
- Calculate price_per_kg_cents from bag details

Purchases accumulate in inventory with:
- purchased_kg, given_kg, balance_kg tracking
- Last purchase price stored in cents
- Timestamps for last purchase/given

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 08:02:24 +00:00
7c972f31d7 docs: mark Step 3.6 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 07:52:00 +00:00
0511ed7bca feat: add animal tagging projection and service
Implement AnimalTagged and AnimalTagEnded event handling:
- Add migration for tag_suggestions table
- Create TagProjection for tag intervals and suggestions
- Update EventAnimalsProjection to handle tag events
- Add add_tag() and end_tag() to AnimalService

Key behaviors:
- No-op idempotence (adding active tag or ending inactive tag)
- Updates live_animals_by_location.tags JSON array
- Tracks tag usage statistics in tag_suggestions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 07:51:20 +00:00
3583285336 docs: mark Step 3.5 as complete in PLAN.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 07:18:58 +00:00