SCHEDULE. games.monsterrobot.depot-archive installed on ultra, daily 05:30 — after meshgod at
05:00, matching the existing games.monsterrobot.* launchd convention, plist kept in the repo
beside the script. plutil-linted and bootstrapped; launchctl reports it registered.
PRUNE. John wants old GLBs off the live VPS while keeping everything backed up. Age alone cannot
decide that: two shipping games resolve depot assets BY FILENAME at runtime, so a three-year-old
mesh some game still names is load-bearing, not stale, and deleting it is a 404 in a released
build. So prune.py deletes only when all three hold — older than --days, named in NO consumer's
source (scanning js/html/json/ts across thriftgod, procity and 90sDJsim, including the JSON
manifests that also carry depot refs), and an identical-SIZE copy confirmed in the Drive archive.
Size mismatch counts as unbacked; it never deletes on a maybe. Dry-run by default, and apply
re-verifies every rule rather than trusting the earlier plan. Thumbnails and meta.json are left
alone so the depot keeps listing pruned entries, as the MeshGod archive does.
Measured today it deletes NOTHING, correctly: of 774 assets, 35 are game-referenced and 724 are
newer than a 180-day cutoff — every asset in the depot is under 30 days old. Reported as-is
rather than loosening the cutoff to manufacture a result.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PUBLISHED. wg-harvest-demo.glb (a dressed character: character_kit body + a garment harvested off
a Ready Player Me donor) went to the live depot through wardrobegod's own export hub. 773 -> 774
assets, and fetching it back over the PUBLIC Cloudflare front — exactly what thriftgod does at
runtime — returns 200, the exact byte count, and valid glTF magic. The whole publish path is
proven end to end, not just the upload half.
BACKUP. depot/archive.sh, deployed to ultra:~/depot-backups/ (outside ~/Documents because of the
launchd TCC trap, absolute homebrew paths), following the existing MeshGod flow: ultra rsyncs the
VPS asset dir, rclone pushes to gdrive:DB-BACKUP/3god-depot alongside the sibling archives.
Not Gitea: git has no delta compression for binary blobs, so 774 GLBs would grow that repo
without bound on every re-upload, and Gitea sits on the disk-tight old box. Wrong tool for 7.5 GB
of meshes that only ever get added to.
One deliberate divergence from the MeshGod script it is modelled on: NO PRUNING. MeshGod deletes
VPS .glb older than 180 days because its gallery keeps thumb+index so stale entries still list.
This depot is live runtime infrastructure — two shipping games resolve assets from it BY FILENAME
at runtime, so pruning an old mesh is a 404 in a released game. Archive only.
Also inherits the fleet-wide risk already logged in the backup-verify skill: gdrive: uses
rclone's shared Google client_id, retired by Google during 2026, and every Drive flow dies with it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3GOD was "three.js god" — a quick way to eyeball a GLB and drop it into a game. wardrobegod's
stage, grid and publish flow cover that far better now, so the bench is retired. What survives is
the half that quietly became infrastructure.
Absorbed into depot/: server.py (271 lines, verbatim), its hardening tests, and viewer.html kept
as superseded reference only.
Retiring the REPO is safe; retiring the SERVICE is not. The live instance on the dealgod VPS
holds 773 assets and two shipping games fetch from it at runtime — thriftgod web/index.html:1176
and procity loaders.js:7 both hardcode https://digalot.fyi/3god. So the /3god URL stays even
though the name is gone: changing it means editing two shipping codebases for no benefit, and the
name now survives only as a URL path nobody looks at. The VPS service is deployed, not sourced
live from the Gitea checkout, so archiving that repo changes nothing at runtime.
Checked before discarding the UI: the depot's /api/meta tag store had 0 tags and 0 notes across
all 773 assets, so there was nothing to migrate. Tagging lives in library/index.json now.
depot/README.md records the two things that are easy to get wrong and expensive to rediscover:
publishing must go direct over the tailnet (the Cloudflare front 403s because auth trusts the raw
socket peer — thriftgod's own prop_campaign.py --publish is broken for exactly this), and
clean_name DELETES illegal characters so 'shop!-cat.glb' silently resolves to an existing
different mesh.
Verified after the change: both the public and tailnet endpoints still answer 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>