Skip to content

feat(drugs_com): add drugs.com mirror site (port 40016) - #9

Open
boyugou wants to merge 177 commits into
aiming-lab:mainfrom
boyugou:feat/drugs-com
Open

feat(drugs_com): add drugs.com mirror site (port 40016)#9
boyugou wants to merge 177 commits into
aiming-lab:mainfrom
boyugou:feat/drugs-com

Conversation

@boyugou

@boyugou boyugou commented May 13, 2026

Copy link
Copy Markdown

TL;DR

Adds a fully functional drugs.com mirror site to WebHarbor at port 40016, with 21 benchmark tasks covering drug lookup, interaction checking, pill identification, condition browsing, news, and authenticated account actions. Real (bcrypt-checked) authentication and CSRF protection throughout; search results and browse pages are click-through-only (no answer visible before opening the relevant detail page).

Motivation

drugs.com is the most-visited drug information portal (24,000+ drugs). It covers pharmaceutical/medical information — a domain not represented in the existing 16 sites — making it a high-signal addition for web-agent benchmarks.

Design

Flask application (sites/drugs_com/app.py)

Ten SQLAlchemy models: User, DrugClass, Drug, DrugImage, DrugInteraction, DrugReview, Condition, DrugCondition, NewsArticle, SavedDrug. All seeded idempotently — each seed_*() function gates on an already-populated table so seed_database() is safe to call repeatedly without breaking the byte-identical reset invariant.

Route coverage mirrors the real site's navigation:

Route Description
/<slug>.html Drug detail with tabbed sections
/drug_information.html Drugs A-Z index
/drug-interactions Drug interaction checker
/pill-identifier Pill identifier by imprint/shape/color
/drug-classes/, /drug-classes/<slug>/ Drug class browser
/conditions/, /condition/<slug>/ Conditions A-Z
/news/ News with category filter
/search Drug/class/condition search
/my-med-list Saved drugs (auth required)

app.url_map.strict_slashes = False is set globally so all routes accept trailing-slash variants. The last @app.route decorator on each view is the canonical URL used by url_for(); alias routes are placed before it.

Auth and CSRF

/login and /register perform real bcrypt-checked authentication, matching the pattern used by every other site in the repo. CSRFProtect is enabled repo-wide-consistently: every <form method="post"> carries a token; the one route that's genuinely JSON-only and unreferenced by any template (/api/interaction-check) is deliberately exempt, while the two routes reachable from both a real form and JavaScript carry their token through both paths (an X-CSRFToken header for the JSON call, an appended FormData field for the other) rather than being exempted.

Answer-leak prevention

Search results (.drug-card / "Best match" cards) show only the drug name and a link — no drug class, brand names, CSA schedule, rating, or description snippet, all of which require opening the detail page. The homepage, the /drug-classes index, and /search's condition/class-match sidebar do not pre-list category members by name, so "name at least N drugs in category X"-style tasks require actually opening that category's page rather than reading a summary widget.

Seed content integrity

Drug detail text (uses/warnings/dosage/side_effects) is sourced from the FDA's public drug-label API at seed time where available, falling back to a generated description otherwise. Because that API does fuzzy/tokenized matching rather than exact matching, a fetched label is verified to actually describe the queried drug (by generic-name match) before being accepted, rather than trusting the top search hit — this prevents one drug's content from silently containing a different, unrelated drug's real label text.

Seed database

  • 246 drugs across diverse Rx and OTC drug classes, 104 drug classes
  • 716 reviews, 76 drug interactions, 103 pill images, 69 conditions, 80 news articles, 12 users
  • Seed DB MD5: d3d228f3fc0b3b880e149ac35550e3c5
  • Benchmark users: alice.j@test.com / TestPass123! (primary), plus bob_c, carol_d, david_k
  • Alice's med list is pre-seeded with ibuprofen, metformin, atorvastatin (lisinopril is not in it)

Pill images

Rendered as inline SVGs via the _pill_svg.html macro (no external files required for the benchmark). Real pill photos at static/images/pills/<slug>.jpg are HuggingFace assets; a pill_image_exists Jinja filter falls back to the SVG macro when absent.

Benchmark tasks (tasks.jsonl)

21 tasks (Drugs.com--0 through Drugs.com--20) covering:

  • Drug detail lookup (drug class, brand names, availability, CSA schedule, pregnancy risk)
  • Drug interaction checker — 2-drug and 3-drug, severity classification
  • Pill identifier by imprint code, shape, and color
  • Drugs A-Z browsing
  • Drug class navigation (Statins, Benzodiazepines, Fluoroquinolones)
  • Condition browsing (diabetes, hypertension)
  • News reading and category filtering
  • User reviews and ratings
  • Authenticated action: sign in, then read the My Med List page (task 14; genuinely gated behind real login now, not a no-op)

Templates

40 Jinja2 templates modeled on real drugs.com layout: drug detail with tabbed sections (Uses, Warnings, Before taking, Dosage, Side effects, Interactions, FAQ), drug status sidebar (Pregnancy/Lactation risk, CSA Schedule, Approval History), interaction checker with severity badges, pill identifier, A-Z index with category browse, and news with category filter tabs.

Registration

Registered in all three required locations:

File Change
websyn_start.sh Added drugs_com to SITES=(...) — index 16, port 40016 (after merriam_webster, index 15)
control_server.py Added drugs_com to SITES list
Dockerfile EXPOSE 8101 40000-40016 covers port 40016

HuggingFace assets

The seed DB and pill images are packaged as drugs_com.tar.gz (5 MB, clean — no macOS AppleDouble sidecars; DB md5 d3d228f3fc0b3b880e149ac35550e3c5) and submitted to the ChilleD/WebHarbor HuggingFace dataset as discussion #39 (https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/39). .assets-revision is pinned to that PR's ref (refs/pr/39) in the interim, since it's a strict superset of main (all 16 existing site tarballs unchanged, plus this one) — safe for every other site to build against right now. After #39 merges, .assets-revision should be re-pinned to main or the merge commit. Fetch locally with:

./scripts/fetch_assets.sh drugs_com

Review history

