Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fa70f03
Add UC Berkeley mirror site (port 40015)
richard-peng-xia May 13, 2026
c0a3fde
chore(berkeley): resolve merge with upstream/main, register as site 2…
evanz37 Sep 13, 2026
2f0c6c4
fix(berkeley): build-generated, byte-reproducible seed
evanz37 Sep 13, 2026
c1cdcb8
fix(berkeley): freeze the benchmark clock
evanz37 Sep 13, 2026
86ba06e
chore(scripts): fetch_assets.sh skips build-generated sites with no a…
evanz37 Sep 13, 2026
1929b84
fix(berkeley): article detail no longer writes view_count
evanz37 Sep 13, 2026
1d17acb
test(berkeley): add deterministic task verifiers and verify_lib
evanz37 Sep 13, 2026
0ff43bf
chore(berkeley): task selection, verifier_path and judge_rubric backfill
evanz37 Sep 13, 2026
67ee9a5
test(berkeley): add the run-signature writer and matrix harness
evanz37 Sep 13, 2026
eb19a2b
chore(berkeley): site README and integration tests
evanz37 Sep 13, 2026
50813e7
fix(berkeley): C — run_matrix writer drives and grades the real recor…
evanz37 Sep 13, 2026
67cff3d
fix(berkeley): C — negation before a titled name is no longer hidden …
evanz37 Sep 13, 2026
5aca1de
chore(berkeley): D — rubric polish
evanz37 Sep 13, 2026
66a0c8d
fix(berkeley): E — app robustness: POST-only logout, per-process key,…
evanz37 Sep 13, 2026
077f37f
fix(berkeley): E — answer facts no longer render before their discove…
evanz37 Sep 13, 2026
0603a3d
fix(berkeley): E — task 16 workflow pages to the catalogue page holdi…
evanz37 Sep 13, 2026
678f703
fix(berkeley): E — neutral ORDER BY on list queries and /search field…
evanz37 Sep 13, 2026
57cb484
fix(berkeley): E — WCAG AA contrast, 320px layout, heading order
evanz37 Sep 13, 2026
455e5f7
fix(berkeley): E — Featured badge escapes its card and overlaps the t…
evanz37 Sep 13, 2026
d5d42b9
fix(berkeley): E — seed generator self-locks the engine URI; scope RE…
evanz37 Sep 13, 2026
ae2bdbd
fix(berkeley): E — two-tone focus ring so the indicator is >=3:1 on t…
evanz37 Sep 13, 2026
a38df80
fix(berkeley): E — task 27 search gate accepts the route the ques nam…
evanz37 Sep 13, 2026
f237364
docs(berkeley): drop references to untracked review artifacts
evanz37 Sep 13, 2026
8e5bb7f
Merge upstream main (Healthline #105, Kaggle #106) into the UC Berkel…
evanz37 Sep 13, 2026
19f7322
feat(berkeley): synthetic imagery (FLUX.1 schnell scenes + determinis…
evanz37 Sep 15, 2026
08d30d8
merge: PR #116 (berkeley) onto main 7ace1c77; re-slot berkeley to ind…
Raibows Sep 15, 2026
36c29b6
docs: align the site inventory to 30 sites / 40000-40029 / 41000-41029
Raibows Sep 15, 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
49 changes: 38 additions & 11 deletions .assets-revision
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,32 @@
#
# The revision is a commit sha, never a moving branch name.
#
# Current pin = the commit that HF dataset `main` points at (verified
# 2026-09-13): the squash-merge commit of HF dataset PR #85 ("Upload nvidia.tar.gz
# with distinct official product and hero images (#107 follow-up)"), which sits on
# top of the merged PR #84 ("Upload repacked nvidia.tar.gz with de-duplicated
# official product images (#107)"), PR #75 ("Add reviewed NVIDIA asset bundle") and
# PR #74 ("Upload kaggle.tar.gz with huggingface_hub"), so this sha is on HF `main`.
# INTERIM PIN (2026-09-14) = refs/pr/91, the open Hugging Face dataset PR
# "berkeley: synthetic imagery bundle (164 files, sha256 ab9d2716...)" whose
# head commit is 4529b18c6fc23f9b203a281b2d1e1940ba93853b. It adds
# berkeley.tar.gz (sha256
# ab9d2716ae8d06540a181b5e60c37f613d87b103864b467511da546b1b173789,
# 6951483 bytes, 171 managed members) — the site's first archive, so that
# fetch_assets.sh can install sites/berkeley/static/images/. Checked at the merge
# of PR #116 onto main 7ace1c77 (2026-09-14): for all 29 sites registered before
# berkeley, this ref's archive size and LFS oid are identical to the b7e605c0 pin
# below, so switching the pin for the berkeley archive does not change any other
# site's assets; this ref covers all 30 registered sites (29 + berkeley).
#
# This is deliberately a PR ref rather than a sha: the PR is unmerged, so its
# head is only reachable through refs/pr/91. Refs of this shape move if the PR
# branch is updated, which is why this is marked interim. Once the PR is merged,
# re-pin `revision:` to the merged commit sha and delete this paragraph — the
# distinction the "never a moving branch name" rule above is about then applies
# again.
#
# Previous pin = b7e605c0ec5fc47de85b09e7427162cc50e38980, the commit HF dataset
# `main` points at (verified 2026-09-14): the squash-merge commit of HF dataset PR
# #85 ("Upload nvidia.tar.gz with distinct official product and hero images (#107
# follow-up)"), which sits on top of the merged PR #84 ("Upload repacked
# nvidia.tar.gz with de-duplicated official product images (#107)"), PR #75 ("Add
# reviewed NVIDIA asset bundle") and PR #74 ("Upload kaggle.tar.gz with
# huggingface_hub"), so this sha is on HF `main`.
#
# Its nvidia.tar.gz is the repacked bundle (sha256
# 617a3e3740ba6706bcab786c8a5c3f9a22ecbb39eff5728ad2c12e4992cb098b, 16340955 bytes,
Expand All @@ -25,15 +45,22 @@
# original 6706395-byte bundle (blob 0f1d8068af602748d0dec19ef04b52c7559fef28),
# which carried duplicates.
#
# Why this sha and not the other candidate (refs/pr/37, resolved
# Pin before that = 64264d065cdb0b7755ee99dab356be5733d9ddef, the commit HF dataset
# `main` pointed at (verified 2026-09-13). It carries the merged HF dataset PR
# #74 ("Upload kaggle.tar.gz with huggingface_hub") and the later PR #75 ("Add
# reviewed NVIDIA asset bundle").
#
# Why these pins and not the other candidate (refs/pr/37, resolved
# 600a3e1de158ae56dc82a5fab56c2ca25acb1e27):
# * this revision carries an archive for every registered site (29 of 29), and
# * the pinned revision carries an archive for every registered site (30 of 30
# for refs/pr/91: the 29 main-site archives plus berkeley.tar.gz; 29 of 29 for
# b7e605c0), and
# the kaggle seed DB it ships was found identical to the seed the site's own
# code generates (13/13 tables, row by row) in the PR #106 audit;
# * refs/pr/37 ships an older kaggle seed (models table has 10 rows instead of
# 11: densenet121-chestxray is absent) and its archives cover only 17 of the
# 29 registered sites, so pinning there would break fetch_assets.sh.
# * this revision's kaggle.tar.gz (sha256
# 30 registered sites, so pinning there would break fetch_assets.sh.
# * the pinned revision's kaggle.tar.gz (sha256
# dd6f1ab34f99989b300e3366225a8f8b0932d49d033b48f141938d16f1c0607d,
# 11278106 bytes) passes the repository's own
# scripts/validate_asset_archive.py:
Expand All @@ -43,4 +70,4 @@
# superseded 11278264-byte pack, sha256 c533c283...) no longer applies and
# `scripts/fetch_assets.sh` installs sites/kaggle's assets from this pin.
repo: ChilleD/WebHarbor
revision: b7e605c0ec5fc47de85b09e7427162cc50e38980
revision: refs/pr/91
4 changes: 2 additions & 2 deletions .claude/skills/clone-website/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ Then run the site once locally to produce `instance/<site>.db`, copy it to
```bash
./scripts/build.sh webharbor:dev
docker run -d --rm --name wh-test \
-p 8201:8101 -p 41000-41028:40000-40028 webharbor:dev
-p 8201:8101 -p 41000-41029:40000-40029 webharbor:dev

# your new site is on port 41000 + its index
curl -so /dev/null -w "%{http_code}\n" http://localhost:41000NN/
Expand All @@ -228,7 +228,7 @@ After Phase 1, you should have:
- `sites/<your_site>/static/` with real CSS/JS/icons (and images under HF assets)
- `sites/<your_site>/instance_seed/<site>.db` with seeded data
- Site registered in `websyn_start.sh`, `control_server.py`, `Dockerfile`
- All 29 sites still return 200 on the alt-port container
- All 30 sites still return 200 on the alt-port container
- Byte-identical reset passes

## Next step
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/evolve-env/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ through `BASE_DIR = os.path.dirname(os.path.abspath(__file__))`.
After any DB-affecting change:

```bash
# 1. Stop test container (don't touch user's working container on :40000-40028)
# 1. Stop test container (don't touch user's working container on :40000-40029)
docker stop wh-test 2>/dev/null || true

# 2. Rebuild
./scripts/build.sh webharbor:dev

# 3. Run on alt ports
docker run -d --rm --name wh-test \
-p 8201:8101 -p 41000-41028:40000-40028 webharbor:dev
-p 8201:8101 -p 41000-41029:40000-40029 webharbor:dev

# 4. Reset your site and confirm byte-identity
curl -X POST http://localhost:8201/reset/<your_site>
Expand Down Expand Up @@ -149,7 +149,7 @@ After Phase 3:
- Every task in `tasks.jsonl` is hand-verified to work end-to-end
- The mirror has no obvious leaks, broken forms, or empty pages
- Byte-identical reset passes
- All 29 sites still return 200
- All 30 sites still return 200

## Next step

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/harden-env/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ Hardening changes seed data. After any DB change:
```bash
./scripts/build.sh webharbor:dev
docker run -d --rm --name wh-test \
-p 8201:8101 -p 41000-41028:40000-40028 webharbor:dev
-p 8201:8101 -p 41000-41029:40000-40029 webharbor:dev
curl -X POST http://localhost:8201/reset/<your_site>
docker exec wh-test md5sum \
/opt/WebSyn/<your_site>/instance/<your_site>.db \
Expand Down
10 changes: 5 additions & 5 deletions .claude/skills/review-env/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ gh pr checkout <pr-number>
./scripts/fetch_assets.sh # pull the pinned HF revision
./scripts/build.sh webharbor:dev
docker run -d --rm --name wh-review \
-p 8201:8101 -p 41000-41028:40000-40028 webharbor:dev
-p 8201:8101 -p 41000-41029:40000-40029 webharbor:dev
```

Confirm the new/changed site is on the expected port (40000 + index). Note: the image now runs 29 sites (40000-40028).
Confirm the new/changed site is on the expected port (40000 + index). Note: the image now runs 30 sites (40000-40029).

### Step 2: The mechanical checks (5 minutes)

Run the same Pre-PR checks the contributor was supposed to run.

```bash
# 1. all 29 sites return 200
for p in $(seq 41000 41028); do
# 1. all 30 sites return 200
for p in $(seq 41000 41029); do
curl -so /dev/null -w "$p:%{http_code}\n" http://localhost:$p/
done

Expand Down Expand Up @@ -231,7 +231,7 @@ Leave a structured comment on the PR:
## Review: <site_name>

### Mechanical checks: PASS / FAIL
- [x] All 29 sites return 200
- [x] All 30 sites return 200
- [x] Control plane healthy
- [x] Byte-identical reset (md5 match)
- [x] Parallel reset <10s
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/seed-database/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,10 @@ gh pr create
./scripts/check_assets.sh # every site has instance_seed/
./scripts/build.sh webharbor:dev # docker build succeeds
docker run -d --rm --name wh-test \
-p 8201:8101 -p 41000-41028:40000-40028 webharbor:dev
-p 8201:8101 -p 41000-41029:40000-40029 webharbor:dev

# all 29 sites return 200
for p in $(seq 41000 41028); do
# all 30 sites return 200
for p in $(seq 41000 41029); do
curl -so /dev/null -w "$p:%{http_code}\n" http://localhost:$p/
done

Expand Down
12 changes: 6 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ A coding agent (Claude Code, Cursor, Aider, Codex, ...) is reading this. Read on

## What it is

29 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.
30 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 @@ -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-40028:40000-40028 webharbor:dev
docker run -d -p 8101:8101 -p 40000-40029:40000-40029 webharbor:dev
```

Or use the published image directly:

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

Sites are on `40000`-`40028` in the order declared by `SITES=( ... )` in `websyn_start.sh`. Control plane:
Sites are on `40000`-`40029` 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-41028:40000-40028 webharbor:dev
-p 8201:8101 -p 41000-41029:40000-40029 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 41028); do
for p in $(seq 41000 41029); 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-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`).
If a container is already running on `:8101` / `:40000-40029`, 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-41029`).
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-40028:40000-40028 webharbor:dev
-p 8101:8101 -p 40000-40029:40000-40029 webharbor:dev
# iterate locally...

