Quick answer
A well-documented project is not a safe project. Ashaveth carries 46 markdown documents, written carefully by people who cared, and measured on 2026-09-01 nearly every authoritative one disagrees with the code it describes — a self-declared "single source of truth" wrong on essentially every number, a balance audit that went stale 32 minutes after it was saved, and a bundle size published 15.5% under what the server actually sends. None of it is dishonest. The code simply moved faster than anyone could maintain the sentences about it. The cure is in the same repository: a handful of tests whose only job is to assert facts about the project itself. Prose decays silently. Assertions fail loudly.
Key takeaways
- Documentation quantity is not documentation accuracy. 441 KB of careful writing, and the numbers still drifted.
- A document can be stale in half an hour. Audit saved 16:18; the two fixes it demanded landed 16:50 and 16:52 the same day. Nobody went back.
- The number your bundler prints is not the number your server sends. 122 kB claimed, 140,856 bytes measured over the wire.
- Write the fact as an assertion, not a sentence. A test can hard-code a banned string and fail the day it reappears.
- Assert against source when behaviour isn't observable — one guard here reads the provider's own file and checks every call site.
- Count the exit paths before you trust a gate. Five of ten checks in this repo can actually stop you shipping. Five cannot.
The game this is about
First Play it for two minutes. Everything after this is a claim about this game, and half the point of the class is checking claims.
ashaveth.ddsboston.com, embedded. Click-to-load on
purpose — nothing fetches until you ask for it. Self-rated 18+.
Ashaveth is a free browser role-playing game: 50 levels across five biomes, 72 monsters, four gate bosses and a final boss, three endings, and live AI-written dialogue for the three residents of the last town. The world is a palimpsest — a page written on before, being scraped clean — and something has reached the last town.
On the name
Everything in Ashaveth is original to Design Delight Studio: the setting, the 72 monsters, the five bosses, the three named residents of Sallowmere, and the forge-only sword called Godsbane. It is not based on or affiliated with any other franchise. Its lineage is the 1990s bulletin-board door game as a genre — a daily budget of fights, a real-calendar reset, a death penalty measured in net worth — rebuilt with a story that takes those conventions seriously.