This PR went through a human review round followed by several rounds of independent automated re-review (deliberately varying which tool/model reviewed each round, to avoid one reviewer's blind spots repeating across rounds). Every finding was verified against the actual code before being acted on — see the comment thread below for the full reasoning on what was fixed and, in a few cases, why a real-but-out-of-scope finding was deliberately left alone (e.g. patterns shared by all 17 sites in the repo, or issues not reachable by a browser-driving agent). Net result: the auth/CSRF/answer-leak/seed-content-integrity design described above is the product of that process, not the original submission.

Non-goals

  • Real FDA API calls at HTTP-request time (the label-search call happens only at build/seed time, never from a runtime route handler)
  • Image assets in git (heavy assets are in HuggingFace as drugs_com.tar.gz)

Verification

Check Result
py_compile sites/drugs_com/app.py
./scripts/build.sh webharbor:dev
GET /healthdrugs_com alive
GET http://localhost:40016/ → 200 (all 17 sites → 200)
POST /reset/drugs_com + md5sum match d3d228f3fc0b3b880e149ac35550e3c5
All 21 task routes manually verified against the current seed data
Real login + CSRF flow (wrong password rejected, correct password + token succeeds, unauthenticated access to gated routes redirects to login) verified against a running container with real cookies
Full-table sweep for cross-drug duplicate content (the seed-content-integrity fix) ✅ none found

Adds a complete Flask mirror of drugs.com — the most popular drug
information portal — as a new benchmark site in the WebHarbor suite.

Site covers 81 drugs across 20+ drug classes with real FDA label content
(sourced from the OpenFDA API at seed time), 20 news articles, 22 drug
interactions, and 67 user reviews. Four benchmark users are pre-seeded
(alice.j@test.com / TestPass123!).

Pages implemented:
- Drug detail (/<slug>.html) with Uses/Warnings/Before taking/Dosage/
  Side effects/Interactions/FAQ/Reviews sections and Drug Status sidebar
- Drug A-Z (/drug_information.html, /drugs-a-to-z.html)
- Drug Interaction Checker (/drug_interactions.html, /interaction-checker/)
- Pill Identifier (/pill_identification.html, /pill-identifier.html)
- Drug classes (/drug-classes, /drug-class/<slug>)
- Conditions (/conditions, /condition/<slug>)
- News (/news/, /news/<category>, /news/article/<id>)
- Search, Login/Register, My Med List, Account

21 benchmark tasks in tasks.jsonl covering: drug lookup, interaction
checking, pill identification, A-Z browsing, conditions, drug classes,
FAQ, news, ratings, auth flow, and saved med list.

Registers site in SITES arrays (websyn_start.sh, control_server.py) and
raises EXPOSE range to 40015 in Dockerfile. Seed DB at
instance_seed/drugs_com.db (managed via HuggingFace dataset).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@boyugou
boyugou marked this pull request as draft May 13, 2026 17:05
boyugou and others added 28 commits May 13, 2026 10:05
before_request hook logs in alice.j@test.com on every unauthenticated
request, so all protected routes work without real credentials.
login/register POST always redirect to account — any input is accepted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Complete visual overhaul matching the real drugs.com site:

Header: white background with colorful logo, A-Z browse strip,
search bar in header, dark navy nav with correct items (Drug
Interaction Checker, Compare Drugs, Pro Edition, More...).

Homepage: "Know more. Be sure." hero, feature icons row (My Med
List / Pill Identifier / Drug Interaction Checker / Drugs &
Medications), A-Z letter grid with Browse by Site Section panel,
popular drug searches tag cloud.

Drug detail: "What is X?" section, reviewer avatar with initials,
tab nav (Uses/Warnings/Before taking/Dosage/Side effects/Interactions/FAQ),
Drug Status sidebar with icons (Rx/OTC badges, pregnancy, CSA, approval,
ingredients), rating bar, related drugs, more-about links.

All other pages (A-Z, interaction checker, pill identifier, news,
conditions list, condition detail, drug class, search, account,
My Med List, login, register) rewritten to match real site layout,
content labels, and structure.

CSS completely rewritten: light/white theme, real drugs.com color
palette, component classes for all new UI patterns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…remove slug

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…features

- Expand drug catalog from 81 to 212 drugs across all major categories
- Expand drug classes from 57 to 95, conditions from 30 to 49
- Expand interactions from 22 to 127 with realistic severity/descriptions
- Expand news articles from 20 to 64 across FDA Alerts, Drug Approvals, Medical News, Clinical Trials, Health
- Add Pro Edition page, Drug Compare side-by-side, Sitemap, Newsletter
- Add Side Effects search, Drug Warnings/Black Box warnings pages
- Add Terms, Privacy, Contact pages
- Add drug images gallery and drug pricing pages
- Add My Reviews and Account Settings pages
- Fix all broken nav links (Pro Edition, Compare Drugs)
- Fix all broken footer links (Terms, Privacy, Contact, Sitemap)
- Fix account tab links (My Reviews, Settings)
- Add review submission route with rating update
- Add review form on drug detail with rating slider
- Improve interaction checker with severity badges and summary
- Improve search with filters, pagination, condition detection
- Improve pill identifier with shape-aware SVG icons
- Add dark mode support via prefers-color-scheme media query
- Add mobile responsive breakpoints
- Additive seeding: all seed functions add missing rows instead of early-returning

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add whole-function early-return gate to seed_database(). Per AGENTS.md,
per-row gates aren't sufficient because even a no-op commit bumps SQLite
metadata. With Drug.query.count() > 0, all seeding is skipped on
subsequent boots, preserving byte-identity between instance/ and
instance_seed/ after /reset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…il pages

- Add /<slug>/dosage and /<slug>/side-effects detail routes + templates
- Add drug_classes.html with alphabetical grid and drug counts
- Improve drug_class.html: Rx/OTC column, ratings, related classes sidebar
- Improve condition.html: rating table, sort by rating/name, related conditions
- Improve drug_detail.html: print/share/images/pricing action buttons, dosage
  info sidebar box, enhanced approval history, improved More About links
- Improve drug_az.html: side effects and drug interactions category links
- Add related articles sidebar to news_article.html
- Add condition sort (rating/name) and related conditions to condition_page route
- Add drug_count_val annotation and use drug_classes.html in drug_classes_list
- Add related_classes to drug_class_page route

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…opics

- Add /<slug>/pregnancy page with FDA pregnancy category badge + info
- Add /<slug>/interactions page with severity-sorted interaction table
- Add interaction checker ?drug=<slug> URL param pre-population
- Update drug_detail.html More About links: pregnancy, interactions
- Homepage: add Browse by Health Topic grid, FDA Alerts strip, newsletter signup
- CSS: topic cards, FDA badge, newsletter strip dark navy footer section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /<slug>/reviews page with pagination, condition/sort filters, rating bars
- Add /account/subscriptions page with email notification preferences
- Add /account/settings save route (mock, always succeeds)
- Add /account/subscriptions/save route
- Fix account.html Subscriptions tab href
- Improve drug_detail.html reviews section: filter/sort bar, data attributes,
  Was this helpful counter, View all reviews link, client-side JS filtering
- Improve account_settings.html: profile form, privacy toggles, connected apps,
  danger zone delete account

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add format_drug_text Jinja filter to convert raw FDA label text into
  readable paragraphs with sentence grouping and section headers
- Apply filter to drug detail, dosage, side effects templates
- Fix dark mode CSS contrast for drug detail content sections
- Add Related News sidebar to drug detail page
- Add news search and category filter to news index
- Rename news section to Pharmaceutical News and Articles
- Add newsletter subscription sidebar to Drug A-Z page
- Add Symptoms tab to homepage browse section
- Add Symptoms Checker to More... dropdown nav
- Make letter buttons circular (38x38) throughout
- Add feature carousel with < > arrows to homepage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add JS tab switching to drug detail page (click tab shows only that section)
- Fix drug_az route: pass active_letter/all_letters so A-Z nav renders
- Fix compare_drugs: remove invalid Jinja2 list comprehensions, add drug3
  support, fix action to use url_for, add more comparison rows
- Fix interaction checker datalist to include brand name options
- Fix Pro Edition calculators: BMI, CrCl, body weight now interactive
- Remove alert() from Pro Edition newsletter form (show inline confirm)
- Fix drug detail sidebar: pregnancy link -> drug_pregnancy route,
  remove duplicate More About links, fix approval history link
- Add /my-account.html and /my-med-list.html URL aliases
- Fix news.html hidden field (active_category -> cat)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cts A-Z

- Add drug thumbnail image to drug detail page header
- Add Drug Images section to homepage with 6 random pill images grid
- Add helpful vote buttons (Yes/No) to reviews with live JS update
- Improve reviews page: rating distribution bars, sort/filter by condition
- Improve search: brand name matching, grouped results (drugs/conditions/news),
  difflib-based "Did you mean?" suggestions
- Improve side effects page: A-Z navigation, 60 curated side effects,
  most commonly searched section, search box

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…icles

- Add generate_drug_prices() with realistic pharmacy price comparison table
  (CVS, Walgreens, Walmart, GoodRx) based on drug tier (OTC/generic/brand)
- Add related drugs section to drug detail page (same drug class, up to 6)
- Add drug interaction count to interactions tab
- Add per-drug warnings page (/<slug>/warnings) with boxed warning section
  and keyword-categorized warning cards
- Add warnings index page with A-Z drug list linking to per-drug warnings
- Improve pill identifier: realistic SVG pill shapes per pill type, imprint
  text displayed on pill, availability badge, size filter removed (unsupported)
- Improve conditions page: top conditions bar, letter filter, drug count badges
- Improve news article: medically reviewed notice, fast facts box, share
  buttons, references section, related articles sidebar improvements
- Improve interaction checker: group results by severity with colored headers,
  summary count banner, drug-food/alcohol interaction sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…vements

- Add /api/autocomplete endpoint (drug generic + brand + conditions)
- Wire autocomplete dropdown to header search bar with keyboard nav
- Add utility bar to base.html (Apps/Newsletter/Community/Pro)
- Improve footer with 4 columns: Company, Drugs, Conditions, News
- Improve homepage: popular searches, New Drug Approvals section
- Track recently viewed drugs in session, show in account page and
  drug detail sidebar
- New Drug Approvals section on homepage from news articles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ovements

- Add symptom checker page with body system categories and condition mapping
- Improve More dropdown: two-column layout with Browse and Tools sections
- Add sort controls to drug class detail page (A-Z, rating, reviews)
- Improve pregnancy page: trimester guidance, bottom line summary box
- Improve dosage page: structured dosage table, max dose warning, storage
- All new pages verified 200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cker verified

- Add contextual FAQ generation from drug data (uses/side_effects/availability)
- Render FAQ section as accordion with details/summary elements
- Polish login page: social login buttons, remember me, forgot password
- Polish register page: password strength indicator, terms checkbox
- Improve account settings: profile section, notification prefs, privacy settings
- Docker: all 16 sites return 200, byte-identity reset verified (md5 match)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… checker

- Pro Edition: 4 working clinical calculators (BMI, CrCl, IBW, BSA)
- FDA Safety Alerts sidebar on news page with red-bordered callout box
- Drug detail related news: search by drug/brand name in title/body
- NewsArticle.slug computed property + /news/<slug>-<id> URL aliases
- Symptom checker with 7 body systems and condition mapping

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /conditions/<slug> alias (was /condition/<slug> singular only)
- Add delete review route and button in account reviews
- Add edit notes functionality in My Med List with textarea toggle
- Add My Stats section to account page (med count, review count, joined date)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… colors

- Add visual star rating (★½☆) to drug header with avg_rating/10 numeric
- Add prominent blue "Add to My Med List" CTA button at top of drug page
- Sync top and sidebar med list toggle buttons via shared JS handler
- Rx badge: blue, OTC badge: green, Rx/OTC badge: purple
- Docker build verified: all 16 sites 200, byte-identity md5 match

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r counts

- Add CLASS_DESCRIPTIONS for 15 drug classes with mechanism explanations
- Drug class page now shows description, common conditions, notable drugs
- Conditions page: featured conditions box, alphabetical letter sections,
  drug count badges per condition
- Drug A-Z: letter buttons show drug count (A (23)), popular drugs section
- Autocomplete dropdown groups results as Drugs / Conditions sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…scriptions

- Homepage browse section: 4 functional tabs (Drugs A-Z, Conditions,
  Drug Classes, Symptoms) with server-side grids toggled by JS
- Search: related searches via difflib close matches
- top_conditions and top_drug_classes passed to homepage
- Docker build verified clean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tems helper

- Add What to Avoid section (new tab) with drug-class-specific warnings:
  NSAIDs→alcohol/ibuprofen+warfarin, SSRIs→alcohol/MAOIs, opioids→alcohol/driving,
  statins→grapefruit, anticoagulants→NSAIDs/vitamin-K, benzodiazepines→alcohol
- Improve Before Taking section: blue info box + structured bullet list with
  links to interaction checker and pregnancy page
- Add _build_avoid_items() helper keyed by drug class name keywords

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…consumer)

- 4 FDA Alerts: Xeljanz liver injury, fluoroquinolone tendons, testosterone CV,
  ketoconazole hepatotoxicity
- 4 New Drug Approvals: lecanemab Alzheimer's, tirzepatide weight, nirsevimab
  RSV, sickle cell gene therapy
- 4 Clinical Trials: semaglutide CV, pembrolizumab breast cancer, aspirin
  primary prevention, depression combination therapy