./scripts/extract_assets.sh ../webharbor-static-pr/ # split assets out
Expand Down
15 changes: 13 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# WebHarbor — slim, self-contained image.
# 29 Flask mirror sites + control plane on :8101.
# 30 Flask mirror sites + control plane on :8101.

FROM python:3.12-slim-bookworm

Expand Down Expand Up @@ -70,6 +70,17 @@ RUN cd /opt/WebSyn/healthline && test -f instance_seed/healthline.db && \
PYTHONHASHSEED=0 python3 migrate_seed.py && \
python3 prune_unreferenced_images.py --apply && rm -rf instance

# Berkeley's generated imagery ships in the pinned asset bundle while its SQLite
# seed stays build-generated from tracked source — see .build-generated-seed. The
# inventory gate enforces exact coverage + per-file SHA-256 + decode at the planned
# dimensions of all 164 generated images (82 FLUX scenes + 82 Pillow avatars), the
# same contract as the webmd_doctor / compass / walmart_careers inventories.
RUN python3 /opt/WebSyn/berkeley/check_generated_assets.py
# No wall clock and no random salt reaches a row, so the artifact is
# byte-reproducible; websyn_start.sh copies it into instance/ at boot.
RUN cd /opt/WebSyn/berkeley && rm -rf instance instance_seed && \
PYTHONHASHSEED=0 python seed_data.py && rm -rf instance

COPY websyn_start.sh /opt/websyn_start.sh
COPY control_server.py /opt/control_server.py
COPY site_runner.py /opt/site_runner.py
Expand All @@ -92,6 +103,6 @@ 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-40028
EXPOSE 8101 40000-40029

CMD ["/opt/websyn_start.sh"]
Loading