All four of those numbers are measured, and I will come back to two of them, because the project's own documents give different ones.
The corpus, and what happened to it
The setup 46 markdown documents. 441,416 bytes. Written carefully. Nearly every authoritative one is wrong today.
Start with the thing that makes this interesting: this is not a badly documented project. MEASURED on 2026-09-01, excluding dependencies and build output, the repository carries 46 markdown documents totalling 441,416 bytes — an architecture doc, a save-format spec, a testing strategy, a deploy topology, a monster-art plan, a claims register, a build dossier, three separate audits, and a self-declared canonical fact sheet.
That is more written record than most commercial projects carry. It is also why the result is worth your time. A badly documented project having bad documentation teaches nothing. A carefully documented project whose documents are nearly all wrong within weeks teaches something structural.
The self-declared source of truth
One document opens by calling itself the "single source of truth for all Ashaveth marketing." Measured against the code it describes:
| The fact sheet says | Measured 2026-09-01 | |
|---|---|---|
| Final boss has 25,000 HP | 13,000 | wrong |
| 103 art assets | 192 | wrong |
| 154 tests across 7 files | 667 across 32 | wrong |
| Godsbane deals 3× to the final boss | 2.5× | wrong |
| Death costs half your carried gold | 15% of carried + banked | wrong |
| Entry bundle 327 kB | 370 kB | wrong |
Every one of those was true of version 1.0.0. The game shipped 1.2.0. The document was never re-run. A document that calls itself the single source of truth and is not regenerated is the most dangerous artifact in a repository, because its title discourages exactly the check that would catch it.
Five documents, five measurements
Each row pairs a claim from a repository document with a measurement taken on 2026-09-01. Decide whether the measurement supports the claim.
The canonical fact sheet is the single source of truth
measured delta -12000 HP -48.0%
The canonical fact sheet is the single source of truth
measured delta +89 assets +86.4%
The maths audit's pacing figure still stands
measured delta +63965 XP +6.4%
The handover note states the AI spend ceiling
measured delta +4667 calls per day +1401.5%
The landing page states the compressed download size
measured delta +18856 bytes +15.5%
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
Six claims. Which hold?
Before reading on, work these yourself. Each is a real sentence from a real document in this repository.
Is the document telling the truth about the code?
Six claims, quoted from the repository's own documents. For each: is it true of the code today?
The canned fallback is deliberately indistinguishable from working AI.
LAUNCH.md line 11, written 2026-07-12 the fix landed 2026-07-13
The AI proxy allows exactly two text models, with image and speech generation deliberately absent.
cloudflare-worker.js lines 97-100
The project has 154 tests across 7 files.
npx vitest run Test Files 32 passed · Tests 667 passed
utils analytics: telemetry is live and reporting.
repo-wide search: no such file
Every renamed entity keeps a pinned art key so the rename cannot orphan its portrait.
ipClearance.test.ts 9 assertions, currently passing
The image quality checker fails the build when an asset is the wrong size.
qa-images.py — one sys.exit, at line 7
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
Stale in thirty-two minutes
The sharpest case An audit is saved at 16:18. The two defects it demands be fixed are fixed at 16:50 and 16:52. The audit is never touched again.
The repository contains a balance audit — a careful, specific document that names defects with file references and proposes fixes. Two of its findings concern exploits:
- A character conversation offers a free, repeatable full heal, which undercuts the inn as a gold sink because talking costs no fights.
- Forest encounter gates roll unseeded randomness while the outcome is seeded, so a player can reload the page to re-roll the gate.
Now the timestamps. MEASURED from file modification times:
| Time | File | What happened |
|---|---|---|
| 16:18 | AUDIT-GAME-MATH-CLAUDECODE.md | The audit is saved. Both findings recorded as open. |
| 16:50 | NPCInteractionScreen.tsx | The heal is gated to once per character per day. The comment cites the audit's own reasoning. |
| 16:52 | ForestScreen.tsx | The gate roll is moved to a seeded generator keyed on day, health, gold, fights and biome. Comment: "NOT reload-rerollable." |
| — | AUDIT-GAME-MATH-CLAUDECODE.md | Never updated. Still reports both as open, today. |
Thirty-two minutes. The developer read the audit, fixed both defects immediately, wrote comments in the code quoting the audit's own language — and did not go back to the document, because at that moment the document had already done its job. It had communicated. Its remaining life as a record was nobody's task.
This class's own research fell for it
I dispatched six read-only specialists over this repository. One was told, explicitly, to verify claims rather than accept them. It read the audit, could not check those two findings because they sat outside its assigned files, and reported them as current open risks. A second specialist, whose scope did include those files, found both fixed and produced the timestamps above.
So: a research process built specifically to catch stale documents was itself misled by a stale document, mid-research, in the class about stale documents. That is not an embarrassing aside. It is the finding. The failure mode does not require carelessness. It only requires a reader who has a document and does not have the file.
The same shape, four more times
Once you look for it, the pattern is everywhere in this repository, and every instance is innocent:
| Document | Went wrong when | Because |
|---|---|---|
| LAUNCH.md | the next day | A production outage forced the AI fallback to announce itself. The runbook still says it is undetectable. |
| ASHAVETH-ADS-AUDIT.md | when the banner was deleted | It describes a rotating advert that no longer exists. A test now asserts it stays deleted. |
| proxy/DEPLOY.md | on its second config change | One commit, ever. Still documents a wildcard origin and model names that are gone. |
| AUDIT_REPORT.md | before version control existed | 59,716 bytes, the largest document here. Committed once, at the root commit. It describes a prototype deleted before git init ran. |
That last one is worth sitting with. The largest document in the repository has exactly one commit — the first one — and has never been touched across 54 subsequent commits. It reads as a live defect list. Eleven of its findings were sampled against current source; eleven were already fixed or described code that no longer exists. Its subject is a 1,543-line component. That component is now 185 lines.
The number the bundler prints
Measurement The landing page says the bundle compresses to 122 kB. Fetching that exact file returns 140,856 bytes. Both numbers are honest. Only one is about the user.
The public page states, twice, that Ashaveth's 370 kB entry bundle "compresses to 122 kB gzipped." That figure came from the build output, where it is printed in a tidy column next to the raw size. It is exactly right about what the bundler did.
Here is the same file, fetched from the live server:
curl -s -o /dev/null -w '%{size_download}' \
https://ashaveth.ddsboston.com/assets/index-DdQpyQ8e.js
371388
curl -s -H 'Accept-Encoding: gzip' -o e.gz \
https://ashaveth.ddsboston.com/assets/index-DdQpyQ8e.js && wc -c < e.gz
140856 # content-encoding: gzip
gzip_comp_level is never set in the
configuration. Both numbers are correct about their own subject.
gzip on;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
gzip_min_length 1024;
# no gzip_comp_level — so nginx uses level 1: fastest, weakest
Nobody lied. A number was copied out of a build log into marketing copy, and the build log was measuring something the server does not do. Build-time output describes what a tool did. It does not describe what a user receives. The only way to know the second is to fetch the artifact from production and weigh it.
The same trap, in the opposite direction, on this very page
Every image on this page is the game's own art, uploaded byte-identical from the repository. Shopify's CDN then re-encoded them — and made several larger: the final boss plate went from 53,494 bytes on disk to 89,785 bytes served, dimensions unchanged. If I had captioned these with their repository sizes, I would have made exactly the mistake this module is about, in a module about not making it.
Which measurement is the one a user experiences?
Three rounds. In each, one of the numbers is the one that describes what actually reaches a person.
four numbers exist for the same file
Three of these are true statements about something other than the user.
uploaded byte-identical to a CDN
The CDN is a transformation, not a delivery pipe.
the project claims full coverage
A count is not a scope.
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
The cure: documentation that executes
The answer One file in this repository cannot go stale, because it is not prose. It is a test whose only job is to assert facts about the project.
The game was rebuilt under a new name. A rename is exactly the kind of fact that gets written down once and then rots — and here it very nearly did. The file that fixed it opens by stating the failure plainly:
"The rebrand changed the marketing and the metadata — and stopped before the code. So the FINAL BOSS still rendered under the pre-rebrand name, in two places a player could see... Meanwhile Wren and Vosk's dialogue said 'Ashaveth', and the in-game Almanac said 'ASHAVETH, THE RED'. The game's own fiction and its own UI disagreed about the name of its final boss."
And then the trap that made it expensive:
"the image cache key for a monster is derived from its name... A naive rename ORPHANS THE SHIPPED PORTRAIT — assets are pre-baked into the repo and keyed by string. The fix is to PIN the art key in the data, so the display name is free to change and the image still resolves."
A markdown file saying "we renamed the boss; remember to pin the art key" would have been accurate on the day it was written and silent forever afterwards. Instead the fact was written as nine assertions:
the final boss displays as Ashaveth, the Red
no banned name appears in any monster's display name
their ability names are grimdark too — no Pixel Bite, no Taser
every renamed monster pins an art key, and the pin != the display name
no provider rebuilds the art key from the display name ← reads SOURCE
a save that killed the old-named boss is migrated on load
other boss kills are left alone
a save with no kills does not explode
every forge-stage boss still exists — the rename orphaned no gate
That is a complete, executable specification of a rename: the display rule, the art-key invariant, the transit invariant, the save migration, and the progression gate. It is about 7.6 KB. It replaces a paragraph that would have been wrong within a month, and it fails the moment any of those facts stops being true.
The anatomy of a document that cannot go stale
The rename regression suite, trimmed. Click any highlighted line to see what that part is load-bearing for.
// IP-CLEARANCE REGRESSION SUITE.//// So the FINAL BOSS still rendered under the pre-rebrand name.
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
The same pattern, four more times
Once you have the idea, this repository is full of it — each one a fact somebody refused to leave in prose:
| File | The fact it refuses to let rot |
|---|---|
| thinkingBudget.test.ts | Reads the AI provider's own source by regular expression and asserts every call site pins a configuration flag. It guards a shipped bug where hidden reasoning tokens ate the budget and truncated combat narration to four characters — invisible to an empty-string fallback, because the string was not empty. |
| endingContrast.test.ts | Asserts the old colour would now fail contrast. A fix that only asserts the new value can be silently reverted by a restyle; one that asserts the old value cannot. |
| ads.test.ts | Asserts a deleted component stays deleted, and reads source to confirm there is no third-party tracker or pixel. |
| check-secrets.mjs | Scans the build output for six credential patterns and exits non-zero. Wired as an automatic post-build step, so it also runs inside the Docker build. |
| AddToHomeScreen.test.tsx | Asserts the service worker never caches the entry bundle, so a stale build can never be served to a returning player. |
The rule
When a fact matters, write it as an assertion, not a sentence. Prose decays silently — it keeps its confident formatting while quietly becoming false. An assertion decays loudly: the day the fact changes, something red happens. You do not need to document everything this way. You need to do it for the claims you cannot afford to be wrong about.
What stops a bad rename
Push a change through this project's actual pipeline and see which check catches it.
Which check stops it?
Five changes entering the build. Pick the check you think refuses each one, then see how far it actually gets.
A rename that puts the pre-rebrand boss name back on screen
- tsc --noEmittype-checks every file without emittingpass
- ipClearance.test.tsbanned names, pinned art keys, save migration, progression gatesREFUSED
- check-secrets.mjsscans the built output for six credential patternsnever reached
- vite buildemits the production bundlenever reached
A tidy-up that makes the pinned art key equal the display name again
- tsc --noEmittype-checks every file without emittingpass
- ipClearance.test.tsbanned names, pinned art keys, save migration, progression gatesREFUSED
- check-secrets.mjsscans the built output for six credential patternsnever reached
- vite buildemits the production bundlenever reached
An API key accidentally inlined into the bundle
- tsc --noEmittype-checks every file without emittingpass
- ipClearance.test.tsbanned names, pinned art keys, save migration, progression gatespass
- check-secrets.mjsscans the built output for six credential patternsREFUSED
- vite buildemits the production bundlenever reached
A component that renders an element it never imported
- tsc --noEmittype-checks every file without emittingREFUSED
- ipClearance.test.tsbanned names, pinned art keys, save migration, progression gatesnever reached
- check-secrets.mjsscans the built output for six credential patternsnever reached
- vite buildemits the production bundlenever reached
Publishing a compressed bundle size copied from the build log
- tsc --noEmittype-checks every file without emittingpass
- ipClearance.test.tsbanned names, pinned art keys, save migration, progression gatespass
- check-secrets.mjsscans the built output for six credential patternspass
- vite buildemits the production bundlepass
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
The tests lie too, in the other direction
The counterweight If documents overstate what is broken, tests overstate what is safe. Five of ten checks here cannot fail.
A class that only criticised prose would be half a class. The same repository shows the opposite failure just as clearly: a green suite that is narrower than it looks.
The balance harness that cannot fail
The combat engine's three tuning constants carry comments saying they were "tuned in the harness." The harness is real: it drives the shipped engine through 30,000 simulated fights and prints a win-rate table. Here is every assertion in it:
line 185: expect(true).toBe(true);
line 199: expect(true).toBe(true);
line 237: expect(true).toBe(true);
Three tests, three assertions, all tautologies. The file is structurally incapable of failing regardless of what the simulation produces — the balance signal exists only in console output a human has to read. And it is excluded from the test run by name, so even the printing does not happen unless someone invokes it directly.
This is not laziness. It is a scratch tool that was useful once and then sat in the tree
looking like a test. The word test in a filename is not a
guarantee.
Three more that look like gates
- Two browser verification scripts — correctly written, with genuine non-zero exits — import their browser library from a hardcoded temporary directory path that appears in neither the dependency list nor the lockfile. They only ever worked on one machine, and a clean checkout cannot run them.
- A performance script shells out to a tool nobody installs.
- The image quality checker prints failures and exits successfully. Its only exit call guards a missing library, not a failed check.
And the gap inside the passing suite
667 tests pass. They are logic-only — no browser rendering — which the project's own testing document states honestly. But 17 of the 34 state-machine actions have no dedicated test anywhere, including the ones that heal you at the inn, buy a drink, revive you after death, and apply damage. A reader seeing "667 passing" would reasonably assume the inn's gold and health arithmetic is pinned down. It is not.
Two questions worth asking of any suite
Has this check ever been observed failing? A test never seen to fail is not known to work. One file here records that it was verified to discriminate — run against the broken source it reports failure, against the fixed source it passes. That sentence is worth more than the test count.
What does the number cover? "667 tests" is a count, not a scope. The honest form names the boundary: 667 unit tests covering the game logic, with no browser rendering and 17 state actions uncovered.
What we would do differently
Still open Everything unresolved, stated plainly — including four corrections this class made to its own research while writing it.
Still open in the repository
- Two governing documents have no supersession marker. The claims register and the canonical fact sheet are both stale against the shipped version. The retraction, where it exists at all, lives in a different file. The next reader opens the stale one.
- The largest document has no banner saying it describes a deleted prototype.
- There is no continuous integration. Five real gates exist and all of them run on whoever remembers to type the command.
- Two verification scripts cannot run on a clean checkout — hardcoded path, undeclared dependency.
- Seventeen state actions are untested, including four that move gold or health.
- The handover note is 15× off on the AI spend ceiling, and contradicts a correct measurement in a sibling file.
- The project calls itself open source with no licence file. The readme still carries a to-do to choose one. That claim is not currently true.
Four corrections this class made to itself
A class about verification that hides its own misses is worth less than one that shows them. All four were caught by measuring rather than reading.
| What a researcher reported | What is true | The method that produced the error |
|---|---|---|
| Two exploits are current open risks | Both fixed — 32 minutes after the audit was written | Trusted a checked-in document over the source, because the relevant files were outside its assigned scope |
| The balance harness has seven vacuous assertions | Three — and they are the file's only assertions | Counted test blocks from a skim instead of grepping. The real finding was starker than the reported one |
| The image checker has no exit call | It has one, guarding a missing library — not the failure branch | Grepped for the conclusion rather than for the token |
| The corpus is 41 documents / 413,470 bytes | 46 documents / 441,416 bytes | A prior measurement, carried forward without re-running — the exact failure this class is about |
The last row is the one I would keep. That figure came from my own handoff note, written days earlier, and I nearly published it. The pattern does not spare the people who are looking for it.
Write one now
Pick a fact in your own project that you cannot afford to be wrong about, and turn it into something that fails. Fill this in and download the result.
Turn a sentence into an assertion
The shape is the one this repository uses: name the incident, put the fact in data, then assert it where it can be checked.
Your answers stay in this browser. Nothing is sent anywhere. Reset clears them.
The five that would have caught all of this
Date every figure and name its method, or it cannot be audited, only believed. Mark a superseded document at the top of itself, not in a correction one directory away. Measure the server, not the bundler. Count the exit paths before calling something a gate. And put the claims you cannot afford to be wrong about into assertions — everything else can be prose, provided nobody treats it as current without checking.
Bottom line
Nothing in this repository was written carelessly. Forty-six documents, a real test suite, a credential scanner wired into every build, a regression suite that enforces a rename down to its art-cache keys — this is a project that took its own record seriously. And measured on a single afternoon, its self-declared source of truth was wrong on every number, its largest document described software that had been deleted, and one audit went stale in the time it takes to fix two bugs. The code did not betray the documentation. The code simply moved, and sentences do not move with it. The only documentation that kept up was the documentation that runs.



