# Provenance This repository is the Adventure Storyteller production fork. Its application code comes from **AI-DnD**, and its planning package (`planning/`) is original to this project. ## Upstream | | | | --- | --- | | Project | AI-DnD | | Repository | | | Commit | `d72f7c1bda0f34fccd84afb7a25c34eb01c901de` | | Subject | Stop paying twice for a block a retry can still throw away | | Author date | Mon 31 Aug 2026 16:14:24 +0000 | | Position | tip of `upstream/main` on 1 Sep 2026, when the fork was taken | | License | MIT, © 2026 Parth Thakkar | The commit is the one pinned by `planning/DECISIONS/009-ai-dnd-production-base.md` after Phase 0B. It was not substituted for a newer upstream commit. ## How the fork is wired Upstream history is *in* this repository rather than copied out of it. The import is a merge of the pinned commit with `--allow-unrelated-histories`, so: - `git log d72f7c1bda0f34fccd84afb7a25c34eb01c901de` shows the real upstream history, not a squashed snapshot; - upstream code paths are unchanged (`backend/`, `frontend/`, …), so a later upstream commit can still be fetched and cherry-picked against matching files. Upstream's own documentation trees, `plan/` and `docs/`, were removed on 2026-09-03: they described the hosted, scripted, multi-user product this fork is not. They remain in this repository's history and in upstream; - the planning package that predates the fork keeps its own history on the other parent of the merge. To re-verify from a fresh clone: ```bash git remote add upstream https://github.com/parththakkar106/AI-DnD.git git fetch --no-tags upstream git cat-file -t d72f7c1bda0f34fccd84afb7a25c34eb01c901de # -> commit git merge-base --is-ancestor d72f7c1bda0f34fccd84afb7a25c34eb01c901de HEAD && echo "in this history" ``` ## License Upstream is MIT. `LICENSE` is upstream's file, unmodified, and the copyright notice stays with it. The MIT terms require that the notice travel with the code and with substantial portions of it; keep `LICENSE` in place in any redistribution of this fork, including a packaged build. Work done in this repository after the fork is a derivative of that MIT-licensed code. ## Vendored third-party assets Both were added by Milestone M1 to remove a runtime Internet dependency. Each is redistributable and each has a regeneration path in the tree, so neither is an opaque binary nobody can rebuild. ### `backend/app/context/vendor/cl100k_base.tiktoken` The BPE merge table for OpenAI's `cl100k_base` tokenizer, used for context budgeting only — no model of OpenAI's is ever called. - Source: `https://openaipublic.blob.core.windows.net/encodings/cl100k_base.tiktoken` - SHA-256: `223921b76ee99bde995b7ff738513eef100fb51d18c93597a113bcffe865b2a7`, which is the digest `tiktoken` itself pins for that URL, and which `backend/app/context/encoding.py` re-checks every time it builds the encoding. - Published by OpenAI for use with `tiktoken` (MIT). ### `frontend/public/fonts/*.woff2` Cinzel, Crimson Pro and Inter, Latin and Latin Extended subsets, as variable fonts. All three are licensed under the SIL Open Font License 1.1; the license text ships beside them as `OFL-cinzel.txt`, `OFL-crimsonpro.txt` and `OFL-inter.txt`, which is what the OFL requires of a redistribution. Regenerate with `python3 frontend/tools/vendor_fonts.py`, which also rewrites `frontend/src/styles/fonts.css`. ## What this fork changed in Milestone M2 M2 is subtractive. It reduced the inherited application to the intended single-user, local-first trust boundary. **Nothing was added that upstream did not have, except the endpoint policy and the tests that hold these removals in place.** Removed in full: campaign scripting and the QuickJS sandbox; multi-user accounts, guest sessions, login, registration and the shared demo key; the visitor analytics tables, dashboard and beacon; the access log; per-IP and per-user rate limiting and quotas; Render deployment config; Postgres/Neon support; cloud inference providers and the API-key field; session-cookie signing and API-key encryption at rest. Added: `backend/app/endpoints.py`, which decides what an inference endpoint may be, and a configurable model timeout. Three database tables (`scripts`, `adventure_scripts`, `analytics_daily`, `analytics_visitor_days`, `access_log`) and four columns (`adventures.script_state`, `settings.api_key`, `users.demo_turns_used`, `users.demo_turns_date`) are left in place, unmapped or inert, so that an existing M1 campaign database opens unchanged. They are not product functionality and nothing reads or writes them. ## What this fork changed in Milestone M1 Nothing was removed from upstream. The changes are the offline/locality hardening M1 called for; see `planning/archive/milestone-reports/M1-BASELINE-REPORT.md` for the evidence. - `backend/app/context/encoding.py` (new) and `backend/app/context/builder.py` — build `cl100k_base` from the vendored table instead of downloading it on first use. - `frontend/index.html`, `frontend/src/index.css`, `frontend/src/styles/fonts.css` (new), `frontend/public/fonts/` (new), `frontend/tools/vendor_fonts.py` (new) — self-hosted fonts in place of the Google Fonts link. - `backend/app/main.py` — CSP narrowed to same-origin, with the two Google hosts dropped and `object-src` / `base-uri` / `form-action` added; `woff2` registered so the self-hosted fonts are served with their real media type. - `backend/app/tlstrust.py` (new), `backend/app/providers/openai_compatible.py`, `backend/app/routers/settings.py` — outbound HTTPS verifies against the machine's own CA store as well as certifi's, so a trusted-LAN Ollama with a locally-issued certificate works. Verification is not relaxed. - `start.sh`, `start.ps1`, `docker-compose.yml` — the storyteller listener is explicitly loopback-bound. - `backend/requirements.lock` (new) — the exact tested dependency closure. - `backend/tests/test_offline_assets.py` and `backend/tests/test_tls_trust.py` (new) — regression tests for the above. - `DEVELOPMENT.md` (new) — environment setup and Ollama configuration.