{"slug":"animals","total":73,"limit":100,"offset":0,"since":null,"commits":[{"hash":"52183c3","date":"2026-07-27 20:04:04 -0700","author":"Steve Abrams","subject":"migrate GoDaddy auth → Bearer PAT (TK-10 key rotation); sso-key fallback retained","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"3a6991a","date":"2026-07-27 08:19:10 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T08:19:05 (1 files) — _nav5x.mjs","body":""},{"hash":"cc3bcfb","date":"2026-07-27 07:49:02 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T07:48:56 (1 files) — _nav5x.mjs","body":""},{"hash":"a7c20ed","date":"2026-07-23 11:41:50 -0700","author":"Steve Abrams","subject":"Pin autonomous Claude CLI invocation to Opus (--model opus)","body":"Bare 'claude' spawn inherited the CLI's drifting default model; pin to Opus\nso this build/gen loop always runs on the intended model.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"c5a90f5","date":"2026-07-23 08:28:23 -0700","author":"Steve","subject":"auth: accept second admin user dbrown","body":""},{"hash":"1ed0c8d","date":"2026-07-22 20:21:07 -0700","author":"Steve Abrams","subject":"Fix flag panel popping open on every lightbox view (CSS display:flex overrode hidden attr)","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"3fc5e1e","date":"2026-07-22 20:16:35 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-22T20:16:30 (1 files) — scripts/localize_breed_heroes.cjs","body":""},{"hash":"a4bf2fe","date":"2026-07-16 17:23:47 -0700","author":"steve@designerwallcoverings.com","subject":"animals: basic-auth creds admin/DW2024!; deployed on mac3:9720","body":""},{"hash":"821fb8b","date":"2026-07-03 08:07:50 -0700","author":"Steve","subject":"chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew)","body":""},{"hash":"d2da3c7","date":"2026-06-03 08:59:35 -0700","author":"Steve","subject":"Untrack committed .log files and ignore *.pre-* backups","body":"Removes 4 stale weekly log files from git tracking (they were committed\nbefore the *.log ignore rule existed) and adds *.pre-* to .gitignore so\nbackup files never get tracked. Working-tree files are left untouched.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"2ab8a9e","date":"2026-05-26 12:27:52 -0700","author":"SteveStudio2","subject":"test: verify Stripe upgrade-checkout line items + live-key guard","body":""},{"hash":"ecd4ce9","date":"2026-05-26 11:43:32 -0700","author":"SteveStudio2","subject":"Add lost-pet alert opt-in surface (/me prefs page + signup checkbox)","body":"The backend (migration 017 + src/lib/lost_pet_alert.js + dispatch wiring in\ncommunity.js) already shipped, but nothing set alert_lost_pets=TRUE, so the\naudience was always empty and the email footer's /me link 404'd.\n\n- expose alert_lost_pets/_sms on req.user (currentUser SELECT)\n- signup: explicit unchecked opt-in checkbox -> alert_lost_pets\n- GET /me preferences page (the surface the alert email + one-click off link to)\n- POST /me/alerts/lost-pets toggles opt-in on/off\n- SMS kept off — page states we never text without separate opt-in\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"2f8b7b5","date":"2026-05-26 10:15:39 -0700","author":"SteveStudio2","subject":"Honor ?next= after login/signup so claimers return to the claim flow","body":"requireUserHtml already redirects logged-out users to /login?next=/clinic/:id/claim,\nbut the auth forms hardcoded location.href='/circles' and ignored it. Now both\nforms read ?next= (with an open-redirect guard: only single-leading-slash local\npaths, rejecting //host and backslash), carry it across the login<->signup\ncross-links, and redirect there on success."},{"hash":"cda6f25","date":"2026-05-19 11:35:43 -0700","author":"Steve","subject":"snapshot — gitify backup 2026-05-19","body":""},{"hash":"6635ad9","date":"2026-05-15 02:22:09 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"b086583","date":"2026-05-14 17:15:58 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"bcf525d","date":"2026-05-14 08:04:49 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"cd61af8","date":"2026-05-13 15:47:12 -0700","author":"animal-yolo","subject":"yolo: Generate sitemap.xml + robots.txt","body":"Task: yolo.directory-sitemap\nPrompt: In ~/Projects/animals: generate a /sitemap.xml route that lists every breed, every business detail page, every shows event, every breed gallery page. Cache at agent level — regenerate every 6h. Add /r"},{"hash":"9a24d54","date":"2026-05-13 12:14:25 -0700","author":"SteveStudio2","subject":"snapshot: backup uncommitted work (1 files)","body":""},{"hash":"4071c18","date":"2026-05-13 11:46:30 -0700","author":"SteveStudio2","subject":"dog-park: arrow-key movement + Auto walk toggle (button/T-key), human input cancels auto","body":""},{"hash":"3aa2726","date":"2026-05-13 11:44:52 -0700","author":"SteveStudio2","subject":"dog-park: brand logo upper-left, hamburger nav upper-right with site sections","body":""},{"hash":"446da7c","date":"2026-05-13 10:41:22 -0700","author":"animal-yolo","subject":"yolo: Breed page: nearest businesses that work with this breed","body":"Task: yolo.breed-page-related-businesses\nPrompt: In ~/Projects/animals: /breeds/:slug currently shows top-rated vets generally. Replace with a query that prefers vets in the visitor's home_zip (if logged in) or top-rated for that species. Also add a"},{"hash":"1b82d04","date":"2026-05-13 08:57:45 -0700","author":"Steve","subject":"snapshot: 1 file(s) changed, ~1 modified","body":""},{"hash":"7decd3c","date":"2026-05-13 07:44:54 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"3fdcff8","date":"2026-05-12 22:33:01 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"fa433df","date":"2026-05-12 13:16:07 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"e54de52","date":"2026-05-12 04:14:36 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"aea9589","date":"2026-05-11 18:55:02 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"588c368","date":"2026-05-11 15:47:31 -0700","author":"SteveStudio2","subject":"animals-viewer: set BASIC_AUTH env so the app starts (was crash-looping on missing env)","body":""},{"hash":"3846ae8","date":"2026-05-11 11:07:36 -0700","author":"animal-yolo","subject":"yolo: Adoption events on /shows page","body":"Task: yolo.shelter-adoption-feed\nPrompt: In ~/Projects/animals: queue a `events` table insert per CA shelter (category='shelter' or 'rescue') with kind='adoption_event' that's a recurring weekly Saturday 11am-3pm 'Open adoption hours' tied t"},{"hash":"8874f66","date":"2026-05-11 09:30:03 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"035fe9a","date":"2026-05-10 15:40:07 -0700","author":"animal-yolo","subject":"yolo: Codex debate on agent's own diff","body":"Task: yolo.codex-debate-on-self\nPrompt: In ~/Projects/animals: trigger a 4-round claude-codex apply-mode debate on whatever the YOLO loop has produced in the last 6 hours. Use ~/.claude/skills/claude-codex/scripts/start.sh. Name the run wit"},{"hash":"e299593","date":"2026-05-10 09:25:14 -0700","author":"Steve","subject":"animals-hawk: skip services not registered in pm2 instead of erroring","body":""},{"hash":"04b9602","date":"2026-05-10 07:08:46 -0700","author":"Steve","subject":"fix: animals-hawk pm2 path portable across Mac1/Mac2","body":"Hardcoded /opt/homebrew/bin/pm2 fails on Mac2 where pm2 is at ~/.npm-global/bin/pm2 — Mac2 was failing every 30m health-check, \"/opt/homebrew/bin/pm2: No such file or directory\" log line × hours.\nNow picks first available: ~/.npm-global/bin/pm2 → /opt/homebrew/bin/pm2 → command -v pm2.\n\nCaught by yolo-loop tick 10 reading hawk.log error pattern."},{"hash":"8a2e6ac","date":"2026-05-10 00:22:12 -0700","author":"SteveStudio2","subject":"Revert \"[morning-review] animals: gate layoutModernClinic vet copy/prices/badges by m.copy.medical so pet stores stop rendering DVM fees\"","body":"This reverts commit aed8935138e6dc9d1bae2ca8997a8fea26605bf1."},{"hash":"aed8935","date":"2026-05-10 00:22:07 -0700","author":"SteveStudio2","subject":"[morning-review] animals: gate layoutModernClinic vet copy/prices/badges by m.copy.medical so pet stores stop rendering DVM fees","body":"Why: review flagged biz-15249-a \"Patriot Pet Supply\" (pet store) shipping\n\"Wellness exam $95, Spay $225, Vaccine package $140\" — fabricated medical\nprices for a non-vet category. The \"Common visits\" price list and the\n\"$95 Wellness exam / 24h Lab results\" hero badges are vet-only by\ndefinition.\n\nWhat changed: layoutModernClinic now branches on m.copy.medical:\n  - hero h1/sub falls back to category copy bundle when not medical\n  - the four hero badges swap the medical-fee pair for s1/s2 service blurbs\n  - the \"Common visits\" price list is replaced by a \"What we do\" service\n    triple sourced from m.copy.s1/s2/s3 for shelters/kennels/stores/parks\nAlso wires the Book CTA to m.bookHref instead of hard-coded \"#book\" so\nclicks resolve to /contact.html on subsites."},{"hash":"72174df","date":"2026-05-10 00:18:07 -0700","author":"SteveStudio2","subject":"Revert \"[morning-review] animals: gate layoutPlayful + layoutBookingFirst.why by m.copy.medical so non-vet sites stop rendering vet copy\"","body":"This reverts commit 9e958c63f804407865358077e489d3067db45731."},{"hash":"9e958c6","date":"2026-05-10 00:17:51 -0700","author":"SteveStudio2","subject":"[morning-review] animals: gate layoutPlayful + layoutBookingFirst.why by m.copy.medical so non-vet sites stop rendering vet copy","body":"Two layouts unconditionally rendered veterinary-clinic copy:\n- layoutPlayful (.pl-hero/.pl-grid) hardcoded \"The {city} vet your pet\n  actually wants to visit\" + Dogs/Cats/Exotics exam-room cards. Houston\n  Humane Society (a SHELTER) rendered this verbatim.\n- layoutBookingFirst (.why-grid) hardcoded \"Same-week openings / Honest\n  pricing / Real follow-up — Email check-in 48h after every visit\".\n  Farrington Kennels (BOARDING) rendered the medical-follow-up promise.\n\nBoth now read m.copy.* from copyBundle() so kennel/shelter/store/groomer/\ntrainer/park/cafe categories get their appropriate s1/s2/s3 + lead, and\nonly true vets keep medical-flavored copy.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"8fe1581","date":"2026-05-10 00:14:08 -0700","author":"SteveStudio2","subject":"Revert \"[morning-review] animals: gate layoutPlayful + layoutBookingFirst.why by m.copy.medical so kennels/shelters/stores stop rendering vet copy\"","body":"This reverts commit 68854b012e29850a2e5841e8dadd83dfafd12176."},{"hash":"68854b0","date":"2026-05-10 00:14:01 -0700","author":"SteveStudio2","subject":"[morning-review] animals: gate layoutPlayful + layoutBookingFirst.why by m.copy.medical so kennels/shelters/stores stop rendering vet copy","body":"Two layouts unconditionally rendered veterinary-clinic copy:\n- layoutPlayful (.pl-hero/.pl-grid) hardcoded \"The {city} vet your pet\n  actually wants to visit\" + \"Cat-only exam room\" cards. Houston Humane\n  Society (a SHELTER) rendered this verbatim.\n- layoutBookingFirst (.why-grid) hardcoded \"Same-week openings / Honest\n  pricing / Real follow-up — Email check-in 48h after every visit\".\n  Farrington Kennels rendered the medical-follow-up promise.\n\nBoth now read m.copy.* (the category-aware copy bundle from copyBundle())\nso kennel/shelter/store/groomer/trainer/park/cafe categories get their\nown appropriate s1/s2/s3 + lead text, and only true vets keep the\nmedical-flavored copy.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"1047395","date":"2026-05-10 00:09:40 -0700","author":"SteveStudio2","subject":"Revert \"[morning-review] animals: gate layout-split copy by m.copy.medical so kennels/shelters/pet stores stop rendering vet copy\"","body":"This reverts commit 1fbaad6b818ed8b0c1b5fc9c464a50ef09f73042."},{"hash":"1fbaad6","date":"2026-05-10 00:09:16 -0700","author":"SteveStudio2","subject":"[morning-review] animals: gate layout-split copy by m.copy.medical so kennels/shelters/pet stores stop rendering vet copy","body":""},{"hash":"270910b","date":"2026-05-09 23:55:20 -0700","author":"SteveStudio2","subject":"Revert \"[morning-review] animals: dedupe Google Fonts family params, decode %2B → +, wire booking-form action/method/submit type across tracked mockups + sites\"","body":"This reverts commit 6748897c6de50b6fee197b2bf1b79d77b4db6538."},{"hash":"6748897","date":"2026-05-09 23:55:15 -0700","author":"SteveStudio2","subject":"[morning-review] animals: dedupe Google Fonts family params, decode %2B → +, wire booking-form action/method/submit type across tracked mockups + sites","body":""},{"hash":"ed86357","date":"2026-05-09 17:34:27 -0700","author":"animal-yolo","subject":"yolo: Business owners can claim their listing","body":"Task: yolo.business-claim-flow\nPrompt: In ~/Projects/animals: add a /clinic/:id/claim route. If logged-in user submits, it sends a verification email to the email already on file for that business. Click the link, businesses.claimed_by get"},{"hash":"51d1f13","date":"2026-05-09 10:37:54 -0700","author":"animal-yolo","subject":"yolo: Generate sitemap.xml + robots.txt","body":"Task: yolo.directory-sitemap\nPrompt: In ~/Projects/animals: generate a /sitemap.xml route that lists every breed, every business detail page, every shows event, every breed gallery page. Cache at agent level — regenerate every 6h. Add /r"},{"hash":"856153b","date":"2026-05-09 09:48:41 -0700","author":"animal-yolo","subject":"yolo: Wire Stripe Checkout for upgrade orders","body":"Task: yolo.upgrade-stripe-real\nPrompt: In ~/Projects/animals: the upgrade_orders table currently goes to 'pending_payment' manually. Wire actual Stripe Checkout: when an order is placed, create a Stripe checkout session with the right line"},{"hash":"f2d7975","date":"2026-05-09 09:03:12 -0700","author":"animal-yolo","subject":"yolo: Lost-pet listing → SMS alert to neighbors in ZIP","body":"Task: yolo.lost-pet-alerts\nPrompt: In ~/Projects/animals: when a marketplace listing of type='lost_pet' is posted, find all app_users with home_zip matching listing.zip OR within ZIP-3 prefix, AND who opted in (new column: alert_lost_p"},{"hash":"2fa8980","date":"2026-05-08 17:19:54 -0700","author":"animal-yolo","subject":"yolo: Business owners can claim their listing","body":"Task: yolo.business-claim-flow\nPrompt: In ~/Projects/animals: add a /clinic/:id/claim route. If logged-in user submits, it sends a verification email to the email already on file for that business. Click the link, businesses.claimed_by get"},{"hash":"33ff008","date":"2026-05-08 14:32:07 -0700","author":"animal-yolo","subject":"yolo: Pet store detail: 'what they sell' section","body":"Task: yolo.pet-store-products\nPrompt: In ~/Projects/animals: /clinic/:id pages where category='pet_store' should show a generic services/inventory blurb. Add a `products_carried` text[] column to businesses (migration needed). Default com"},{"hash":"d1144d1","date":"2026-05-08 13:43:10 -0700","author":"animal-yolo","subject":"yolo: 3D dog park: use dog's actual photo as billboard texture","body":"Task: yolo.dog-park-dog-photo\nPrompt: In ~/Projects/animals: in public/dogpark/dogpark.js, when an owner_pets photo URL is provided in the join message, build a Three.js Sprite from a CanvasTexture that loads that photo + the dog's name u"},{"hash":"2069600","date":"2026-05-08 12:49:51 -0700","author":"animal-yolo","subject":"yolo: Email verification on signup","body":"Task: yolo.email-verify-gate\nPrompt: In ~/Projects/animals: when a user signs up, send a verification link via George (localhost:9850 /api/send) and require click before they can post marketplace listings or send friend requests. Store v"},{"hash":"e7e8d06","date":"2026-05-08 09:04:16 -0700","author":"animal-yolo","subject":"yolo: Breed page: nearest businesses that work with this breed","body":"Task: yolo.breed-page-related-businesses\nPrompt: In ~/Projects/animals: /breeds/:slug currently shows top-rated vets generally. Replace with a query that prefers vets in the visitor's home_zip (if logged in) or top-rated for that species. Also add a"},{"hash":"53b3de1","date":"2026-05-08 01:32:14 -0700","author":"animal-yolo","subject":"yolo: Surface adoptable animals on pound/shelter detail pages","body":"Task: yolo.pound-detail-photos\nPrompt: In ~/Projects/animals: on /clinic/:id pages where category in ('shelter','rescue','pound'), query shelter_animals table for that business_id and show available animals as cards (name, breed, photo if"},{"hash":"f22df9f","date":"2026-05-08 00:51:49 -0700","author":"Steve","subject":"rel=alternate JSON + HTTP Link header on /breeds and /photographers","body":"Cross-fleet directory pattern (VCL fbd4be4, NPH 51036bf, lacountyeats 963d23a)\napplied to animals. /api/breeds.json + /api/photographers.json already exist\nas JSON twins; this commit just surfaces them via RFC 8288 Link headers.\n\nChanges:\n- src/server/index.js /breeds: HTTP Link with canonical + alternate (mirrors\n  the filter query params q/species/size/energy onto /api/breeds.json)\n- src/server/index.js /photographers: HTTP Link with canonical + prev + next\n  + alternate (paginated; respects ?page= query)\n- ALSO fixed pre-existing ES-module crash on line 92: 'const helmet =\n  require()' replaced with 'await import()' destructure pattern. Server\n  was in pm2 crash loop before this commit; now listening on :9720.\n\nSmokes (with basic auth admin:DWSecure2024!):\n- /breeds → 200 + Link header (canonical + alternate)\n- /photographers?page=2 → 200 + Link header (canonical + prev + next + alternate)\n\nCross-fleet rel=alternate now: VCL + NPH + lacountyeats + animals = 4 of 6\ndirectory targets. Skipped: lawyer-directory (SPA, autocomplete pattern),\nprofessional-directory (api-only, no HTML listing).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"18ee2c0","date":"2026-05-08 00:47:15 -0700","author":"animal-yolo","subject":"yolo: Adoption events on /shows page","body":"Task: yolo.shelter-adoption-feed\nPrompt: In ~/Projects/animals: queue a `events` table insert per CA shelter (category='shelter' or 'rescue') with kind='adoption_event' that's a recurring weekly Saturday 11am-3pm 'Open adoption hours' tied t"},{"hash":"7d3642f","date":"2026-05-08 00:01:22 -0700","author":"animal-yolo","subject":"yolo: Wire /my-pets to /dog-park — auto-fill avatar","body":"Task: yolo.dog-park-from-mypets\nPrompt: In ~/Projects/animals: when a logged-in user goes to /dog-park, pre-fill the join form with their first owner_pets row (name, hero_image_url, breed-to-color mapping). The dog-park already accepts dogN"},{"hash":"01839be","date":"2026-05-07 23:54:17 -0700","author":"Steve","subject":"checkpoint: codex --apply overnight + gitignore generated content","body":"5 days of autonomous animal-agent work:\n- 15,098 businesses (was 6,101) — multi-state OSM ingest rotation\n- 5,825 site audits, 6,060 mockups, 358 generated subsites\n- 13,023 PD/CC breed images across 119 breeds\n- 13,150 emails harvested\n- 1,328 agent tasks completed across 8 cron categories\n\nCodex --apply mode delivered hardening:\n- agents/animal-agent/server.js: BASIC_AUTH gate (env-only, no source fallback)\n- src/scripts/build_subsites.js: category-aware copy buckets (vet/shelter/\n  boarding/grooming/retail/training/park/generic) — was emitting \"Board-\n  certified veterinarians, Fear Free Certified\" on shelter/store pages\n- src/server/dog_friends.js: P0 auth fix — /friends/* endpoints now require\n  pet ownership; previous version let anyone read home_zip / send requests\n  as anyone else's pet\n- migrations/012_site_audit_html.sql: stores raw HTML alongside screenshots\n\n.gitignore: untrack public/{mockups,sites,screenshots,uploads}/, raw_html/,\nexports/, *.png/jpg — these are agent-generated content, not source. Reduces\ngit diff from 5,714 → ~30 real source changes."},{"hash":"a79a69b","date":"2026-05-07 12:29:20 -0700","author":"Steve","subject":"tighten .gitignore: add missing standing-rule patterns (*.log dist/ build/ .next/)","body":""},{"hash":"b9336a0","date":"2026-05-04 12:51:08 -0700","author":"SteveStudio2","subject":"[morning-review] animals: escape biz fields, validate website href, fix font URL + meta tags","body":"Critical: stored XSS via unescaped ${biz.*}/${m.*} in 15 layouts and contact\npage (raw <script>, \" onmouseover=\" payloads now neutralised in meta() and\npageHtml()). javascript: hrefs blocked via safeWebsiteHref(). Each Google\nFonts family name now percent-encoded individually so future names with\nspecial chars round-trip. Adds <html lang=\"en\">, viewport meta, and unique\n<title> per page. Font name allow-list guards CSS :root injection.\n\nHigh: subpages get unique <title>, address line no longer shows leading\ncommas when street is missing, tel: hrefs strip non-digit chars, --biz 0\nno longer collapses to null, and pool.end() runs in finally so a Postgres\nerror can't leak the connection."},{"hash":"82583ba","date":"2026-05-04 12:50:32 -0700","author":"SteveStudio2","subject":"[morning-review] animals: drop trailing footer separator + bundle iter4 template safety (lang/title/viewport, font-name encode, XSS escape)","body":""},{"hash":"14cfcfd","date":"2026-05-04 11:26:03 -0700","author":"yolo","subject":"yolo: iter 3 trivial patches from claude-codex debate","body":""},{"hash":"77636a0","date":"2026-05-04 09:30:23 -0700","author":"yolo","subject":"yolo: iter 2 trivial patches from claude-codex debate","body":""},{"hash":"cee28f8","date":"2026-05-04 08:19:35 -0700","author":"yolo","subject":"yolo: iter 1 trivial patches from claude-codex debate","body":""},{"hash":"f106fd8","date":"2026-05-04 07:05:57 -0700","author":"yolo","subject":"yolo: iter 4 trivial patches from claude-codex debate","body":""},{"hash":"c0c2328","date":"2026-05-04 05:24:59 -0700","author":"yolo","subject":"yolo: iter 3 trivial patches from claude-codex debate","body":""},{"hash":"f0625fb","date":"2026-05-04 03:16:21 -0700","author":"yolo","subject":"yolo: iter 2 trivial patches from claude-codex debate","body":""},{"hash":"05cb1bc","date":"2026-05-04 01:35:03 -0700","author":"yolo","subject":"yolo: iter 1 trivial patches from claude-codex debate","body":""},{"hash":"b70d15d","date":"2026-05-01 18:50:22 -0700","author":"Steve","subject":"fix(events): codex P1 XSS in /shows map + P2 dedupe collision","body":"P1 (security) — render.js:389-396\nThe /shows page injected scraped event titles via raw JSON.stringify in a\n<script> block, then built popups via 'string' + p.title concat fed to\nLeaflet's bindPopup (which treats it as innerHTML). Event titles come from\nthird-party AKC/UKC pages — a malformed or hostile title containing\n</script> or HTML became stored XSS on a public route.\n\nSwitched to:\n- <script type=\"application/json\" id=\"show-pts\">…</script> + JSON.parse\n  (with a <-escape on the JSON output for an extra layer in case the\n  pattern is ever copy-pasted into a non-JSON context)\n- Popup built via document.createElement('strong') + .textContent so\n  titles can never become HTML.\n\nP2 (data integrity) — dog_shows_ca.js:158 + migrations/007_*.sql\nON CONFLICT (source, source_url, start_at) collided for AKC/UKC where\nsource_url is the shared search/results page. Two distinct shows on the\nsame date silently overwrote each other in the events table.\n\nAdded title to the dedupe key + new migration that drops the old unique\nindex and creates idx_events_dedupe (source, source_url, start_at, title).\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"bf214ed","date":"2026-05-01 18:40:19 -0700","author":"Steve","subject":"fix: codex review findings — creds + URL parse + license regex","body":"Three issues codex flagged on 2026-05-01:\n\nP1 — src/scripts/2week-followup-audit.sh:12: Hardcoded George Basic-auth\ncredential. Same pattern as run-meeting.sh had — read GEORGE_AUTH from env\nor ~/Projects/secrets-manager/.env, abort send if neither has it.\n\nP1 — src/lib/auth.js:157-158: `new URL(req.headers.origin)` throws on a\nmalformed Origin or Referer header, surfacing as an unhandled promise\nrejection in this Express 4 async handler — could crash the process.\nWrap with safeHost() so a bad header is treated as cross-origin (rejected)\ninstead of a 500.\n\nP2 — src/enrich/wikimedia_breed_images.js:37: ALLOWED_LICENSES regex only\nmatched hyphen-joined or no-separator forms (CC-BY-4.0, CCBY4.0). Real\nCommons LicenseShortName values use spaces too (CC BY-SA 4.0, CC BY 2.0),\nso the enricher was rejecting most CC-BY images. Updated regex to accept\nhyphen, space, or no separator between CC/BY/SA and the version.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"95e913a","date":"2026-05-01 14:31:13 -0700","author":"Steve","subject":"fix(community): debate-driven fixes for visibility, comments, signup","body":"5 defects converged on by claude+codex debate (animals-pawcircles-2026-05-01):\n\nP1 functional — marketplace SELECT omitted visibility/app_user_id/visible_circles,\n  so the in-memory userCanSeeListingSync filter read undefined and hid every\n  non-public listing from logged-in users. Now selects the fields and\n  over-fetches 200 → filters → slices to 100.\n\nP1 privacy — /circles/:slug returned matching-zip/state listings with no\n  visibility check at all, leaking scoped listings to anyone browsing a\n  circle. Now post-filtered through the same userCanSeeListingSync helper\n  used elsewhere (single source of truth for the gate).\n\nP2 — POST /marketplace/:id/comment had no listing-access check; users could\n  comment on listings they couldn't see. Now loads the listing and runs the\n  visibility gate before insert.\n\nP2 — auth.js signup: species_pets from a checkbox group is a string when one\n  box is checked, an array when several. Insert into TEXT[] failed for the\n  single-checkbox case. Normalize via [].concat() before insert.\n\nP3 — admin_pitch.js: \"All states\" <option> had no value=\"\"; form posted\n  state=\"All states\" and SQL filter got junk. Added value=\"\".\n\nSmoke-tested signup with no/single/array pets (all 200, species_pets stored\nas {}, {dog}, {dog,cat} respectively), and confirmed all routes still 200."},{"hash":"9e16943","date":"2026-05-01 13:02:40 -0700","author":"SteveStudio2","subject":"fix(map): stop near-me SQL from crashing, hide empty cats, add cap notice","body":"The home-page \"Sharing your location loads the closest 24 listings…\" was\nthe reported \"map does not work\" — /api/near-me returned 500 because\nPostgres saw $1/$2/$3 as untyped 'unknown' and refused subtraction. The\nCTE param-typing pattern in index.js fixes the planner. Plus three\nuser-visible cleanups from the dual-Claude review:\n\n- renderHome filters out zero-count categories (Specialty Hospitals,\n  Daycare) so the home-page grid stops linking to dead-end pages.\n- renderCategory annotates the map when the 200-marker cap is hit,\n  e.g. /dog-parks now shows \"Map shows first 200 of 377 geocoded\n  listings — full table below.\"\n- All Leaflet CSS + JS <link>/<script> tags get integrity= hashes\n  back; they were stripped during the working-tree refactor.\n\nAlso lands the broader companion work that was sitting uncommitted:\ngeo.js (browser geolocation + ipapi.co fallback), sort-table.js,\nOSM California / Reddit / Nextdoor ingest stubs, email enrich\nmigration, llm helper.\n\nCo-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"},{"hash":"474af3c","date":"2026-05-01 11:33:17 -0700","author":"Steve","subject":"init: project animals scaffold (schema + viewer + audit + mockups + ad engine + lead funnel)","body":""}]}