Add phet_simulations mirror site (port 40015) - #29
ZhongyangLi0124 wants to merge 16 commits into
Conversation
Adds Flask app, templates, and seed DB for PhET Interactive Simulations (https://phet.colorado.edu/), claiming port slot 40015. Catalog: 98 simulations across 5 subjects (physics, chemistry, math, biology, earth-science), 4 grade levels (elementary, middle, high, university), and 28 languages (incl. 3 RTL scripts). Every primary filter bucket clears the >=20-record threshold. Models: User, Subject, GradeLevel, Language, Simulation, Activity, SavedSimulation. Routes: 17 public + 2 JSON APIs + /_health, all reachable from /. Auth via Flask-Login + bcrypt; saves via CSRF-protected JSON endpoints. Idempotency: every seed_* helper early-returns when its table is populated; verified byte-identical (md5 e094a2ee...) across the control_server reset cycle (rm -rf instance; cp -a instance_seed instance; re-import app). Tested under the exact Dockerfile pin set (Flask 3.1.0, SQLAlchemy 2.0.36, Werkzeug 3.1.3). Per the port-slot convention, also: - websyn_start.sh: append to SITES, bump 15 -> 16 in startup messages - control_server.py: append 'phet_simulations' to SITES list - Dockerfile: EXPOSE 40000-40014 -> 40000-40015 Seed DB (instance_seed/phet_simulations.db, 143KB) packs into a 17KB phet_simulations.tar.gz via scripts/extract_assets.sh and ships separately via the Hugging Face dataset. .assets-revision will need a bump after the HF PR merges. tasks.jsonl: 43 benchmark prompts covering catalog browse, subject filters, simulation detail extraction, search, translations, teacher activities, and the account save flow.
Replace placeholder UI with a high-fidelity mirror of the real
PhET Interactive Simulations site.
Visual:
- Real PhET yellow trademark logo + CU Boulder logo in white header bar
- Right-aligned nav (Simulations / Studio / Teaching / Research / Initiatives)
with hover dropdowns; collapsing search icon + profile icon
- Dismissible pink educator banner
- Photo-backed top hero ("Interactive Simulations for Science and Math")
- 5 pastel subject squares in PhET's canonical order (Physics, Math &
Statistics, Chemistry, Earth & Space, Biology) with their SVG icons
- Photo-backed Teaching Resources callout
- "Interact. Discover. Learn." stats section with real iconography
- Secondary STEM hero photo + centered "Supported in part by" + Donate CTA
- Real footer: social row, 4-column links, language selector, app-store
badges, sponsor logos strip (Moore, Hewlett, NSF, Mastercard, Yidan)
Simulations browse page:
- Underwater illustration banner + Browse / Filter / Customize sub-tabs
- Filter view is the default; left sidebar with collapsible subject tree,
grade level, compatibility, release type, inclusive features, locale,
apply / clear, active-filter chips, sort dropdown, results count
- Browse view groups sims by subject with "View all »" links
Simulation detail page:
- Large screenshot with hover "Play" overlay
- Tabbed sections (About / Teaching Resources / Activities /
Translations / Credits) plus topics, learning goals, related sims
- "Supported by" sidebar, share row, pink Explore More + Donate CTA
Backend wiring:
- Index route adds total_activities for the stats section
- Simulations route exposes view tab and per-subject buckets
- App.py exposes available_thumbnails so cards fall back gracefully
when a slug has no screenshot
Assets ship via the paired HF dataset tarball (not committed):
- 98 sim screenshots (49 from PhET CDN, 49 generated placeholders)
- PhET + CU Boulder logos, subject icons, sponsor logos, hero photos,
app-store badges, underwater simulations banner
Seed DB unchanged, /reset/phet_simulations remains byte-identical
(md5 e094a2ee23369d3b60232f49f4ac691c).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Conflicts resolved: - websyn_start.sh / control_server.py: append berkeley after phet_simulations (PR base predated aiming-lab#29). - Dockerfile EXPOSE 40000-40015 → 40000-40016. Fixes on top of PR: - sites/berkeley/seed_data.py: pin bcrypt hash for benchmark users. set_password() uses bcrypt.generate_password_hash which mixes a random salt on every call, breaking the byte-identical reset invariant. We store a pinned $2b$12$ hash for 'test1234' directly; check_password_hash still accepts it so login works unchanged. - sites/berkeley/app.py: __main__ port 40015 → 40016 (cosmetic — site_runner passes port via -c string, not via __main__).
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.
Review —
|
Addresses all points from MufanQiu's review:
1. Homepage now renders simulation grids (BLOCKER). index.html displays
the route's featured / new_sims / most_played context in three
subject-section rows (20 sim cards), so task --41 is solvable from /.
2. 'New' release filter is functional (MAJOR). simulations() now reads
release=new (is_new) and release=updated (released >= 2024-01-01);
the sidebar checkboxes persist state and the active-filter chip,
sort, and pagination links carry the param. Task --21 is solvable
via UI (answer: 7 New sims, all released 2025).
3. No DB mutation on GET (MAJOR). Removed play_count increment in
simulation_detail and download_count increment in activity_detail;
counts are now fixed seed data, so tasks --6/--31/--41 have
deterministic answers.
4. Seed/task disambiguation (MINOR):
- Activities carry explicit pairwise-distinct download counts;
unique most-downloaded = Net Force Investigation (8742), paired
with Forces and Motion: Basics (task --12).
- Sim versions derived deterministically from seed constants
(47 distinct versions; Wave Interference = 1.5.2, task --28).
- Tasks --6, --24, --28, --31 reworded with tighter constraints so
each has exactly one valid answer (verified programmatically).
Seed DB rebuilt; reset cycle remains byte-idempotent
(md5 48ca438b8ac6dab37a6503a4e5574503). 66/66 routes return 200.
New phet_simulations.tar.gz must be re-uploaded to the HF dataset and
.assets-revision repinned to the HF merge SHA (separate commit).
|
Thanks for the thorough review — all five points addressed in b15feb3:
Re-verified locally: 66/66 routes 200, reset cycle byte-idempotent (seed md5 |
|
I'm taking over the review and remediation of this PhET Interactive Simulations contribution. I'll build a separate The review will cover current-main integration (site registry/port slot and the |
|
Review PR is up as a Draft: #114 (branch Two findings drove most of the work, and I want to be direct about the larger one. 43 of the 98 seeded simulations do not exist on phet.colorado.edu. I checked every one of The catalogue is now the real HTML5 library from PhET's official metadata service: 120 Every page overflowed horizontally below about 840px. The desktop nav, search form and user Also fixed from @MufanQiu's earlier list, which I re-verified at The task set is rebuilt from 43 to 18. Nine targeted fabricated simulations, four read the Assets: ChilleD/WebHarbor discussions/79 supersedes #19, since #19's seed is the fabricated Still outstanding on the review PR: the independent review of the frozen runs, and a full |
Addresses all points from MufanQiu's review:
1. Homepage now renders simulation grids (BLOCKER). index.html displays
the route's featured / new_sims / most_played context in three
subject-section rows (20 sim cards), so task --41 is solvable from /.
2. 'New' release filter is functional (MAJOR). simulations() now reads
release=new (is_new) and release=updated (released >= 2024-01-01);
the sidebar checkboxes persist state and the active-filter chip,
sort, and pagination links carry the param. Task --21 is solvable
via UI (answer: 7 New sims, all released 2025).
3. No DB mutation on GET (MAJOR). Removed play_count increment in
simulation_detail and download_count increment in activity_detail;
counts are now fixed seed data, so tasks --6/--31/--41 have
deterministic answers.
4. Seed/task disambiguation (MINOR):
- Activities carry explicit pairwise-distinct download counts;
unique most-downloaded = Net Force Investigation (8742), paired
with Forces and Motion: Basics (task --12).
- Sim versions derived deterministically from seed constants
(47 distinct versions; Wave Interference = 1.5.2, task --28).
- Tasks --6, --24, --28, --31 reworded with tighter constraints so
each has exactly one valid answer (verified programmatically).
Seed DB rebuilt; reset cycle remains byte-idempotent
(md5 48ca438b8ac6dab37a6503a4e5574503). 66/66 routes return 200.
New phet_simulations.tar.gz must be re-uploaded to the HF dataset and
.assets-revision repinned to the HF merge SHA (separate commit).
|
Review complete. #114 is out of Draft and ready for maintainer review. Since my last comment the branch was rebased again: upstream merged fedex, webmd_doctor, Two independent review rounds were run on the frozen executions in sessions with no access to the The first round flagged evidence-quality gaps rather than wrong verdicts, and chasing them turned
A 90-cell adversarial matrix then found three verifiers a wrong answer could satisfy: the two One thing for the maintainers rather than for you: Merge order: HF discussion #79 first, then Thanks for the mirror — the Flask app, auth, CSRF and reset behaviour were solid throughout, and |
Adds Flask app, templates, and seed DB for PhET Interactive Simulations (https://phet.colorado.edu/), claiming port slot 40015. Catalog: 98 simulations across 5 subjects (physics, chemistry, math, biology, earth-science), 4 grade levels (elementary, middle, high, university), and 28 languages (incl. 3 RTL scripts). Every primary filter bucket clears the >=20-record threshold. Models: User, Subject, GradeLevel, Language, Simulation, Activity, SavedSimulation. Routes: 17 public + 2 JSON APIs + /_health, all reachable from /. Auth via Flask-Login + bcrypt; saves via CSRF-protected JSON endpoints. Idempotency: every seed_* helper early-returns when its table is populated; verified byte-identical (md5 e094a2ee...) across the control_server reset cycle (rm -rf instance; cp -a instance_seed instance; re-import app). Tested under the exact Dockerfile pin set (Flask 3.1.0, SQLAlchemy 2.0.36, Werkzeug 3.1.3). Per the port-slot convention, also: - websyn_start.sh: append to SITES, bump 15 -> 16 in startup messages - control_server.py: append 'phet_simulations' to SITES list - Dockerfile: EXPOSE 40000-40014 -> 40000-40015 Seed DB (instance_seed/phet_simulations.db, 143KB) packs into a 17KB phet_simulations.tar.gz via scripts/extract_assets.sh and ships separately via the Hugging Face dataset. .assets-revision will need a bump after the HF PR merges. tasks.jsonl: 43 benchmark prompts covering catalog browse, subject filters, simulation detail extraction, search, translations, teacher activities, and the account save flow.
Replace placeholder UI with a high-fidelity mirror of the real
PhET Interactive Simulations site.
Visual:
- Real PhET yellow trademark logo + CU Boulder logo in white header bar
- Right-aligned nav (Simulations / Studio / Teaching / Research / Initiatives)
with hover dropdowns; collapsing search icon + profile icon
- Dismissible pink educator banner
- Photo-backed top hero ("Interactive Simulations for Science and Math")
- 5 pastel subject squares in PhET's canonical order (Physics, Math &
Statistics, Chemistry, Earth & Space, Biology) with their SVG icons
- Photo-backed Teaching Resources callout
- "Interact. Discover. Learn." stats section with real iconography
- Secondary STEM hero photo + centered "Supported in part by" + Donate CTA
- Real footer: social row, 4-column links, language selector, app-store
badges, sponsor logos strip (Moore, Hewlett, NSF, Mastercard, Yidan)
Simulations browse page:
- Underwater illustration banner + Browse / Filter / Customize sub-tabs
- Filter view is the default; left sidebar with collapsible subject tree,
grade level, compatibility, release type, inclusive features, locale,
apply / clear, active-filter chips, sort dropdown, results count
- Browse view groups sims by subject with "View all »" links
Simulation detail page:
- Large screenshot with hover "Play" overlay
- Tabbed sections (About / Teaching Resources / Activities /
Translations / Credits) plus topics, learning goals, related sims
- "Supported by" sidebar, share row, pink Explore More + Donate CTA
Backend wiring:
- Index route adds total_activities for the stats section
- Simulations route exposes view tab and per-subject buckets
- App.py exposes available_thumbnails so cards fall back gracefully
when a slug has no screenshot
Assets ship via the paired HF dataset tarball (not committed):
- 98 sim screenshots (49 from PhET CDN, 49 generated placeholders)
- PhET + CU Boulder logos, subject icons, sponsor logos, hero photos,
app-store badges, underwater simulations banner
Seed DB unchanged, /reset/phet_simulations remains byte-identical
(md5 e094a2ee23369d3b60232f49f4ac691c).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Addresses all points from MufanQiu's review:
1. Homepage now renders simulation grids (BLOCKER). index.html displays
the route's featured / new_sims / most_played context in three
subject-section rows (20 sim cards), so task --41 is solvable from /.
2. 'New' release filter is functional (MAJOR). simulations() now reads
release=new (is_new) and release=updated (released >= 2024-01-01);
the sidebar checkboxes persist state and the active-filter chip,
sort, and pagination links carry the param. Task --21 is solvable
via UI (answer: 7 New sims, all released 2025).
3. No DB mutation on GET (MAJOR). Removed play_count increment in
simulation_detail and download_count increment in activity_detail;
counts are now fixed seed data, so tasks --6/--31/--41 have
deterministic answers.
4. Seed/task disambiguation (MINOR):
- Activities carry explicit pairwise-distinct download counts;
unique most-downloaded = Net Force Investigation (8742), paired
with Forces and Motion: Basics (task --12).
- Sim versions derived deterministically from seed constants
(47 distinct versions; Wave Interference = 1.5.2, task --28).
- Tasks --6, --24, --28, --31 reworded with tighter constraints so
each has exactly one valid answer (verified programmatically).
Seed DB rebuilt; reset cycle remains byte-idempotent
(md5 48ca438b8ac6dab37a6503a4e5574503). 66/66 routes return 200.
New phet_simulations.tar.gz must be re-uploaded to the HF dataset and
.assets-revision repinned to the HF merge SHA (separate commit).
…40024 Rebased @ZhongyangLi0124's contribution onto current main. The PR's original 15/16-site registry edits were superseded, so phet_simulations is appended to websyn_start.sh and control_server.py at index 24 and Dockerfile exposes 40000-40024. Also sweeps the repo docs (README, AGENTS, CONTRIBUTING, CLAUDE, agent_demo) from 24 to 25 sites, points tasks.jsonl at port 40024, and updates the rotten_tomatoes registry assertions that pin the SITES tail and EXPOSE range. The port slot stays provisional until merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every page rendered an 837px-wide document at both 768px and 390px viewports because the desktop nav, search form and user menu never collapsed. Body content stayed in the left 390px and the rest of each page was blank gutter. - collapse the primary nav behind a toggle below 900px, with sub-links shown inline inside the open panel so they stay reachable without hover; - inline the search field, which was absolutely positioned off-screen in a narrow bar, and drop the CU mark below 520px; - reflow the pastel subject grid at <=1000px, which previously kept five columns until 760px and overhung a 768px viewport; - let grid children shrink (min-width:0) and cap image width; - contain the simulation detail tab strip's overflow inside itself. Verified across 20 pages x 1440/768/390: 60 of 60 captures now have scrollWidth equal to the viewport, down from 40 overflowing. All 20 desktop pages keep byte-identical layout heights, so the change is additive below 900px only. Reset still restores the seed byte-identically. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43 of the 98 seeded simulations did not exist on phet.colorado.edu. They were invented, with generated titles, descriptions, subjects, grade bands, versions, release dates, play counts and language lists, and each was illustrated by a purple gradient placeholder card rather than a screenshot. Six more existed upstream but under a mangled slug. The catalogue is now the real HTML5 library, harvested 2026-09-13: - 120 simulations from the official metadata service, with upstream titles, descriptions and sample learning goals; - subject and topic membership from the numeric facet ids, whose meaning was confirmed by intersecting each id against the live filter (Physics 65, Math & Statistics 51, Chemistry 35, Earth & Space 19, Biology 8 -- exact matches on all four); - grade bands, version strings, release and last-updated dates, the per-sim locale list and relatedSimulations, all from the same feed; - the topic strip shown on each upstream simulation page; - the 131-language translation table from the upstream translated-sims page, whose HTML5 counts agree with the seeded per-locale counts; - official 600px screenshots for all 120 simulations, replacing every placeholder. Facts PhET does not publish are removed rather than invented: play counts, download counts and per-simulation runtime are gone from the model, the homepage's third rail is now Recently Updated, and catalogue sort offers Recently updated and Most translated instead of Most played. Also fixed in the same pass: - the topic facet now filters (it read no parameter before, leaving 11 topic, 3 compatibility and 3 inclusive-feature checkboxes inert); the compatibility and inclusive groups, which this HTML5-only snapshot cannot back with data, are replaced by a statement of that fact; - the Customize tab rendered an empty page because it fell through to the browse branch with no data, and now lists the 49 simulations upstream marks as available in PhET Studio; - search tokenises, so "build atom" reaches Build an Atom instead of returning nothing; - the filter sidebar gains Heat & Thermo and renames Numbers and Quantum Mathematics to the upstream Math Concepts and Math Applications; - teacher activities are relabelled as benchmark fixtures with synthetic authors and now point at simulations that exist, instead of attributing invented lesson plans to real, named PhET contributors. Reset stays byte-identical and re-seeding on restart is a no-op. Tasks that were anchored on fabricated simulations still need re-anchoring; that is the next commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ract The 43 contributor tasks could not survive the catalogue rebuild: nine of them targeted simulations that do not exist upstream, four more read a play counter that PhET does not publish and that is now gone, one asked which scripts are right-to-left (answerable without opening the site) and one only asked the agent to click through to a language page, leaving nothing to grade. This replaces them with 18 tasks anchored on facts that live on this site and that a model cannot recall: exact version strings, exact release dates, exact per-language and per-facet counts, the related-simulations list, account state. None of those appear on a listing card, so each one requires opening the page that carries it. Adds the reviewer grading contract: verify_lib.py plus verify_0..verify_17, recorded as verifier_path and a rules-only judge_rubric on every row. Ground truth is hardcoded in the verifiers; tasks.jsonl has no answer key. Validation, all deterministic (--no_llm True): - 18 of 18 scripted UI walks pass their verifier; - an 88-cell adversarial matrix matches every expectation - no-op, wrong answer, shortcut without navigation, state mismatch on the two stateful tasks, and an unexpected database write on each read-only task all fail on the intended check; - 16 legitimate rephrasings and alternate routes all still pass. Two verifier defects surfaced during that validation and are fixed here: task 2 rejected a correct answer that echoed the question's own phrase "not offered at university level", and the shared number matcher accepted only digits, so an answer of "Five" was wrongly failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two defects surfaced while reconciling the independent review. The simulation detail page's save form had no note field, yet the API stores a note and a task asks for one. The task was therefore not completable through the UI at all; only a direct API call could satisfy it. Add the field, send it from main.js, and render any existing note back into it. The translations grid applied direction:rtl to the whole card for right-to-left languages, which reversed the English count line as well: Arabic rendered "simulations 119" instead of "119 simulations". Scope the direction to the native-name element and isolate the English name and count. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The adversarial matrix found three verifiers that a wrong answer could satisfy. verify_13 and verify_14 graded the saved-simulation tasks purely on the database delta, so an answer describing an unrelated simulation still passed once the save itself had happened. Both now require the answer to name the simulation it saved. has_number accepted a digit appearing anywhere in the answer, so "version 9.9.9" satisfied a check for the count 9. Add verify_lib.counts(), which requires the number to be reported as a count of the thing being counted, and use it for the four small-count tasks. It still accepts the natural phrasings: "9 simulations", "nine simulations", "Simulations: 9", "there are 9". Ship the matrix itself under verify/tests/ so the result is reproducible. It is excluded from the image by .dockerignore. 18/18 canonical runs pass, the 90-cell matrix matches every expectation, and six legitimate rephrasings still pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sets Upstream merged fedex, webmd_doctor, healthline, kaggle and nvidia while this branch was in review, so take the next free slot. .assets-revision points at ChilleD/WebHarbor discussions/86 so this branch fetches and builds without waiting for that PR to merge. That commit is upstream's current pin b7e605c plus phet_simulations.tar.gz, with every other archive byte-identical - checked by comparing the file OIDs of both trees, which matters because the earlier asset PR aiming-lab#79 predated the NVIDIA repin and would have regressed those images. Temporary; repin to the merge commit once aiming-lab#86 lands. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Preserve the original contribution and review branch history. Use the exact file tree validated by the complete 36-site build, HTTP and reset checks.
Summary
Adds a 16th mirror site to WebHarbor: PhET Interactive Simulations
(https://phet.colorado.edu/). Bound to port 40015.
Real site: University of Colorado Boulder's CC-BY-licensed catalog of
free interactive math and science simulations. Selected for its clean
taxonomy (subjects × grade bands × languages), stable academic content,
and no commercial anti-bot defenses.
Seeded catalog
Visual fidelity
Mirror is reskinned to closely match the real PhET site:
(Simulations / Studio / Teaching / Research / Initiatives)
photo-backed Teaching Resources callout, Interact/Discover/Learn stats,
second STEM hero, sponsor footer (Moore / NSF / Hewlett / Mastercard / Yidan)
/simulationsBrowse / Filter / Customize tabs with underwater banner;Filter view has left-sidebar with collapsible subject tree, grade level,
compatibility, locale, active-filter chips, sort
Credits), large screenshot, supported-by sidebar, Donate CTA
Assets ship via the paired HF dataset PR (see below). 98 sim screenshots
(49 from PhET CDN, 49 styled placeholders for slugs not in HTML5 lib),
plus logos, sponsor logos, hero photos, subject icons, app-store badges,
underwater banner. ~5 MB tarball total.
Paired HF dataset PR
https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/19
This PR is in Draft status until the HF PR merges. Once merged,
.assets-revisionwill be bumped to the merge commit SHA and thedraft will be marked ready for review.
Test plan
python3 -m py_compile sites/phet_simulations/app.py./scripts/build.shsucceeds (3.07 GB image)docker run -d --rm -p 8101:8101 -p 40000-40015:40000-40015 webharbor:devphet_simulationsalive on port 40015/,/simulations,/simulations?view=browse,/simulations?view=filter&subject=physics,/simulation/build-an-atom,/simulation/algebra-tiles,/teachers,/translations,/about,/accessibility)POST /reset/phet_simulationsreturns"ready": trueinstance/phet_simulations.dband
instance_seed/phet_simulations.dbboth equale094a2ee23369d3b60232f49f4ac691cpost-reset and afterdocker restartReset evidence