- 4 Medical/Consumer: PPIs kidney risk, statin muscle gene, acetaminophen
  pregnancy, generic drug shortages
- Per-title idempotency gate means new articles auto-insert on next fresh seed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e capsule SVG

- Rewrite drug_images.html: per-shape SVG (round/oval/capsule/etc), radial
  gradient depth, two-tone capsule halves with complementary colors, imprint
  text on pill, drug class and brand names header
- Interaction checker empty state: How it works info box, 6 common interaction
  quick-fill buttons (Warfarin+Aspirin, Fluoxetine+Tramadol, etc.)
- Interaction checker results: allergy reminder callout at top of results

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Print button uses window.print() with @media print CSS hiding nav/sidebar/tabs
- Share button uses Web Share API with clipboard fallback ("Link copied!" feedback)
- Speaker icon near drug name triggers SpeechSynthesisUtterance at rate 0.8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ovements

- Drug prices: 30/60/90 quantity tabs with deterministic pricing (md5 seed)
- GoodRx-style coupon section with inline code reveal
- "What affects the price?" 4-card info grid
- Account reviews: star rating display, drug name linked, date, Edit button
- Account: saved searches section with 3 example queries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r checkboxes

- Drug A-Z: rich drug cards (class badge, Rx/OTC, rating, description excerpt)
- Drug A-Z sidebar: Browse by Drug Type, Popular Drug Classes, Popular Conditions
- Sitemap: 4-column layout (Drug Info, Tools, News, User Tools) with url_for links
- Contact: full contact form with subject dropdown, 911 emergency warning,
  editorial/medical team info, JS submit confirmation
- Newsletter: 4 subscription options (daily/weekly/monthly/trials), recent topics

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p drugs

- Pro Edition: professional drug lookup widget, clinical monographs grid,
  professional resources grid (interactions, FDA, prescribing, calculators)
- Drug classes list: class data dict with drug count, top 3 drugs, description
- Drug classes template: count badge, description excerpt, top drug links,
  alphabetical grouping
- CSS: .tag-class pill style (blue, rounded)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…unter

- 10-star clickable rating selector with hover/click JS (replaces slider)
- Review form: duration dropdown (1mo/1-6mo/6mo-1yr/1-2yr/2yr+)
- Review form: character counter (0/1000) for body textarea
- Review cards: 5-star visual display, condition/duration pill tags,
  full-month date format, helpful votes retained
- CSS: .star-selector, .star-btn, .review-stars, .review-tag, .char-count

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@boyugou boyugou changed the title [WIP] Add drugs.com mirror site (port 40015) feat(drugs_com): add drugs.com mirror site (port 40015) May 15, 2026
@boyugou
boyugou marked this pull request as ready for review May 15, 2026 04:13
hqhq1025 pushed a commit to hqhq1025/WebHarbor that referenced this pull request May 26, 2026
Conflicts resolved:
- websyn_start.sh: keep PR's dynamic count (${#SITES[@]}) — removes the
  hardcoded "16" from aiming-lab#11/aiming-lab#29 base; append drugs_com after berkeley.
- control_server.py: append drugs_com after berkeley.
- Dockerfile EXPOSE 40000-40016 → 40000-40017; keep berkeley build-time
  RUN; pick up requests==2.32.3 dep from PR.
- .gitignore: merge both sides (keep main's dashboard ignores + PR's
  local artifact ignores).

Note: drugs_com seeds via pre-built HF db (refs/pr/13), so the dynamic
bcrypt salt in app.py's set_password does NOT cycle on reset.
hqhq1025 pushed a commit to hqhq1025/WebHarbor that referenced this pull request May 27, 2026
…tch learnings

verify-site-gui:
- PER_SLUG examples expanded with 5 P0 sites (eventbrite/smartasset/apartments_com/mayo_clinic/fandom)
  showing the _url_overrides pattern for multi-placeholder URLs (Avoids "amanda-dixon" pollution)
