Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8e11e7d
feat(adopt-a-pet): add high-fidelity mirror
sarendis56 Sep 10, 2026
57df594
fix(adopt_a_pet): pin runtime requirements so app.py imports standalone
JeremyJC67 Sep 11, 2026
1871a05
feat(adopt_a_pet): add deterministic verifiers and judge rubrics for …
JeremyJC67 Sep 11, 2026
5279cb3
test(adopt_a_pet): add verifier validation harness
JeremyJC67 Sep 11, 2026
ed865a4
docs: bump site count to 25 (ports 40000-40024)
JeremyJC67 Sep 11, 2026
d6b4080
fix(adopt_a_pet): harden sessions, CSRF, redirects and form validation
JeremyJC67 Sep 12, 2026
1a9a6e5
fix(adopt_a_pet): repair pagination links, result range and dead navi…
JeremyJC67 Sep 12, 2026
a84eacd
fix(adopt_a_pet): meet WCAG AA on labels and remove horizontal overflow
JeremyJC67 Sep 12, 2026
faa6dcb
fix(adopt_a_pet): reword task 4 so its search path exists
JeremyJC67 Sep 12, 2026
1166ad6
chore(adopt_a_pet): merge the 26-site main and re-slot to site 27 (po…
JeremyJC67 Sep 13, 2026
ac907f9
fix(adopt_a_pet): pair each listing with its own matching photograph
sarendis56 Sep 13, 2026
5acfa5a
docs(adopt_a_pet): show corrected desktop and mobile pet photographs
sarendis56 Sep 13, 2026
89a63fa
fix(adopt_a_pet): restore the build-time seed step lost in the main m…
JeremyJC67 Sep 13, 2026
decb0d6
Merge contributor photo remediation (JeremyJC67/WebHarbor#1 by @saren…
JeremyJC67 Sep 13, 2026
6c56371
chore(adopt_a_pet): keep review-reports out of the Docker build context
JeremyJC67 Sep 13, 2026
54c469f
chore(adopt_a_pet): merge the 26-site main and re-slot to site 27 (po…
JeremyJC67 Sep 13, 2026
f697043
fix(adopt_a_pet): restore the build-time seed step dropped by the mai…
JeremyJC67 Sep 13, 2026
0b07a78
Merge current main into original Adopt-a-Pet contribution; preserve s…
QianhuiWu Sep 20, 2026
971c568
Merge original Adopt-a-Pet contribution and current registry into review
QianhuiWu Sep 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .assets-revision
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# All 49 registered sites use this immutable merged HF main revision.
# Bandcamp HF #94 is merged; all 51 unrelated dataset files are unchanged.
# assets-manifest.json binds archives and the extracted managed tree.
# All 50 sites pinned to merged HF main, including Adopt-a-Pet HF #67.
repo: ChilleD/WebHarbor
revision: e82d584da9eb2b138f8db71fb28f50438860b17d
revision: 2e9c786038d560b363ad9c046087bf114af7c6bf
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ build/
# Note: sites/*/instance_seed/, static/images/, static/external_cache/ ARE
# shipped — those are the runtime assets. They live in .gitignore (managed
# via HF), not here.

# Review evidence is not part of the runtime image.
review-reports/
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ A coding agent (Claude Code, Cursor, Aider, Codex, ...) is reading this. Read on

## What it is

49 Flask mirror websites (Amazon, GitHub, BBC News, ...) packaged into one Docker image, plus a control plane on `:8101` for resetting per-site state. Used as a deterministic offline environment for web-agent benchmarks. ~3 GB image.
50 Flask mirror websites (Amazon, GitHub, BBC News, ...) packaged into one Docker image, plus a control plane on `:8101` for resetting per-site state. Used as a deterministic offline environment for web-agent benchmarks. ~3 GB image.

Two repos:
- **code** (this one) — Flask apps, control plane, scripts.
Expand Down Expand Up @@ -59,17 +59,17 @@ Inside the image, sites live at `/opt/WebSyn/<site>/`. The path predates the ren
# fresh clone
./scripts/fetch_assets.sh # pulls assets from HF
./scripts/build.sh # docker build -t webharbor:dev .
docker run -e WEBSYN_CONTROL_TOKEN -d -p 8101:8101 -p 40000-40048:40000-40048 webharbor:dev
docker run -e WEBSYN_CONTROL_TOKEN -d -p 8101:8101 -p 40000-40049:40000-40049 webharbor:dev
```

Or use the published image directly:

```bash
docker run -e WEBSYN_CONTROL_TOKEN -d -p 8101:8101 -p 40000-40048:40000-40048 \
docker run -e WEBSYN_CONTROL_TOKEN -d -p 8101:8101 -p 40000-40049:40000-40049 \
battalion7244/webharbor:latest
```

Sites are on `40000`-`40048` in the order declared by `SITES=( ... )` in `websyn_start.sh`. Control plane:
Sites are on `40000`-`40049` in the order declared by `SITES=( ... )` in `websyn_start.sh`. Control plane:

| Method | Path | Purpose |
|--------|---------------------|-------------------------------------------|
Expand Down Expand Up @@ -147,7 +147,7 @@ python3 -m py_compile sites/<site>/app.py

# 3. run on alt ports (don't collide with anything you already have running)
docker run -e WEBSYN_CONTROL_TOKEN -d --rm --name wh-test \
-p 8201:8101 -p 41000-41048:40000-40048 webharbor:dev
-p 8201:8101 -p 41000-41049:40000-40049 webharbor:dev

# 4. control plane healthy, all sites alive
curl -s -H "Authorization: Bearer $WEBSYN_CONTROL_TOKEN" http://localhost:8201/health | python3 -m json.tool | head
Expand Down
13 changes: 11 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# WebHarbor — slim, self-contained image.
# 49 Flask mirror sites + control plane on :8101.
# 50 Flask mirror sites + control plane on :8101.

FROM python:3.12-slim-bookworm@sha256:782412e85d0f0984994c290652577d4018aff08145c85b262bb63dc0c7522254

Expand Down Expand Up @@ -153,9 +153,18 @@ RUN python3 /opt/check_asset_inventory.py /opt/WebSyn/y_combinator
RUN cd /opt/WebSyn/y_combinator && rm -rf instance instance_seed && \
PYTHONHASHSEED=0 python seed_data.py && rm -rf instance

# Adopt-a-Pet builds its synthetic catalog; representative photos come from HF.
RUN test -n "$(ls -A /opt/WebSyn/adopt_a_pet/static/images)" && \
cd /opt/WebSyn/adopt_a_pet && rm -rf instance instance_seed && python3 -c "\
import app; \
import os, shutil; \
os.makedirs('instance_seed', exist_ok=True); \
shutil.copy2('instance/adopt_a_pet.db', 'instance_seed/adopt_a_pet.db'); \
print('Adopt-a-Pet seed DB generated at build time.')" && rm -rf /opt/WebSyn/adopt_a_pet/instance

# Fail closed after all registered-site seed migrations/generators.
RUN python3 /opt/check_seed_databases.py /opt/WebSyn

EXPOSE 8101 40000-40048
EXPOSE 8101 40000-40049

CMD ["/opt/websyn_start.sh"]
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ WebHarbor takes a different approach. We leverage coding agent (e.g., Claude Cod
- **Deep features unlocked** — carts, checkouts, accounts, all fully testable
- **Evolving** — harder tasks drive richer mirrors; the environment grows with agents
- **RL-ready** — sub-second database resets between rollouts
- **Community-driven** — 49 sites today, scaling to 100+ together
- **Community-driven** — 50 sites today, scaling to 100+ together

## 🚀 Quickstart

Build this checkout to run its registered web environments (published image tags may have an older registry):

```bash
./scripts/build.sh webharbor:dev
docker run -e WEBSYN_CONTROL_TOKEN -p 8101:8101 -p 40000-40048:40000-40048 webharbor:dev
docker run -e WEBSYN_CONTROL_TOKEN -p 8101:8101 -p 40000-40049:40000-40049 webharbor:dev
```

Then point your agent at `http://localhost:40000` through `http://localhost:40048` to explore 49 local mirrors of WebVoyager sites: `Allrecipes, Amazon, Apple, ArXiv, BBC News, Booking, GitHub, Google Flights, Google Maps, Google Search, Hugging Face, Wolfram Alpha, Cambridge Dictionary, Coursera, ESPN, Merriam-Webster, IKEA, Phys.org, Target, TED, Ohio State University, Rotten Tomatoes, Compass, Walmart Careers, FedEx, WebMD Doctor, Healthline, Kaggle, NVIDIA, UC Berkeley, B&H Photo, AccuWeather, GOV.UK, IMDb, NBA, Recreation.gov, BoardGameGeek, CarMax, BabyCenter, Amtrak, Cookpad, Craigslist, Drugs.com, Versus, Y Combinator, PhET Interactive Simulations, Discogs, Google Finance, and Bandcamp`.
Then point your agent at `http://localhost:40000` through `http://localhost:40049` to explore 50 local mirrors of WebVoyager sites: `Allrecipes, Amazon, Apple, ArXiv, BBC News, Booking, GitHub, Google Flights, Google Maps, Google Search, Hugging Face, Wolfram Alpha, Cambridge Dictionary, Coursera, ESPN, Merriam-Webster, IKEA, Phys.org, Target, TED, Ohio State University, Rotten Tomatoes, Compass, Walmart Careers, FedEx, WebMD Doctor, Healthline, Kaggle, NVIDIA, UC Berkeley, B&H Photo, AccuWeather, GOV.UK, IMDb, NBA, Recreation.gov, BoardGameGeek, CarMax, BabyCenter, Amtrak, Cookpad, Craigslist, Drugs.com, Versus, Y Combinator, PhET Interactive Simulations, Discogs, Google Finance, Bandcamp, and Adopt-a-Pet`.

For sub-second reset between rollouts, expose the control plane and call `/reset/<site>`:

Expand All @@ -64,7 +64,7 @@ git clone https://github.com/aiming-lab/WebHarbor && cd WebHarbor

### Site registry

This checkout registers **49 sites**. NVIDIA remains at index 28, UC Berkeley remains at index 29, B&H Photo remains at index 30, AccuWeather remains at index 31, GOV.UK remains at index 32, IMDb remains at index 33 and NBA remains at index 34. Recreation.gov remains at index 35, BoardGameGeek remains at index 36, CarMax remains at index 37, BabyCenter remains at index 38, Amtrak remains at index 39, Cookpad remains at index 40, Craigslist remains at index 41, Drugs.com remains at index 42, Versus remains at index 43, Y Combinator remains at index 44, PhET Interactive Simulations remains at index 45, Discogs remains at index 46, and Google Finance remains at index 47, and Bandcamp is appended at index 48. Build the image from this checkout to use this registry; publishing source does not update the published Docker image automatically.
This checkout registers **50 sites**. NVIDIA remains at index 28, UC Berkeley remains at index 29, B&H Photo remains at index 30, AccuWeather remains at index 31, GOV.UK remains at index 32, IMDb remains at index 33 and NBA remains at index 34. Recreation.gov remains at index 35, BoardGameGeek remains at index 36, CarMax remains at index 37, BabyCenter remains at index 38, Amtrak remains at index 39, Cookpad remains at index 40, Craigslist remains at index 41, Drugs.com remains at index 42, Versus remains at index 43, Y Combinator remains at index 44, PhET Interactive Simulations remains at index 45, Discogs remains at index 46, and Google Finance remains at index 47, Bandcamp remains at index 48, and Adopt-a-Pet is appended at index 49. Build the image from this checkout to use this registry; publishing source does not update the published Docker image automatically.

| Site | Registry position | Container port | Example local review host port |
| --- | --- | --- | --- |
Expand All @@ -89,17 +89,18 @@ This checkout registers **49 sites**. NVIDIA remains at index 28, UC Berkeley re
| Discogs | 46 | 40046 | 48046 |
| Google Finance | 47 | 40047 | 48047 |
| Bandcamp | 48 | 40048 | 48048 |
| Adopt-a-Pet | 49 | 40049 | 48049 |

`websyn_start.sh`, `control_server.py`, the `Dockerfile` `EXPOSE` line and every
site's `tasks.jsonl` `web` URL agree on 49 sites and `40000-40048`;
site's `tasks.jsonl` `web` URL agree on 50 sites and `40000-40049`;
`scripts/check_site_registry.py` (run by `scripts/check_assets.sh`) fails when they
drift.

After preparing the candidate assets and building `webharbor:dev`, the local
review deployment uses:

```bash
docker run -e WEBSYN_CONTROL_TOKEN -p 127.0.0.1:48080:8101 -p 127.0.0.1:48000-48048:40000-40048 webharbor:dev
docker run -e WEBSYN_CONTROL_TOKEN -p 127.0.0.1:48080:8101 -p 127.0.0.1:48000-48049:40000-40049 webharbor:dev
```

NVIDIA inherits the site contribution from @KaKituken
Expand All @@ -120,7 +121,7 @@ The bundle contains 78 articles and 62 structured guidance sections. That archiv
is part of the consolidated pinned dataset revision below.


The current `.assets-revision` pins all **49 registered sites** to merged HF commit `e82d584da9eb2b138f8db71fb28f50438860b17d`. Bandcamp [HF #94](https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/94) is merged; only its archive changed, preserving all 51 unrelated dataset files byte-for-byte. Its reviewed archive has SHA-256 `63b81ffdcafc3738f5a91dbb18680126140e294074cf437c6730ba3acf83b68b` and was not repacked. `assets-manifest.json` binds all selected archives and the extracted managed tree. Unregistered bundles are not fetched; tracked seed migrations and generation remain part of the build contract.
The current `.assets-revision` pins all **50 registered sites** to merged HF commit `2e9c786038d560b363ad9c046087bf114af7c6bf`. Adopt-a-Pet [HF #67](https://huggingface.co/datasets/ChilleD/WebHarbor/discussions/67) is merged; only its archive was added, preserving all 52 existing dataset files. Its reviewed archive has SHA-256 `e337aee58818a0e3128d157afcdf83cfbdf2bca1044ad647ca32ddc85bed4682` and was not repacked. `assets-manifest.json` binds all selected archives and the extracted managed tree. Unregistered bundles are not fetched; tracked seed migrations and generation remain part of the build contract. Adopt-a-Pet's reset seed is generated from tracked code during the Docker build.

Historical asset integration notes below describe superseded pins, not the current pin.

Expand Down
8 changes: 6 additions & 2 deletions assets-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
"bytes": 5524,
"sha256": "5dee4441c964fe9ef4e2467a8c9f2ce77cb840c34b820221261a62045ff27e99"
},
"adopt_a_pet.tar.gz": {
"bytes": 2422612,
"sha256": "e337aee58818a0e3128d157afcdf83cfbdf2bca1044ad647ca32ddc85bed4682"
},
"allrecipes.tar.gz": {
"bytes": 85460995,
"sha256": "0aa156ef92bbae1ae308ddf93e0c7d275f7aec564f292bc26fa256f52af3377e"
Expand Down Expand Up @@ -197,8 +201,8 @@
"sha256": "43c666bda84680f327ce64720b2baa2f9e427acb751fe81900967f267e9176f4"
}
},
"managed_tree_sha256": "01ceff507cd3d0002bcbe43e86b6ff195946618cc5864ad87ff095071362afc8",
"managed_tree_sha256": "5a3876f533a8a94f4f532b84a0fbd1effacf9c18053b231027dcf8aee6ec975e",
"repo": "ChilleD/WebHarbor",
"revision": "e82d584da9eb2b138f8db71fb28f50438860b17d",
"revision": "2e9c786038d560b363ad9c046087bf114af7c6bf",
"version": 1
}
2 changes: 1 addition & 1 deletion control_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
'imdb',
'nba', 'recreation_gov', 'boardgamegeek', 'carmax', 'babycenter', 'amtrak',
'cookpad', 'craigslist', 'drugs_com', 'versus', 'y_combinator',
'phet_simulations', 'discogs', 'google_finance', 'bandcamp',
'phet_simulations', 'discogs', 'google_finance', 'bandcamp', 'adopt_a_pet',
]
BASE_PORT = 40000
WEBSYN_DIR = '/opt/WebSyn'
Expand Down
39 changes: 39 additions & 0 deletions review-reports/ADOPT-A-PET-FINAL-AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Adopt-a-Pet final task and UI audit

Audit date: 2026-09-10. Branch: `add-adopt-a-pet-mirror`.

Each task began with `POST /reset/adopt_a_pet`, cleared browser cookies, and loaded `http://localhost:41024/`. Playwright used visible roles, labels, and link names for all searching, filtering, pagination-dependent selection, login, registration, favorites, alerts, adoption inquiries, shelters, and account confirmation. No destination URL, database record, or source answer replaced a user interaction.

| Tasks | Result | Evidence |
|---|---|---|
| AdoptAPet--0 through AdoptAPet--19 | 20/20 pass | Structured step log and one final screenshot per task in `outputs/adopt-a-pet-review/` |

The paths covered: location and species search; breed, sex, age, and size filters; pet details; multi-profile comparisons; rescue details; Breed 101; favorites add/remove; adoption inquiry submission; New Pet Alert creation; account registration; account persistence; and editorial resources.

## Hardening results

- De-leak: cards show only name, breed, broad age group, sex, and location. Exact age, fee, compatibility, color, rescue contact, and application state require the appropriate detail or account flow.
- Distractors: Arizona has nine pets across multiple cities and breeds; Phoenix, Scottsdale, New York, Seattle, Austin, and Miami each have multiple plausible candidates. Filters narrow genuine sets rather than routing directly to a target.
- Catalog breadth: 20 pets, 6 shelters, 12 primary breeds, two species, four age groups, three sizes, both sexes, six metro areas, and 20 distinct captured images.
- Cross-field consistency: each pet’s city/state agrees with its linked rescue region; shared relational rows drive search, detail, shelter, favorites, alerts, inquiries, and account pages.
- Leak archetypes checked: direct prompt answer; artificial first-result target; pre-sorted winner; result count as answer; detail on card; insufficient distractors; route/slug answer; hidden attribute; accessible-name answer; placeholder answer; mutation-free success; visit-only completion; unrelated state acceptance. None were found.
- Hard reasoning tasks include 2, 3, 5, 12, 14, and 19. Tasks 6–9, 15, and 16 additionally require exact persistent state changes.

## Visual and asset audit

Home, search, pet detail, shelter list, and account were checked at 1440, 390, and 320 CSS pixels. Across all 15 combinations there were zero broken images and zero horizontal-overflow failures. Representative committed screenshots:

- `review-reports/assets/adopt-a-pet-homepage-1440.png`
- `review-reports/assets/adopt-a-pet-homepage-390.png`
- `review-reports/assets/adopt-a-pet-homepage-320.png`

All pet and editorial photos were harvested from the live homepage asset inventory. Every pet listing uses a distinct captured image; no placeholder or generated image is present.

## Reset proof

After the final task audit, both databases had MD5 `376b1ca1b6197540c9e01f7893096287`:

- `/opt/WebSyn/adopt_a_pet/instance/adopt_a_pet.db`
- `/opt/WebSyn/adopt_a_pet/instance_seed/adopt_a_pet.db`

Calling `seed_benchmark_users()`, `seed_database()`, and `seed_user_state()` on the initialized runtime did not change that hash.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions sites/adopt_a_pet/.build-generated-seed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Seed generated from tracked app.py during Docker build.
3 changes: 3 additions & 0 deletions sites/adopt_a_pet/_health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Per-site health probe (optional, called by control_server)."""
def health():
return {"ok": True, "site": "adopt_a_pet"}
Loading