Give every new guest an adventure that is already played

An empty account gives a visitor nothing to read, and the daily demo turns are
limited, so learning what the app does cost one of them. `app/starter.py` now
copies a shipped export bundle into each new guest at the point the row is
created. The bundle is two exchanges of the Pokemon demo, which ends on a
knockout and shows an applied change, a refused one, and a milestone.

The guest row is committed before the copy is attempted, so a failure there
still leaves them with an account, and the copy runs inside a savepoint.

The row building that `POST /adventures/import` did inline moved into
`bundle.materialize`, which both callers use. The rate and size checks stayed
in the endpoint: the starter writes a file the server ships, so it has no
untrusted list to cap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PacdRuPXSkQQy4ZYdH32hF
This commit is contained in:
parththakkar106
2026-08-28 18:42:15 +05:30
co-authored by Claude Opus 5
parent ae39514d1e
commit 6cbf6d996f
6 changed files with 783 additions and 51 deletions
+6 -1
View File
@@ -3,7 +3,8 @@ import re
from fastapi import APIRouter, Depends, HTTPException, Request, Response
from sqlalchemy.orm import Session
from .. import accesslog, analytics, auth, cleanup, limits, models, schemas, security
from .. import (accesslog, analytics, auth, cleanup, limits, models, schemas,
security, starter)
from ..database import get_db
from .settings import get_settings
@@ -70,6 +71,10 @@ def me(request: Request, response: Response, db: Session = Depends(get_db)):
user = models.User(is_guest=True)
db.add(user)
db.commit()
# The guest is committed first, so a failure while copying the
# starter adventure still leaves them with an account.
starter.give(db, user)
db.commit()
_set_session_cookie(response, user.id)
# This endpoint is the SPA's bootstrap call, so it is where a session first
# shows itself; accesslog thins the rows down to one per day per address.