Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 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
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
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,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 @@ -48,17 +48,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 -d -p 8101:8101 -p 40000-40027:40000-40027 webharbor:dev
docker run -d -p 8101:8101 -p 40000-40028:40000-40028 webharbor:dev
```

Or use the published image directly:

```bash
docker run -d -p 8101:8101 -p 40000-40027:40000-40027 \
docker run -d -p 8101:8101 -p 40000-40028:40000-40028 \
battalion7244/webharbor:latest
```

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

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

# 3. run on alt ports (don't collide with anything you already have running)
docker run -d --rm --name wh-test \
-p 8201:8101 -p 41000-41027:40000-40027 webharbor:dev
-p 8201:8101 -p 41000-41028:40000-40028 webharbor:dev

# 4. control plane healthy, all sites alive
curl -s http://localhost:8201/health | python3 -m json.tool | head

# 5. every site renders 200
for p in $(seq 41000 41027); do
for p in $(seq 41000 41028); do
curl -so /dev/null -w "$p:%{http_code}\n" http://localhost:$p/
done

Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ The full agent guide is loaded above via `@AGENTS.md`. The notes below apply onl

## Existing containers

If a container is already running on `:8101` / `:40000-40027`, treat it as the user's working environment — don't `docker stop` or `docker rm` it without explicit confirmation. Spin up your test container under a different name on alt ports (`:8201`, `:41000-41027`).
If a container is already running on `:8101` / `:40000-40028`, treat it as the user's working environment — don't `docker stop` or `docker rm` it without explicit confirmation. Spin up your test container under a different name on alt ports (`:8201`, `:41000-41028`).
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ git clone https://github.com/<you>/webharbor && cd webharbor
./scripts/fetch_assets.sh # pull current assets
./scripts/new_site.py mywebsite # OR edit an existing site
./scripts/build.sh && docker run -d --rm \
-p 8101:8101 -p 40000-40027:40000-40027 webharbor:dev
-p 8101:8101 -p 40000-40028:40000-40028 webharbor:dev
# iterate locally...

./scripts/extract_assets.sh ../webharbor-static-pr/ # split assets out
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.
# 28 Flask mirror sites + control plane on :8101.
# 29 Flask mirror sites + control plane on :8101.

FROM python:3.12-slim-bookworm

Expand Down Expand Up @@ -92,6 +92,15 @@ os.makedirs('instance_seed', exist_ok=True); \
shutil.copy2('instance/rotten_tomatoes.db', 'instance_seed/rotten_tomatoes.db'); \
print('Rotten Tomatoes seed DB generated at build time.')" && rm -rf /opt/WebSyn/rotten_tomatoes/instance

EXPOSE 8101 40000-40027
# Adopt-a-Pet freezes its relational catalog and captured real-site media.
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

EXPOSE 8101 40000-40028

CMD ["/opt/websyn_start.sh"]
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ 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** — 28 sites today, scaling to 100+ together
- **Community-driven** — 29 sites today, scaling to 100+ together

## 🚀 Quickstart

One command to run all web environments:

```bash
docker run -p 8101:8101 -p 40000-40027:40000-40027 battalion7244/webharbor:latest
docker run -p 8101:8101 -p 40000-40028:40000-40028 battalion7244/webharbor:latest
```

Then point your agent at `http://localhost:40000` through `http://localhost:40027` to explore 28 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, and Kaggle`.
Then point your agent at `http://localhost:40000` through `http://localhost:40027` to explore 29 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, and Adopt-a-Pet`.

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

Expand Down
2 changes: 1 addition & 1 deletion agent_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export OPENAI_BASE_URL=https://api.openai.com/v1 # or your Azure / vLLM endpoi

## Run a task

WebHarbor must already be running locally (`docker run -p 8101:8101 -p 40000-40027:40000-40027 battalion7244/webharbor:latest`).
WebHarbor must already be running locally (`docker run -p 8101:8101 -p 40000-40028:40000-40028 battalion7244/webharbor:latest`).

Run a single task from a site's `tasks.jsonl`:

Expand Down
1 change: 1 addition & 0 deletions control_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
'ikea', 'phys_org', 'target', 'ted',
'osu', 'rotten_tomatoes', 'compass', 'walmart_careers',
'fedex', 'webmd_doctor', 'healthline', 'kaggle',
'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.
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