Frequently asked
What is Ashaveth?
Ashaveth is a free browser role-playing game by Design Delight Studio. Fifty levels across five biomes, seventy-two monsters, four gate bosses and a final boss, three endings, and live AI-written dialogue for the three residents of the last town. Everything in it is original to the studio: the setting, the monsters, the bosses, the named characters and the forge-only sword called Godsbane. It is not based on or affiliated with any other franchise. Its lineage is the 1990s bulletin-board door game as a genre — a daily budget of fights, a real-calendar reset, a death penalty measured in net worth — rebuilt with a story that takes those conventions seriously.
How many documents does the project ship, and why does that matter?
Forty-six markdown documents totalling 441,416 bytes, measured on 1 September 2026 excluding dependencies and build output. That is a more complete written record than most commercial projects carry, which is exactly why it is worth auditing. The interesting result is not that a badly documented project has bad documentation. It is that a carefully documented project, written by people who cared, still ends up with nearly every authoritative document wrong within weeks.
What does it mean for a document to be stale in 32 minutes?
The repository contains a balance audit whose file modification time is 16:18 on 14 July 2026. It reports two open defects: an unlimited free heal from a character conversation, and a random roll that could be re-rolled by reloading the page. The two source files that fix those exact defects have modification times of 16:50 and 16:52 the same day. The fixes landed roughly half an hour after the document was saved, and the document was never updated to say so. Anyone reading it afterwards, including an AI agent doing research, would report two solved problems as current risks.
Why is the published bundle size wrong?
The landing page states that the game's 370 kB entry bundle compresses to 122 kB gzipped. Fetching that exact file from the live server with gzip encoding returns 140,856 bytes — 15.5 percent more. Nobody lied. The 122 kB figure is precisely what the bundler prints at build time. It is not what the server sends, because the nginx configuration enables gzip without setting a compression level, so nginx compresses at its weakest default while the bundler's estimate assumes a stronger one. A number was copied out of a build log into marketing copy, and the build log was measuring something the server does not do.
What is executable documentation?
A test whose only purpose is to assert a fact about the project rather than to check a feature. The clearest example in this repository is a regression suite covering a rename. It does not describe the rename in prose; it asserts that a set of banned strings never appears on any surface a player can read, that every renamed entity keeps a pinned art key, that no code path rebuilds that key from the display name, that old save files are migrated on load, and that the rename did not orphan a progression gate. A markdown file saying we renamed the boss would have been true the day it was written and silent forever after. The test fails the moment the fact stops being true.
Which checks in the project can actually fail a build?
Five of ten, measured. A credential scanner runs automatically after every build and exits with a failure code if it finds an API key inlined into the output. Four test files run as part of the suite and fail it: the rename regression suite, a guard that reads the AI provider's own source to confirm a configuration flag is pinned at every call site, a contrast test that asserts a previously used colour would now fail, and an advertising policy test that asserts a deleted component stays deleted. The other five cannot stop anything. Three browser verification scripts are wired into nothing and import a dependency from a hardcoded temporary path that exists on no other machine. An image quality checker prints failures and then exits successfully. A balance simulation has three assertions and all three are the literal expression expect true to be true, and it is excluded from the test run anyway.
Does the game actually use live AI, and can a player tell when it does not?
Yes, through a Cloudflare Worker that holds the API key server-side and enforces an origin allowlist, a two-model allowlist with image and speech quotas set to zero, per-session and per-address rate limits, and a hard global daily ceiling. For character conversation the player can tell when it falls back: each turn is tagged as live, cached or quota-exhausted, and the interface shows an explicit banner reading speaking from memory or today's improvised speech is spent. A comment in the fallback file states the principle directly: a fallback you cannot detect is a fallback that lies to you. For eleven other AI-written features, including monster descriptions and combat narration, there is no tag and no signal, so those still fall back silently.
How many tests does the project have, and what do they not cover?
667 tests across 32 files, all passing, run independently twice during this research. They are logic-only with no browser rendering, which the project's own testing document states plainly. Seventeen of the thirty-four state-machine actions have no dedicated test anywhere, including the ones that heal the player at the inn, buy a drink at the tavern, revive after death and apply damage. A reader seeing 667 passing tests would reasonably assume the inn and tavern gold and health arithmetic is pinned down. It is not. The correct way to describe this suite is 667 unit tests covering the game logic, never fully tested.
What is the practical lesson for someone building with AI agents?
Prose decays silently and assertions fail loudly, so put the facts that matter into assertions. Every document in this project was accurate when written; the code simply moved faster than anyone could maintain the sentences describing it. Writing more documentation does not fix that, and neither does a better model. What fixes it is converting the specific claims you cannot afford to be wrong about into checks that run: a banned string that must never ship, a constant that must be pinned at every call site, a deleted component that must stay deleted, a colour that must not regress. Everything else can be prose, provided you date it and never treat it as current without checking.
Is Ashaveth free, and is this class free?
Both are free. Ashaveth runs in a browser with no download, no account and no way to spend money inside it; the repository contains no payment or checkout code of any kind. This masterclass has no signup, no email capture, no paywall and no certificate. Every figure quoted on this page was measured from the repository or from the live server on 1 September 2026, including the figures that contradict the project's own documents, and including four corrections made to this class's own research while it was being written.
Keep going
The whole Academy is free
No signup, no email capture, no paywall, no certificate. Every class is measured from a real repository and cites its sources — including the mistakes, and including our own.
Browse all classes Play Ashaveth