- Add 2 new false-positive categories (aiming-lab#8 template:null download endpoints, aiming-lab#9 designed-404 fallback pages)
  + corresponding harness filter logic
- Add 2 new real-bug categories: §5 byte-identical reset broken by bcrypt salt / hash() / utcnow non-determinism
  (fandom dc5b676 fix pattern); §6 circular import in python3 app.py standalone (apartments 850465d fix)
- Document max_pages CLI 3rd arg (python3 _verify_playwright.py mayo_clinic 50034 80 to cover full 77 pages)
- Document agent-dispatch traps: no SendMessage tool; worktree baseRef defaults to origin so misses unpushed work

document-site-gui:
- Add explicit "incremental Write/Edit mandatory" rule with 4-step procedure
- MD 50-130 KB + YAML 100-200 KB targets cannot fit a single Write tool call (32k output token cap)
- Prior agents hit this and stopped at "let me write the file" with nothing written
@YuanDaoze

Copy link
Copy Markdown

Review

Tested on a fresh worktree of this branch. HF asset (drugs_com.tar.gz, 5 MB) pulled directly from the dataset PR ref (refs/pr/13), the other 15 sites' assets hard-linked from upstream/main. Built as webharbor:rev9, run on alt ports :8221 / :42200-42215 to avoid colliding with the dev container.

What works ✓

Mechanical

  • Three-place registration in sync (websyn_start.sh SITES, control_server.py SITES, Dockerfile EXPOSE 8101 40000-40015).
  • All 16 sites alive after boot. drugs_com on :42215 returns 200.
  • Byte-identical reset holds: md5(instance/drugs_com.db) == md5(instance_seed/drugs_com.db) == bfc94f8ff61fbbd553ae496217588bad both before and after POST /reset/drugs_com — matches the value claimed in the PR description.
  • Seed gating is textbook-correct: a single top-level gate in seed_database() (if Drug.query.count() > 0: return) protects all 11 sub-seeds, with an explicit comment explaining why per-row gates aren't enough. This is the cleanest implementation of the AGENTS.md idempotency rule I've seen.
  • Build context clean — no .db files, no static/images/, no scraped_data/ committed. .gitignore and .dockerignore cover runtime data and tarballs properly.
  • tasks.jsonl has 21 tasks, all five required fields on every line, port matches 40015.

Functional depth

  • 169 routes, 49 templates, 7080-line app.py. Most thorough single-site mirror in the repo.
  • /drug-interactions?drugs=ibuprofen,warfarin (GET-style, supports comma-separated multi-drug input) returns categorized results: drug-drug + drug-food (vitamin K, cranberry juice) + drug-alcohol, with severity badges (Major / Moderate / Minor). The 3-drug variant ?drugs=alprazolam,oxycodone,fluoxetine also works.
  • /pill-identifier has imprint + shape (round/oval/capsule/oblong/+5 more) + color (12 colors) form fields, real pill JPGs for 43 drugs from HF + inline-SVG fallback for the rest via the _pill_svg.html macro.
  • /drug-classes/, /conditions/, /news/ all populated. Drug detail page at /<slug>.html has full sections: black-box warnings, uses, before-taking, dosage, side effects, interactions, FAQ accordion, related drugs.
  • Login (alice.j@test.com / TestPass123!) works. /my-med-list shows alice pre-seeded with ibuprofen + metformin + atorvastatin (matches PR description) and her 3 saved drugs are listed with Rx/OTC badges, edit/remove actions, and a "Check all 3 medications for interactions" CTA.
  • /search?q=... aggregates across drugs / classes / conditions — 24/57/48 results for ibuprofen / diabetes / antibiotics.

Task quality

  • 21 tasks span 8 categories: drug detail lookup, search, interaction checker (2-drug + 3-drug), pill identifier (imprint, shape+color), A-Z browsing, drug class, condition, news, authenticated med list, reviews/ratings.
  • Difficulty spans simple lookup (--0 ibuprofen drug class) → multi-step (--14 login + add drug to med list) → multi-result aggregation (--13 first 3 white oval pills).
  • Spot-checked 5 risky tasks; all answerable from canonical pages:
    • --3 pill imprint I-2/pill-identifier?imprint=I-2 returns Round/Oval results with Ibuprofen
    • --9 Statins class → /drug-classes/statins lists Atorvastatin, Lipitor, Simvastatin, Rosuvastatin, Crestor
    • --15 lisinopril pregnancy → black-box warning text on /lisinopril.html explicitly mentions "FDA Pregnancy Category D"
    • --8 3-drug interaction → returns major/moderate/minor verdicts
    • --14 lisinopril is correctly NOT in alice's pre-seeded list (so the task can verify the add-to-med-list action took effect)
  • No count-leak or single-item-catalog leaks found in spot checks.

Should-fix (non-blocking)

1. .assets-revision pinned to main, but drugs_com.tar.gz is in HF PR ref refs/pr/13 and not yet merged.

A fresh git clone + ./scripts/fetch_assets.sh will silently skip drugs_com (the file isn't on main) → drugs_com won't have a seed DB → the site won't boot. This is the same problem as PR #32 (gov_uk).

Fix one of:

  • Get the HF PR merged to main and bump .assets-revision to that commit SHA (cleanest);
  • Or temporarily pin .assets-revision to a fork/PR ref that includes drugs_com (the merriam_webster PR uses this pattern via repo: YuanDaozeiii/WebHarbor until the upstream HF PR merges).

2. macOS ._* AppleDouble files in drugs_com.tar.gz.

The tarball was created on macOS with default tar, which embedded 51 AppleDouble metadata files (1:1 with real files). They're 4 KB each and tar tzf triggers a stream of LIBARCHIVE.xattr.com.apple.provenance warnings. They don't break anything functionally (extracted as ._foo, ignored by Flask), but they bloat the tarball and pollute static/images/pills/.

Fix: re-create with COPYFILE_DISABLE=1 tar czf drugs_com.tar.gz drugs_com/ and re-upload. Same problem affects gov_uk's tarball, so a one-line README note in the asset workflow doc would help future contributors.

3. PR base is 3c408d8 init, way behind upstream/main.

A rebase is needed before merge. With 187 commits in this branch, an interactive squash to ~5 logical commits would also help reviewability.

4. requirements.txt is unused and mis-pinned.

The file lists deps with no version pins and is never read at build time (the Dockerfile pip-installs explicitly with locked versions). Either delete it (it's noise) or make it the source of truth and have the Dockerfile use it. AGENTS.md says "Lock dependency versions in Dockerfile's pip install — the image must be reproducible", so the current Dockerfile approach is correct; the requirements.txt file is dead code.

5. _pill_svg.html SVG fallback occasionally renders for drugs that DO have a real JPG in the asset bundle.

Spot-checked /ibuprofen.html — page contains 12 inline SVG <svg> elements but static/images/pills/ibuprofen.jpg returns 404 (only 43 drugs have real JPGs out of ~250). For those 43 the page does load the JPG. Working as designed; just noting for completeness.

Bottom line

Genuinely impressive depth — 169 routes, full interaction checker with drug-food/drug-alcohol, working pill identifier, real-data pregnancy categories, accordion FAQ, etc. Seed idempotency design is the cleanest in the project. The only real friction is on the asset-distribution side: .assets-revision needs to point to where drugs_com.tar.gz actually lives, and the macOS tar junk should be cleaned up before re-upload. Once those land, this is solidly mergeable.

@boyugou

boyugou commented Jun 4, 2026

Copy link
Copy Markdown
Author

Review

Tested on a fresh worktree of this branch. HF asset (drugs_com.tar.gz, 5 MB) pulled directly from the dataset PR ref (refs/pr/13), the other 15 sites' assets hard-linked from upstream/main. Built as webharbor:rev9, run on alt ports :8221 / :42200-42215 to avoid colliding with the dev container.

What works ✓

Mechanical

  • Three-place registration in sync (websyn_start.sh SITES, control_server.py SITES, Dockerfile EXPOSE 8101 40000-40015).
  • All 16 sites alive after boot. drugs_com on :42215 returns 200.
  • Byte-identical reset holds: md5(instance/drugs_com.db) == md5(instance_seed/drugs_com.db) == bfc94f8ff61fbbd553ae496217588bad both before and after POST /reset/drugs_com — matches the value claimed in the PR description.
  • Seed gating is textbook-correct: a single top-level gate in seed_database() (if Drug.query.count() > 0: return) protects all 11 sub-seeds, with an explicit comment explaining why per-row gates aren't enough. This is the cleanest implementation of the AGENTS.md idempotency rule I've seen.
  • Build context clean — no .db files, no static/images/, no scraped_data/ committed. .gitignore and .dockerignore cover runtime data and tarballs properly.
  • tasks.jsonl has 21 tasks, all five required fields on every line, port matches 40015.

Functional depth

  • 169 routes, 49 templates, 7080-line app.py. Most thorough single-site mirror in the repo.
  • /drug-interactions?drugs=ibuprofen,warfarin (GET-style, supports comma-separated multi-drug input) returns categorized results: drug-drug + drug-food (vitamin K, cranberry juice) + drug-alcohol, with severity badges (Major / Moderate / Minor). The 3-drug variant ?drugs=alprazolam,oxycodone,fluoxetine also works.
  • /pill-identifier has imprint + shape (round/oval/capsule/oblong/+5 more) + color (12 colors) form fields, real pill JPGs for 43 drugs from HF + inline-SVG fallback for the rest via the _pill_svg.html macro.
  • /drug-classes/, /conditions/, /news/ all populated. Drug detail page at /<slug>.html has full sections: black-box warnings, uses, before-taking, dosage, side effects, interactions, FAQ accordion, related drugs.
  • Login (alice.j@test.com / TestPass123!) works. /my-med-list shows alice pre-seeded with ibuprofen + metformin + atorvastatin (matches PR description) and her 3 saved drugs are listed with Rx/OTC badges, edit/remove actions, and a "Check all 3 medications for interactions" CTA.
  • /search?q=... aggregates across drugs / classes / conditions — 24/57/48 results for ibuprofen / diabetes / antibiotics.

Task quality

  • 21 tasks span 8 categories: drug detail lookup, search, interaction checker (2-drug + 3-drug), pill identifier (imprint, shape+color), A-Z browsing, drug class, condition, news, authenticated med list, reviews/ratings.

  • Difficulty spans simple lookup (--0 ibuprofen drug class) → multi-step (--14 login + add drug to med list) → multi-result aggregation (--13 first 3 white oval pills).

  • Spot-checked 5 risky tasks; all answerable from canonical pages:

    • --3 pill imprint I-2/pill-identifier?imprint=I-2 returns Round/Oval results with Ibuprofen
    • --9 Statins class → /drug-classes/statins lists Atorvastatin, Lipitor, Simvastatin, Rosuvastatin, Crestor
    • --15 lisinopril pregnancy → black-box warning text on /lisinopril.html explicitly mentions "FDA Pregnancy Category D"
    • --8 3-drug interaction → returns major/moderate/minor verdicts
    • --14 lisinopril is correctly NOT in alice's pre-seeded list (so the task can verify the add-to-med-list action took effect)
  • No count-leak or single-item-catalog leaks found in spot checks.

Should-fix (non-blocking)

1. .assets-revision pinned to main, but drugs_com.tar.gz is in HF PR ref refs/pr/13 and not yet merged.

A fresh git clone + ./scripts/fetch_assets.sh will silently skip drugs_com (the file isn't on main) → drugs_com won't have a seed DB → the site won't boot. This is the same problem as PR #32 (gov_uk).

Fix one of:

  • Get the HF PR merged to main and bump .assets-revision to that commit SHA (cleanest);
  • Or temporarily pin .assets-revision to a fork/PR ref that includes drugs_com (the merriam_webster PR uses this pattern via repo: YuanDaozeiii/WebHarbor until the upstream HF PR merges).

2. macOS ._* AppleDouble files in drugs_com.tar.gz.

The tarball was created on macOS with default tar, which embedded 51 AppleDouble metadata files (1:1 with real files). They're 4 KB each and tar tzf triggers a stream of LIBARCHIVE.xattr.com.apple.provenance warnings. They don't break anything functionally (extracted as ._foo, ignored by Flask), but they bloat the tarball and pollute static/images/pills/.

Fix: re-create with COPYFILE_DISABLE=1 tar czf drugs_com.tar.gz drugs_com/ and re-upload. Same problem affects gov_uk's tarball, so a one-line README note in the asset workflow doc would help future contributors.

3. PR base is 3c408d8 init, way behind upstream/main.

A rebase is needed before merge. With 187 commits in this branch, an interactive squash to ~5 logical commits would also help reviewability.

4. requirements.txt is unused and mis-pinned.

The file lists deps with no version pins and is never read at build time (the Dockerfile pip-installs explicitly with locked versions). Either delete it (it's noise) or make it the source of truth and have the Dockerfile use it. AGENTS.md says "Lock dependency versions in Dockerfile's pip install — the image must be reproducible", so the current Dockerfile approach is correct; the requirements.txt file is dead code.

5. _pill_svg.html SVG fallback occasionally renders for drugs that DO have a real JPG in the asset bundle.

Spot-checked /ibuprofen.html — page contains 12 inline SVG <svg> elements but static/images/pills/ibuprofen.jpg returns 404 (only 43 drugs have real JPGs out of ~250). For those 43 the page does load the JPG. Working as designed; just noting for completeness.

Bottom line

Genuinely impressive depth — 169 routes, full interaction checker with drug-food/drug-alcohol, working pill identifier, real-data pregnancy categories, accordion FAQ, etc. Seed idempotency design is the cleanest in the project. The only real friction is on the asset-distribution side: .assets-revision needs to point to where drugs_com.tar.gz actually lives, and the macOS tar junk should be cleaned up before re-upload. Once those land, this is solidly mergeable.

Thanks for the review! Will fix accordingly soon

boyugou and others added 3 commits June 24, 2026 17:44
upstream/main added merriam_webster as the 16th site (index 15, port 40015) plus a booking image fix. This branch independently added drugs_com as a 16th site at the same index/port. Resolve the collision so both coexist:

- websyn_start.sh / control_server.py: SITES order ends '... espn merriam_webster drugs_com'. merriam_webster keeps index 15 / port 40015 (already released upstream); drugs_com moves to index 16 / port 40016.
- Dockerfile: EXPOSE 8101 40000-40016; header comment now 17 sites.
- drugs_com/tasks.jsonl: 21 task 'web' URLs 40015 -> 40016.
- drugs_com/CLAUDE.md: port references 40015 -> 40016.
- Keep the dynamic ${#SITES[@]} readiness/echo lines over upstream's hardcoded 16.

Also pulls in upstream's contributor-contract docs (AGENTS.md / CONTRIBUTING.md): tasks.jsonl ships only the 5 base keys; the reviewer later adds verifier_path + judge_rubric.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- scripts/extract_assets.sh: pack with COPYFILE_DISABLE=1 and pre-strip ._*/.DS_Store so macOS bsdtar stops embedding AppleDouble sidecars (synthesized from com.apple.provenance xattrs) into every <site>.tar.gz. Fixes the 51 ._* files the reviewer found in drugs_com.tar.gz; GNU tar ignores the env var so Linux packing is unaffected. Also benefits any future macOS-packed site.
- sites/drugs_com/tasks.jsonl (task --10): repoint to an FAQ entry that actually exists. The generated ibuprofen FAQ has no 'empty stomach' item (that guidance is in the Dosage section), so the old wording was unanswerable from the FAQ as instructed. Now asks the FAQ 'how should I take ibuprofen' entry (OTC dose + 24h max).
- sites/drugs_com/requirements.txt: drop Flask-WTF (never imported; no CSRF/WTForms/FlaskForm usage). File kept: a per-site requirements.txt is the new_site.py scaffold convention and merriam_webster ships one too; the Dockerfile stays the pinned source of truth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- .dockerignore: ignore .venv/ (not just venv/). This repo standardizes on uv, which creates .venv; .gitignore already covers it but .dockerignore did not, so a local build leaked the dev venv (~1k files) into the COPY context. Aligns the two ignore files.
- sites/drugs_com/CLAUDE.md: note the asset packer is macOS-safe (drop stale 'PR aiming-lab#13' reference).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@boyugou boyugou changed the title feat(drugs_com): add drugs.com mirror site (port 40015) feat(drugs_com): add drugs.com mirror site (port 40016) Jun 25, 2026
@boyugou

boyugou commented Jun 25, 2026

Copy link
Copy Markdown
Author

Update — merged upstream/main, addressed review feedback, drugs_com moved to port 40016

Why the port changed. upstream/main merged merriam_webster (#44) into the 16th slot (index 15 → port 40015) — the slot this PR originally used. I merged main into this branch and moved drugs_com to index 16 / port 40016 so the two coexist; merriam_webster keeps its released 40015. Registration is back in sync (websyn_start.sh, control_server.py, Dockerfile EXPOSE 8101 40000-40016), the 21 task URLs now use 40016, and GitHub reports no conflicts with base. The PR title/description have been updated to 40016.

Review feedback addressed (the 3 new commits):

  • AppleDouble junkscripts/extract_assets.sh now packs with COPYFILE_DISABLE=1 and strips ._*/.DS_Store, so no <site>.tar.gz embeds macOS sidecars (the 51 ._* files came from com.apple.provenance xattrs). Regenerated a clean drugs_com.tar.gz0 AppleDouble entries, DB md5 unchanged → re-submitted as a HuggingFace dataset PR (https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/39), replacing the earlier junk tarball.
  • requirements.txt kept (it's the new_site.py scaffold convention and merriam_webster ships one too), but the genuinely-unused Flask-WTF was pruned.
  • .assets-revision pin: will be bumped to the merged HF SHA once that HuggingFace PR lands (currently inherits upstream's pin, which predates drugs_com).

Self-review fix (not in the original review): task --10 asked what the ibuprofen FAQ says about taking it "on an empty stomach", but the generated FAQ has no such entry (that guidance is in the Dosage section) — reworded to target an FAQ entry that exists. Also added .venv to .dockerignore (repo uses uv).

Verification on this branch (full 17-site image):

  • All 17 sites → 200; all drugs_com task routes → 200.
  • Byte-identical reset: POST /reset/drugs_commd5(instance) == md5(instance_seed) == bfc94f8ff61fbbd553ae496217588bad.
  • Task-14 med list correct (alice: ibuprofen / metformin / atorvastatin, not lisinopril); interaction checker returns Major for ibuprofen + warfarin.

Paired asset PR: ChilleD/WebHarbor HuggingFace dataset — https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/39 (clean tarball). Merge that first, then bump .assets-revision.

Note for maintainers — port coordination: drugs_com now claims 40016. PR #24 (CarMax) still references 40015, which merriam_webster (#44) already occupies on main; whichever of the remaining site PRs merges next will need its own free index.

@MufanQiu

MufanQiu commented Jul 1, 2026

Copy link
Copy Markdown

Review — drugs_com (PR #9)

Verdict: REQUEST CHANGES.

We deployed the environment locally and ran the full review checklist; every finding below was independently reproduced, and fidelity was checked against the real upstream site.

Issues (summary)

  • BLOCKER: .assets-revision SHA presence on HuggingFace not verifiable locally (CI fail-closed risk)
  • MAJOR: Answer-leak: 5 tasks fully solvable on the /search results page (no detail-page click)
  • MINOR: Difficulty too low / illusory auth: most tasks are 1-2 actions; the one auth task is a no-op
  • MINOR: AppleDouble '._*' junk (48 files) ships inside the image via the pinned tarball
  • MINOR: Data inconsistencies: brand-as-generic duplicate rows and a CSA value in the availability field
  • NIT: CLAUDE.md quick-start has an inconsistent port (49015 vs 49016/40016)

Mechanical checks: PASS (with nits)

  • Reset invariant holds. instance_seed/drugs_com.db and instance/drugs_com.db are byte-identical (md5 bfc94f8ff61fbbd553ae496217588bad), and a fresh boot leaves the instance md5 unchanged.

Visual fidelity: PASS

Faithful reproduction of the dark-blue header, "Know more. Be sure." tagline, A-Z browse bar, health-category tiles, drug-images strip, featured drugs, and medical-news sections.

Functional depth: PASS (with nits)

Deep, DB-backed behaviour. Search is scored (not strict-AND) with brand/condition/class boosts, an exact-match "Best match" card, a "Did you mean?" fuzzy fallback ("ibuprofin"→ibuprofen), and working multi-word queries.

Task quality: FAIL

21 tasks, all solvable against the DB and reachable in the UI, atop a large catalog with strong distractor density (251 drugs, 95 classes, 68 conditions, 80 news, 76 interactions, 103 pill images, 748 reviews).

Required fixes before approval

  1. Eliminate the search-results answer-leak (F1, now ≥10 tasks). In templates/search.html, remove drug class, brand names, CSA-schedule chip, rating/review_count, AND the uses/description blurb from both the .drug-card (lines 169-201) and the "Best match" card (lines 16-52).
  2. Fix illusory auth and raise difficulty (F2). Make the login handler actually validate alice.j@test.com / TestPass123! and gate @login_required routes (or remove the auto_login shim) so Task 14's sign-in is genuinely exercised.
  3. Repack and re-pin assets (F3 + F5 + instance_seed sidecar). Rerun scripts/extract_assets.sh (strips ._*/.DS_Store, packs COPYFILE_DISABLE=1), upload a clean drugs_com.tar.gz, and update .assets-revision to a MERGED HF SHA that contains it.
  4. Clean up data inconsistencies (F4). Set suvorexant.availability to Rx and move C-IV into csa_schedule only; fix the five inverted brand-as-generic duplicate rows so generic_name is the real generic (or drop the duplicates).
  5. Fix the CLAUDE.md quick-start port typo (F6). Change the verify curl from 49015 to 49016 to match -p 49016:40016 (docs-only).

boyugou and others added 2 commits July 9, 2026 14:19
Review feedback (aiming-lab#9): the search results page rendered drug_class, brand_names, the CSA-schedule chip, avg_rating/review_count, and a uses/description snippet directly in both the 'Best match' exact-match card and the .drug-card list results — none of it gated behind a click-through to the detail page. At least 4 tasks (drug class, brand names, availability, rating+review count) could be answered from the search page alone.

Stripped all of the above from both card types and from the popular_for_query sidebar (same issue via a brand-name + availability badge). Search results now show only the drug name and navigation links; every field still exists on the detail page, just requires a click to reach.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auth (review finding: illusory auth)
A before_request hook silently logged every request in as alice regardless
of the /login form, so task 14's sign-in step was a no-op. Removed it and
rewrote login()/register() to do real bcrypt-checked auth, matching the
pattern already used by amazon/allrecipes/bbc_news/github/coursera/
merriam_webster. Verified: wrong password rejected, correct password
succeeds, anonymous access to @login_required routes redirects to /login.

CSRF protection (found during a follow-up auth-security review)
drugs_com was the only one of 17 sites without CSRFProtect(app) -- every
other site (including the two the auth rewrite was modeled on) has it.
Added CSRFProtect, a csrf_token() hidden field to all 19 classic
<form method="post"> submissions across 14 templates, and @csrf.exempt on
the 3 JSON/AJAX-only endpoints (matching the exact pattern other sites use
for their own AJAX endpoints). Re-added Flask-WTF to requirements.txt.

Seed data-quality fixes (review finding + a follow-up DRUGS_DATA sweep)
- suvorexant's availability field held a CSA schedule value ("C-IV")
  instead of "Rx" -- fixed to match every other controlled-drug row.
- Removed 5 brand-as-generic duplicate rows (januvia/jardiance/xarelto/
  xeljanz/xanax), each duplicating an already-correct generic row
  (sitagliptin/empagliflozin/rivaroxaban/tofacitinib/alprazolam). Kept
  janumet/yaz/yasmin -- legitimate distinct real-world branded products.
- 4 pharmacological misclassifications, found by cross-referencing every
  drug's class against that class's own description text: vancomycin
  (glycopeptide, not a Cephalosporin), colchicine (antigout, not a
  Xanthine oxidase inhibitor -- that's allopurinol), glipizide and
  nitrofurantoin (a sulfonylurea and a nitrofuran, neither is a
  Sulfonamide). Added 4 correctly-described classes and reassigned all 4.
- compare_drugs.html: removed 2 popular-comparison suggestions that
  referenced drugs absent from the catalog (orlistat, phentermine,
  glimepiride, insulin detemir).
- Docs (.assets-revision, CLAUDE.md): fixed a stray port reference
  (49015->49016), corrected task 14's description to match tasks.jsonl
  (it's read-only -- lists the med list, doesn't add to it), and updated
  drug/review counts + seed DB md5 for the regenerated seed.

None of the removed/reclassified drugs are referenced by any of the 21
benchmark tasks (grepped tasks.jsonl to confirm). Regenerated
instance_seed/drugs_com.db from scratch and reverified the idempotency
invariant. Full Docker verification: 17/17 sites 200, byte-identical
reset holds, real auth + CSRF verified against the running container with
cookies, all 21 tasks re-audited against the new DB (no regressions).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@boyugou

boyugou commented Jul 9, 2026

Copy link
Copy Markdown
Author

Update — addressed all 6 points from the review above, plus a self-initiated deeper pass

Went through each finding; all confirmed as real issues on inspection and fixed. Then ran three independent Sonnet-based review passes over the resulting diff (task-by-task re-audit, auth security review, DRUGS_DATA data-quality sweep) before calling this done, since search/auth/data are exactly the areas most likely to regress silently. Summary below.

Review findings

BLOCKER — .assets-revision not verifiable. Confirmed: it was still pinned to a pre-drugs_com upstream SHA. Fixed by pinning to refs/pr/39 on the ChilleD/WebHarbor dataset (https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/39) — verified this ref is a strict superset of main (all 16 existing tarballs unchanged, plus drugs_com.tar.gz), and verified ./scripts/fetch_assets.sh drugs_com actually resolves it and extracts a working seed DB. Will re-pin to main (or the merge commit) once that HF PR merges.

MAJOR — search-results answer-leak. Confirmed by reading templates/search.html: both the "Best match" exact-match card and the .drug-card list results rendered drug_class, brand_names, the CSA-schedule chip, avg_rating/review_count, and a uses/description snippet — all without a click-through. Stripped all of it from both card types and from the popular_for_query sidebar (same issue via a brand-name + availability badge). Search results now show only the drug name and a link into the detail page; every field still exists, just gated behind a click.

MINOR — illusory auth. Confirmed: a before_request hook silently logged every request in as alice regardless of the /login form, so task 14's "sign in" step was a no-op. Removed that hook and rewrote /login and /register to do real bcrypt-checked auth, matching the pattern already used by every other site in the repo (bbc_news, allrecipes, amazon, github, coursera, merriam_webster). Verified end-to-end (wrong password rejected, correct password succeeds, anonymous access to @login_required routes now redirects to /login) both via the Flask test client and against the real container with cookies.

MINOR — AppleDouble junk still shipping. Traced back to the same root cause as the BLOCKER — the pinned revision didn't include the (already-cleaned) tarball from the first review round. Re-verified the packed tarball has 0 ._*/.DS_Store entries; reachable now via the refs/pr/39 pin.

MINOR — data inconsistencies. Confirmed both:

  • suvorexant's availability field was "C-IV" (a CSA schedule value) instead of "Rx" — fixed to match the pattern every other controlled-substance row follows.
  • 5 rows were brand-as-generic duplicates (januvia/jardiance/xarelto/xeljanz/xanax), each duplicating an already-correct generic row (sitagliptin/empagliflozin/rivaroxaban/tofacitinib/alprazolam). Removed all 5 — none were referenced by any task or by pill/interaction/pregnancy-risk data. (Kept janumet, yaz, yasmin — legitimate distinct real-world branded products, not the same bug.)

NIT — CLAUDE.md port typo. Fixed (4901549016).

Additional issues found during the self-review pass (not in the original review)

  • CSRF protection was missing. A dedicated auth-security review pass flagged that drugs_com was the only one of 17 sites without CSRFProtect(app) — every other site (including the two the auth rewrite was modeled on) has it. Added CSRFProtect, added a csrf_token() hidden field to all 19 classic <form method="post"> submissions across 14 templates, and @csrf.exempt on the 3 JSON/AJAX-only endpoints (matching the exact pattern other sites use for their own AJAX endpoints). Verified: a form POST without a token now gets rejected (400), the same form with its token succeeds, and the exempted JSON endpoints are unaffected.
  • 4 more drug-classification errors, found by a targeted sweep of the full DRUGS_DATA table cross-referenced against each class's own description text: vancomycin was filed under "Cephalosporins" (it's a glycopeptide, not a beta-lactam — contradicts the class's own description), colchicine under "Xanthine oxidase inhibitors" (it doesn't inhibit xanthine oxidase — that's allopurinol), and glipizide/nitrofurantoin under "Sulfonamides" (an antidiabetic sulfonylurea and a nitrofuran, respectively — neither is a sulfonamide). Added 4 correctly-described classes (Glycopeptide antibiotics / Antigout agents / Sulfonylureas / Urinary anti-infectives) and reassigned all four. None of the 4 are referenced by any task.
  • 2 dead comparison suggestions on the Compare Drugs page referenced drugs that don't exist in the catalog (orlistat/phentermine, and one leg of a diabetes pairing) — removed those two broken suggestion pairs.
  • Docs vs. reality: two CLAUDE.md files described task 14 as "add lisinopril to alice's med list," but the actual task in tasks.jsonl is read-only (sign in, then list what's already saved). Fixed the docs to match; flagging for you separately in case you'd rather extend task 14 into a genuine write/add-action task — that's a benchmark-design call I didn't want to make unilaterally by editing the task file itself.
  • Added an explicit order_by(DrugImage.id) to the pill-identifier queries for deterministic "first N results" ordering (was relying on implicit SQLite row order).

Consequence: reseeded DB (twice)

Both the data fixes and the class reassignments required regenerating instance_seed/drugs_com.db from scratch and re-verifying the idempotency invariant each time (seed_database() on the new frozen seed leaves the instance byte-identical). Final counts: 246 drugs (251 − 5 duplicates), 780 reviews. Final seed DB md5: 22d3eeb82d7f2804592f0a9a0832485c (was bfc94f8ff61fbbd553ae496217588bad before any of this round's fixes — expected, since the underlying data changed). Re-uploaded the corrected tarball to the same HF PR rather than opening a new one.

Full re-verification after all of the above

Via a fresh Docker build + the real control plane (not just the Flask test client):

  • All 17 sites → 200.
  • POST /reset/drugs_commd5(instance) == md5(instance_seed) == 22d3eeb82d7f2804592f0a9a0832485c.
  • All 21 tasks' routes re-checked against the new DB by an independent review pass (no FAILs; nothing broke from removing the 5 duplicate drugs or reclassifying the other 4).
  • Real auth flow re-verified against the running container with actual cookies (wrong password → rejected; correct password → session → /my-med-list shows alice's 3 meds, not lisinopril).
  • CSRF re-verified: unauthenticated form POST without a token → 400; the same form with its token → succeeds; exempt JSON endpoints unaffected.
  • Re-swept templates/search.html output structurally (not substring grep) to confirm the .drug-card/.exact-match-card blocks contain nothing but name + navigation links across multiple queries (ibuprofen, semaglutide, atorvastatin, antibiotics).

Ran two independent Codex reviews (a different model family than what did the prior work) as a second-opinion pass over the search-leak/auth/CSRF/data fixes: one targeted re-check of those specific changes, one fully open-ended exploration. Both surfaced real issues the Sonnet-based reviews had missed.

CSRF exemption gaps (targeted review)
Two routes were @csrf.exempt despite actually consuming request.form/
request.values from a real browser form or FormData submission, not just
JSON -- meaning the csrf_token already present in those forms was silently
never checked:
- /my-med-list/toggle: removed the exempt; the JSON-only call site
  (drug_detail.html's save/remove buttons) now sends the token via an
  X-CSRFToken header, which Flask-WTF validates for non-form requests.
- /<slug>/review/<id>/helpful: removed the exempt; both FormData call
  sites (drug_detail.html, drug_reviews_page.html) now append csrf_token
  to the FormData alongside the vote.

Open redirect in login() (both reviews independently flagged this)
request.args.get("next") was passed straight to redirect() with no
validation. Added _safe_next_url() -- only allows a single-leading-slash
relative path, rejecting absolute/protocol-relative URLs -- and used it in
place of the raw query param.

Data: 7 drugs referencing undefined drug-class names (open-ended review)
memantine/trimethoprim/lecanemab/ezetimibe/ursodiol referenced class names
with no matching DRUG_CLASSES entry, so drug_class_id silently ended up
NULL for each (Drug.query cls_by_name.get() returns None, no error).
Added the 5 missing classes. umeclidinium and ulipristal referenced
near-miss class name variants ("Bronchodilators, long-acting",
"Progesterone agonists/antagonists") that didn't match anything either --
reclassified both into the existing, pharmacologically-correct classes
(Anticholinergic bronchodilators; Progestogens).

Three smaller bugs (open-ended review)
- 404 handler ordered by the nonexistent Drug.rating_count (typo for
  review_count, silently caught by a broad except and emptying the
  page's "Popular drugs" section).
- drug_side_effects.html and drug_dosage.html both referenced a
  DrugImage.dosage_form field that was never a real column, so the
  intended per-drug value was always the same fallback text. Simplified
  side_effects to the static fallback it already always rendered; dropped
  the dead reference from dosage.html's working shape/strength fallback.
- /api/interaction-check (a JSON endpoint, unreferenced by any template
  and unreachable through the UI -- confirmed no task depends on it, no
  regression risk) silently reported "alcohol" as unrecognized instead of
  resolving it via the same _lifestyle_interactions() helper the main
  interaction-checker UI already uses correctly.

Regenerated instance_seed/drugs_com.db (class assignments changed),
reverified idempotency, and reran the full Docker verification: 17/17
sites 200, byte-identical reset, and the CSRF fix confirmed live against
the running container (toggle rejected without a token, accepted with the
X-CSRFToken header).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@boyugou

boyugou commented Jul 9, 2026

Copy link
Copy Markdown
Author

Update — ran two independent Codex (GPT-family) reviews as a second opinion, fixed what they found

The prior round of fixes (search-leak removal, real auth, CSRF, seed-data cleanup) was checked by Sonnet-based subagents before landing. To get a genuinely independent second opinion — different model family, not just a different prompt — I ran two Codex reviews against the same diff: one a targeted re-check of those specific changes, one fully open-ended ("explore however seems useful, don't work off a checklist"). Both surfaced real issues.

CSRF exemption gaps (targeted review, then verified by hand). Two routes were @csrf.exempt despite genuinely consuming request.form/request.values from a real browser form or FormData submission, not just JSON — meaning the csrf_token field already present in those forms was silently never validated:

  • /my-med-list/toggle — removed the exempt; the JSON-only call site now sends the token via an X-CSRFToken header (Flask-WTF validates this for non-form requests).
  • /<slug>/review/<id>/helpful — removed the exempt; both FormData call sites now append csrf_token alongside the vote.

Verified live against the running container: toggling a saved drug without a token now returns 400; with the header, 200.

Open redirect in login() (both reviews independently flagged this). request.args.get("next") went straight into redirect() with no validation — POST /login?next=https://evil.com/phish would redirect there after a successful login. Added a same-site-only check (single leading slash, no scheme/netloc) and use it in place of the raw query param.

7 drugs referenced drug-class names with no matching class definition (open-ended review) — memantine/trimethoprim/lecanemab/ezetimibe/ursodiol pointed at class names that didn't exist in the class table at all, so drug_class_id silently ended up NULL for each (no error, just a quietly missing "Drug class" line on those 5 pages). Added the 5 missing classes. umeclidinium and ulipristal referenced near-miss variants of existing classes that didn't match exactly — reclassified both into the correct existing classes (Anticholinergic bronchodilators; Progestogens).

Three smaller bugs (open-ended review):

  • 404 handler's "Popular drugs" section ordered by a nonexistent Drug.rating_count (typo for review_count), caught by a broad except and silently emptying the section.
  • Two templates (drug_side_effects.html, drug_dosage.html) referenced a DrugImage.dosage_form field that was never a real column — cleaned up the dead reference in both (one was already saved by a working fallback; the other always rendered the same static fallback text regardless of drug, now made explicit).
  • /api/interaction-check — a JSON endpoint, confirmed unreferenced by any template and unreachable through the UI, so no task depends on it — silently reported "alcohol" as unrecognized instead of resolving it the way the main interaction-checker page already does correctly. Fixed for consistency; zero regression risk since nothing calls it today.

One finding from the open-ended review I did not act on: it flagged that some browse routes' canonical URL (via url_for()) resolves to the .html variant rather than the "cleaner" extensionless one. This is a style/consistency question, not a functional bug — both URLs work, nothing breaks — so I'm leaving it for a maintainer's judgment call rather than unilaterally re-ordering route decorators across the file.

Consequence: the 7-drug class fix touches seed data, so instance_seed/drugs_com.db was regenerated again and the idempotency invariant reverified. New seed DB md5: 4af8a6688ec3b1d291b493abbfbdd7c8. Re-uploaded to the same HF PR discussion (https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/39).

Full re-verification: fresh Docker build, 17/17 sites → 200, POST /reset/drugs_commd5(instance) == md5(instance_seed) == 4af8a6688ec3b1d291b493abbfbdd7c8, and both CSRF fixes + the open-redirect fix confirmed against the actual running container (not just the Flask test client).

…ntegrity, XSS)

Ran four independent Codex reviews in parallel, each scoped to a distinct angle: security deep-dive, benchmark task-quality audit, performance/code-quality, and data-integrity/cross-field consistency. Verified every finding against the codebase before acting -- most security and performance findings were confirmed real but assessed as hardening-only with no task impact at this data scale, and left alone; the following were confirmed as genuine bugs and fixed.

Three new answer-leaks (task-quality audit)
Beyond the search-results leak fixed in an earlier round, three more
surfaces let a task be answered without following the path its wording
describes:
- Homepage had a dedicated "New Drug Approvals" box listing article
  titles by recency (directly answering task --11, 'find the most recent
  article in that category'), AND a second, display:none-hidden grid
  section repeating the same titles in raw HTML (dead code, removed). The
  visible box now shows only a category link, no titles. Also excluded
  the New-Drug-Approvals category from the homepage's general "Latest
  Medical News" feed, which was independently leaking the same title via
  its category badge.
- /drug-classes index listed each class's top-3 drugs by name (directly
  answering tasks like --16, 'list 3 benzodiazepines', without opening
  the class page). Removed the list; this also drops an N+1 query
  (104 extra per-class lookups) the performance review flagged separately.
- /search's 'Popular for <query>' sidebar showed up to 8 drug names for
  a matched condition/class (leaking tasks --6/--9/--20 the same way).
  Removed the block and its backing query.

OpenFDA content-mismatch root cause (data-integrity review)
fetch_openfda_label() accepted whatever result the FDA label search
returned with no check that it actually described the queried drug.
Confirmed live: querying "polyethylene glycol" returns a label whose own
openfda.generic_name is ["NAPROXEN"] -- an unrelated drug -- because
FDA's search does fuzzy/tokenized matching. This had silently seeded at
least 4 drugs (polyethylene glycol, tobramycin ophthalmic, zoledronic
acid, insulin aspart) with a completely different drug's
uses/warnings/dosage/side-effects text. Added a match check (the
returned label's own generic name must equal, contain, or token-subset-
match the query) before accepting a label; on rejection, seeding falls
back to the existing synthetic-content generator. Verified the 4 known-
bad drugs are clean post-fix, and swept the full 246-drug table for any
remaining cross-drug duplicate uses/warnings/dosage text -- none found.

XSS escaping inconsistency (security review)
compare_drugs.html and interaction_checker.html both built their
autocomplete dropdown via string-concatenated innerHTML without escaping
the API-provided label, unlike base.html's autocomplete which already
does. Current data source is seeded drug/brand names, not user input, so
not exploitable today, but the pattern is inconsistent and a latent risk
if a future contributor feeds less-trusted text through the same
endpoint. Added the same escapeHtml() used elsewhere to both call sites.

Not actioned, with reasoning
- N+1 query patterns elsewhere (search, condition pages, account pages)
  and the /api/interaction-check O(n*m) brand lookup: real, but at the
  current 246-drug seed size the practical latency impact is negligible,
  and this is a benchmark environment (task correctness, not throughput)
  -- fixing all of them would touch a lot of surface area for no benefit
  to what the benchmark actually measures.
- Canonical URL ordering drift (url_for() resolving to the .html alias
  on a few routes), no visible logout link, Advertise/About linking to
  the same page, hardcoded SECRET_KEY: real but either purely cosmetic,
  a repo-wide convention shared by all 17 sites (not a regression here),
  or not reachable by a UI-only browsing agent.

Regenerated instance_seed/drugs_com.db (seed content changed both from
the leak-fix query changes and the openFDA re-fetch), reverified
idempotency, and reran full Docker verification: 17/17 sites 200,
byte-identical reset, both leak fixes and the CSRF/login flow confirmed
against the running container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@boyugou

boyugou commented Jul 9, 2026

Copy link
Copy Markdown
Author

Update — ran 4 parallel Codex reviews from distinct angles, fixed what held up

After the earlier two-review pass (targeted + open-ended), I ran four more Codex reviews in parallel, each scoped to a different concern: security deep-dive, benchmark task-quality/leak audit, performance and code-quality, and data-integrity/cross-field consistency. Every finding below was independently verified against the codebase before I acted on it — most security and performance findings were confirmed real but judged hardening-only with no benchmark impact, and left alone (reasoning included). Two findings were genuine bugs worth fixing immediately.

Three more answer-leaks, beyond the search-results one fixed earlier (task-quality audit):

  • Homepage had a dedicated "New Drug Approvals" box listing article titles by recency — directly answering task --11 ("find the most recent article in that category") without ever visiting the news section. It also had a second, display:none-hidden grid section repeating the same titles in raw HTML (dead code — removed). The visible box now shows only a category link, no titles. Also excluded that category from the homepage's general "Latest Medical News" feed, which was independently leaking the same title via its category badge.
  • /drug-classes index listed each class's top-3 drugs by name — directly answering tasks like --16 ("list 3 benzodiazepines") without opening the class page. Removed the list; this also drops an N+1 query (104 extra per-class lookups) the performance review flagged separately, so it's a two-for-one.
  • /search's "Popular for <query>" sidebar showed up to 8 drug names for a matched condition/class, leaking --6/--9/--20 the same way. Removed the block and its backing query.

(One nuance: the audit also flagged plain search results surfacing statin/diabetes/hypertension drug names when searching those exact terms — I did not touch that. Task --9's own wording says "Search Drugs.com for drugs in the Statins drug class," so search legitimately returning statin-class drugs by name is the intended mechanism, not a leak.)

OpenFDA content-mismatch root cause (data-integrity review) — this was the most serious finding. fetch_openfda_label() accepted whatever the FDA label-search endpoint returned with no check that it actually described the queried drug. Confirmed live: querying polyethylene glycol returns a label whose own openfda.generic_name is ["NAPROXEN"] — a completely unrelated drug — because FDA's search does fuzzy/tokenized matching, not exact matching. This had silently seeded at least 4 drugs (polyethylene glycol, tobramycin ophthalmic, zoledronic acid, insulin aspart) with a different drug's entire uses/warnings/dosage/side-effects text. Added a match check (the returned label's own generic name must equal, contain, or token-subset-match the query) before accepting it; on rejection, seeding falls back to the existing synthetic-content generator. Verified the 4 known-bad drugs are clean post-fix, then swept the full 246-drug table for any other cross-drug duplicate uses/warnings/dosage text — none found.

XSS escaping inconsistency (security review). compare_drugs.html and interaction_checker.html both built their autocomplete dropdown via string-concatenated innerHTML without escaping the API-provided label, unlike base.html's autocomplete, which already does. Current data source is seeded drug/brand names, not user input, so not exploitable today — but the pattern was inconsistent and a latent risk if a future contributor routes less-trusted text through the same endpoint. Added the same escapeHtml() used elsewhere to both call sites.

Confirmed real but not actioned, with reasoning:

  • N+1 query patterns in search/condition/account pages and the (unreferenced, dead-code) /api/interaction-check's O(n·m) brand lookup — real, but at 246 drugs the practical latency is negligible, and this is a benchmark environment where task correctness matters, not throughput. Fixing all of these would touch a lot of surface area for no benefit to what the benchmark measures.
  • Canonical URL drift (url_for() resolving to the .html alias on a few routes), no visible logout link in the header, "Advertise" and "About" resolving to the same page, hardcoded SECRET_KEY — real, but each is either purely cosmetic, a convention shared by all 17 sites in the repo (not a regression here), or not reachable by a UI-only browsing agent (a forged session via the shared secret requires source-code access and out-of-band crypto, not something a browser-driving agent can do).
  • IDOR and SQL injection: reviewed specifically, no findings — every owner-scoped route correctly filters by current_user.id, and no query builds SQL from unparameterized user input.

Consequence: seed content changed again (both from the leak-fix query changes and the openFDA re-fetch), so instance_seed/drugs_com.db was regenerated and idempotency reverified. New seed DB md5: 77e17b36c03fde357c3248895aff65d7. Re-uploaded to the same HF PR discussion.

Full re-verification: fresh Docker build, 17/17 sites → 200, POST /reset/drugs_commd5(instance) == md5(instance_seed) == 77e17b36c03fde357c3248895aff65d7, all three leak fixes confirmed absent from the rendered pages, and the login/CSRF flow reconfirmed against the running container.

boyugou and others added 2 commits July 9, 2026 15:44
…rd state

Adds a 'Contribution status' section at the top (PR links, current seed md5, what's left) so a reader lands on the current state immediately. Documents the OpenFDA content-integrity guard and the answer-leak guardrails as durable 'do not remove/reintroduce' notes rather than one-off fix logs, since both are load-bearing invariants a future change could silently break. Fixes a stale internal inconsistency (task 14 was described as both 'read-only' and 'read and write' in different sections) and updates the HF asset-upload snippet to push onto the existing PR ref instead of --create-pr, which would open a duplicate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@boyugou

boyugou commented Jul 10, 2026

Copy link
Copy Markdown
Author

Update — large data-quality + settings-persistence round, independently re-verified

Commit d1f096f is a substantial change (~1732 lines in app.py, ~20 templates, a reseed) that landed on this branch outside the usual incremental-fix flow this thread has followed. Before accepting it, I ran 6 independent, parallel re-reviews covering every angle that scale of change warrants: scope-compliance (did anything outside sites/drugs_com/ get touched inappropriately), app.py correctness on the full diff, data-integrity on the reseed, all 21 tasks against the new state, template-diff correctness, and an end-to-end re-verification of every previously-established guarantee (auth, CSRF, the answer-leak fixes, the OpenFDA content-integrity guard, byte-identical reset). Summary below.

Scope check: no violation. 6 root-level files were touched outside sites/drugs_com/ (.assets-revision, AGENTS.md, CLAUDE.md, CONTRIBUTING.md, README.md, websyn_start.sh). Every one of them is a stale 15/16-site or 40000-40014/40000-40016 port-range doc reference being corrected to the true 17-site state — the kind of correction that was already overdue on this branch. websyn_start.sh's SITES array, site ordering, and every other site's port assignment are untouched (the only change there is a one-line comment). No sites/<other-site>/ directory appears in the diff. .assets-revision's new pin (a resolved commit SHA rather than the branch ref) was verified to be the actual current head of refs/pr/39 — not a stale/older commit.

Data change: review count 780 → 716, expected and correct. DrugReview gained a (drug_id, user_id) uniqueness constraint, and the seeding logic deduped a popular-drugs list that had accidentally listed 16 drugs twice. Reproduced the old and new algorithms independently and the numbers match exactly: 32 literal duplicate rows removed, 32 more trimming over-represented drugs to a uniform review count. Verified no drug lost all its reviews, alice's 3 benchmark-critical reviews (ibuprofen 9/10, lisinopril 7/10, hydrochlorothiazide 10/10) are untouched, and every drug's cached avg_rating/review_count still matches its actual review rows.

Consequence for task --12: atorvastatin's rating is now 7.0/10 with 4 reviews (this PR's own earlier description had listed a since-superseded 7.1/10, 8 reviews snapshot — now corrected). If a reviewer has already pinned a verifier/rubric to the old numbers, it needs updating to match.

Genuine improvements this round made (not requested, but confirmed as strict improvements after tracing the diff): account_settings/account_subscriptions — previously flash-only no-ops, a gap an earlier review round flagged and deliberately left unfixed since no task exercised it — now actually persist to the database; the homepage's featured-drug cards had a rating/review-count badge removed (an answer-leak for task --12 this round happened to also close); /logout is now POST + CSRF-protected with a visible header link (previously a bare unlinked GET route); a session/DB-ledger-backed dedup was added for the review "helpful" vote buttons, correctly scoped to this app's actual single-process/multi-threaded deployment model (traced the lock ordering across every handler — no deadlock risk, bounded memory via FIFO eviction, no leak).

One accepted, non-blocking gap found in the new vote-dedup logic: logging out and then re-voting "helpful" anonymously in the same browser can double-count a vote by +1 until the next login reconciles it. Self-healing, bounded to +1 per review per browser, and no benchmark task reads the helpful_count field — left as-is rather than adding more complexity for a non-task-affecting counter.

Full re-verification after accepting this round: all 21 tasks re-audited against the current app.py + current seed data (20 PASS, 1 CONCERN — task --12's updated answer, noted above, not a bug); every previously-established guarantee re-confirmed by actually running the app and driving requests through it (not just reading code): real auth (wrong password rejected, correct password + CSRF token succeeds, unauthenticated access to gated routes redirects to /login), CSRF on every checked route (/login, /my-med-list/toggle, the review-helpful endpoint, /account/settings/save, /logout — all reject a missing token with 400 and accept a valid one), the OpenFDA content-integrity guard (still wired in, and a full-table sweep of the new seed data found zero cross-drug duplicate uses/warnings/dosage text), the three answer-leak guardrails (homepage, /drug-classes index, /search sidebar — all still absent), and the byte-identical reset invariant against the new seed md5.

New seed DB md5: d3d228f3fc0b3b880e149ac35550e3c5. Uploaded to the same HF PR discussion (already reflected in .assets-revision's current pin). PR description and this comment reflect the corrected review/condition counts and md5.

…unding gotcha

An independent fresh-eyes review round (5 parallel angles: app.py logic,
data-integrity, concurrency, security, templates) found the codebase clean
overall. Two minor items came out of it:

- drug_detail.html had a dead JS click handler for a `#share-btn` element
  that no longer exists on the page (a Share button was apparently removed
  at some point, the handler wasn't). Harmless (guarded by `if (shareBtn)`,
  no console error) but pure dead code — removed.
- avg_rating is a cached column computed with Python's round() (banker's
  rounding), which can differ by 0.1 from SQLite's ROUND(AVG(...)) for
  drugs whose true mean ends in exactly .x5. The site is internally
  consistent (every route reads the same cached column), but a future
  reviewer writing a deterministic verifier by recomputing the average via
  raw SQL could pin a value 0.1 off from what the site actually shows.
  Documented in CLAUDE.md so that doesn't happen.

No task-affecting bugs, no data changes, no reseed needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@boyugou

boyugou commented Jul 10, 2026

Copy link
Copy Markdown
Author

Update — independent fresh-eyes review round (not diff-scoped)

Rather than only re-checking the previous large round's diff, this pass ran 5 independent reviews from angles chosen to not assume anything already fixed is still correct, plus a live re-verification of every benchmark task against a freshly built image:

  1. Live task re-verification — built the image fresh, ran a new container, and drove all 21 tasks with real HTTP requests (not just reading code): every task resolves to a stable, unambiguous answer, POST /reset/drugs_com stays byte-identical, and real login/CSRF flows behave correctly (wrong password rejected, missing CSRF token → 400, correct login succeeds).
  2. Full-table data-integrity sweep — referential integrity, cached-aggregate correctness, uniqueness, cross-drug content duplication, and value-domain checks run across all 246 drugs (not sampled). Clean.
  3. Security-focused fresh audit — SQL injection, SSRF, path traversal, XSS, auth/session, mass-assignment, rate-limiting, secret handling, each verified by tracing the actual code path rather than trusting prior claims. Clean for this offline single-tenant benchmark's threat model.
  4. Concurrency/thread-safety audit — traced every module-level mutable state and lock acquisition site against the confirmed single-process/multi-threaded deployment model. No race, deadlock, or memory leak; found that a coarse _sqlite_write_lock already serializes every writer, making the finer-grained locks belt-and-suspenders (a design note, not a bug).
  5. Template/frontend auditurl_for references, XSS escaping consistency, CSRF token presence on all 22 POST forms, accessibility, orphaned templates, and JS DOM references, checked across all 49 templates.
  6. Fresh full-file app.py logic audit — read all 8446 lines end-to-end for business-logic bugs, error-handling gaps, and edge cases, independent of the prior round's diff.

Two minor items came out of this, both addressed in 588cbab:

  • drug_detail.html had an orphaned JS click handler for a #share-btn that no longer exists on the page (harmless — guarded by if (shareBtn), no console error — but dead code). Removed.
  • avg_rating is a cached column computed with Python's round() (banker's rounding). For a drug whose true mean ends in exactly .x5, this can differ by 0.1 from SQLite's ROUND(AVG(rating), 1) (which rounds half-away-from-zero) — the site itself is internally consistent (every page reads the same cached column), but a reviewer writing a deterministic verifier by recomputing the average via raw SQL could pin a value 0.1 off from what the site actually displays. Documented in sites/drugs_com/CLAUDE.md so this doesn't bite a future verifier.

No task-affecting bugs, no data-quality problems, and no reseed/repackage was needed this round — everything else came back clean, including re-confirming that the prior large round (d1f096f) introduced no scope violations and no regressions.

@boyugou

boyugou commented Jul 10, 2026

Copy link
Copy Markdown
Author

@MufanQiu @YuanDaoze Finished a major round of revision. Please feel free to take a look when you have a chance. Thank you!

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.

3 participants