Remove false agency and the metaphorical carry from the hand-written pages - #138
Merged
Merged
Conversation
A door cannot need a key and surprise cannot roll itself. The door now opens only with the right key, which is how the vocabulary table on the index already states it, and the engine is the subject of both surprise rolls in the adventure walk-through. Part of #72. Claude-Session: https://claude.ai/code/session_01NmCezTw8hKKujkaEZ3YGAs
Authored content and inert models lose the verbs they cannot perform: a quest beat no longer displays itself, a depth bound no longer records its own note, a declaration no longer carries a value, and coin no longer earns XP. Two quantifiers name their members, and a repeated "both" in one sentence becomes the lock and the gate spelled out. Part of #72. Claude-Session: https://claude.ai/code/session_01NmCezTw8hKKujkaEZ3YGAs
The TUI crawler and FastAPI pages carried every em dash and semicolon in the hand-written docs, along with the metaphorical carry (an envelope that carries everything, a save that carries data) and sentences that spliced three facts together. Same facts, same sections, same code fragments and captured transcripts: the dashes become full stops, colons, or parentheses, the long sentences split, and the engine, the crawler, the view, and the server take the subject positions that were going to inert things. Part of #72. Claude-Session: https://claude.ai/code/session_01NmCezTw8hKKujkaEZ3YGAs
The page said a mistyped key "cannot fork a stream of its own", which is the opposite of what RngStreams.get does: any string forks a stream, so a typo draws plausible numbers from the wrong one. StreamName's own docstring in core/rng.py says so, and the page now says it too, with the advice to draw with a member rather than a typed-out string. A session builds its stream container rather than owning it, and the dashes and the pointer to the sections below go. Part of #72. Claude-Session: https://claude.ai/code/session_01NmCezTw8hKKujkaEZ3YGAs
A view does not drop a quest, so the sentence states what the one before it already establishes: the projection holds the active quests, so a finished one is not in it. The gate in the rejection sentence had no gate to point at. The formation-width sentence said "the space the party stands in" twice and now says what it measured the second time. The FastAPI page introduced "trust model", a term the docs do not use, and lost the "ever" that makes the seed claim absolute. Part of #72. Claude-Session: https://claude.ai/code/session_01NmCezTw8hKKujkaEZ3YGAs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The hand-written pages made inert things the subject of verbs they cannot perform (a door needed a key, a quest beat displayed itself, a dungeon made rolls, a cache spread itself across the party), reused the carry family to mean "contains" on pages where a party member literally carries an item, and left pronouns and quantifiers pointing at nothing in particular. The two front-end pages and the RNG streams page carried the register problems as well: every em dash and semicolon in the hand-written docs lived on those three pages, along with sentences that spliced three facts together, two pages that opened by describing themselves, and the stock words.
104 changes across 12 pages, in five commits: four grouped by page cluster (the index and getting-started pages, the guides, the two front-end pages, and the RNG streams reference) and one holding the five corrections review asked for, which are the last five rows of the table. 50 changes apply the agency, carry, and reference rules from #72; 54 apply the house prose rules the maintainer asked for in the same pass. Where one sentence had both, the row names both and the change is counted under #72's rule.
One factual correction came out of the pass.
docs/reference/rng-streams.mdsaid a mistyped stream key "cannot fork a stream of its own", which is the opposite of whatRngStreams.getdoes.StreamName's own docstring insrc/osrlib/core/rng.pysays a mistyped name raises nothing and draws plausible numbers from the wrong stream. The page now says that.No headings changed, no code identifiers, field names, rejection codes, message codes, or content ids changed, and nothing inside a fenced block changed. Line numbers are the same before and after on every page except
docs/reference/rng-streams.md, where one paragraph split in two and the numbers after line 15 shift by two.Four pages #72 lists are not in this pull request, because other work was in them:
docs/guides/views-and-visibility.md,docs/guides/listeners-and-flags.md,docs/front-ends/llm-referees.md, anddocs/adaptations.md.docs/reference/rejection-codes.mdanddocs/reference/message-codes.mdare generated from the source at build time and have no file to edit.Verification
uv run mkdocs build --strictpasses, before the corrections and again after them.uv run pytest tests/test_docs_gates.py tests/test_docs_examples.py tests/test_docs_site.py: 372 passed, 73 skipped, before the corrections and again after them.ruff format --check(157 files already formatted),ruff check(all checks passed),pyright(0 errors),uv run pytest(2906 passed, 146 skipped, 10 xfailed).CHANGELOG.mdentry: prose corrections are not behavior changes.Review table
docs/index.md:18docs/getting-started/quickstart.md:134docs/getting-started/building-an-adventure.md:51docs/getting-started/building-an-adventure.md:88docs/guides/gates-triggers-quests.md:3docs/guides/gates-triggers-quests.md:27map-editor.md:77.docs/guides/gates-triggers-quests.md:87docs/guides/gates-triggers-quests.md:89RecordNote(_truncatedincrawl/interpreter.py); the passive hid the actor.docs/guides/gates-triggers-quests.md:117offerbeat displays and lands in the journalofferbeat goes on the activation event and into the journalActivateQuest's docstring: the activation appends the beat to the journal and the event includes the same line.docs/guides/gates-triggers-quests.md:133docs/guides/sessions-commands-events.md:11docs/guides/sessions-commands-events.md:24record_notebeside them says which consequence was droppedrecord_notebeside them records which consequence was droppeddocs/guides/sessions-commands-events.md:35game_overandvictorydocs/guides/sessions-commands-events.md:46RevealObjectivesurfaces a hidden objectiveRevealObjectiveshows the players a hidden objectivedocs/guides/sessions-commands-events.md:96command_typethis version of the library has never heard ofcommand_typethis version of the library doesn't definedocs/guides/sessions-commands-events.md:109docs/guides/determinism-saves-replay.md:70docs/guides/rules-without-a-session.md:5docs/guides/ruleset-options.md:54docs/guides/authoring-custom-content.md:61docs/guides/authoring-custom-content.md:550docs/front-ends/tui-crawler.md:3input()input()docs/front-ends/tui-crawler.md:3docs/front-ends/tui-crawler.md:3docs/front-ends/tui-crawler.md:5docs/front-ends/tui-crawler.md:5docs/front-ends/tui-crawler.md:9"move e"is a sentencedocs/front-ends/tui-crawler.md:15MovePartyexpectsMovePartytakesdocs/front-ends/tui-crawler.md:15docs/front-ends/tui-crawler.md:15docs/front-ends/tui-crawler.md:21Visibility; filteringVisibility. Filteringdocs/front-ends/tui-crawler.md:36docs/front-ends/tui-crawler.md:36enter— folded intoenter, folded intodocs/front-ends/tui-crawler.md:38docs/front-ends/tui-crawler.md:42docs/front-ends/tui-crawler.md:48Visibility.PLAYER— hit points, gold, and carried valuablesVisibility.PLAYER: hit points, gold, and carried valuablesdocs/front-ends/tui-crawler.md:48docs/front-ends/tui-crawler.md:48docs/front-ends/tui-crawler.md:52docs/front-ends/tui-crawler.md:58docs/front-ends/tui-crawler.md:64docs/front-ends/tui-crawler.md:64AreaSpecandEncounterTableinstances**;** nothing about authoring themAreaSpecand the rival table an ordinaryEncounterTable. Nothing about authoring either onedocs/front-ends/tui-crawler.md:68docs/front-ends/tui-crawler.md:68--scriptmode always builds--scriptmode always buildsdocs/front-ends/tui-crawler.md:80docs/front-ends/tui-crawler.md:86docs/front-ends/tui-crawler.md:98source="quest:the-idol"on every command this quest causessource="quest:the-idol"on every command the interpreter issues for this questdocs/front-ends/tui-crawler.md:127docs/front-ends/tui-crawler.md:127has_itemcondition tests whether the party holds the idol, not whohas_itemcondition tests whether the party holds the idol, not which member does_distribute_haulincrawl/exploration.pydoes both. One 60-word sentence with an em-dash pair becomes three.docs/front-ends/tui-crawler.md:127docs/front-ends/tui-crawler.md:131docs/front-ends/tui-crawler.md:134docs/front-ends/tui-crawler.md:136concludes_adventure=True- ends the session invictoryconcludes_adventure=True, ends the session invictorydocs/front-ends/tui-crawler.md:138victoryandgame_overalike, it answers "has this session ended?" in one readvictoryandgame_overalike, so one read tells a front end whether the session has endeddocs/front-ends/tui-crawler.md:140docs/front-ends/tui-crawler.md:140docs/front-ends/tui-crawler.md:146-150[link] — gloss[link] - glossdocs/front-ends/fastapi-pattern.md:3docs/front-ends/fastapi-pattern.md:3docs/front-ends/fastapi-pattern.md:3osrlib.errorsosrlib.errorsin fulldocs/front-ends/fastapi-pattern.md:5examples/fastapi_crawler/app.py— and every server fragment below is excerpted directly from that fileexamples/fastapi_crawler/app.py, and every server fragment below comes straight out of that filedocs/front-ends/fastapi-pattern.md:5docs/front-ends/fastapi-pattern.md:9defendpointsdefendpointsdocs/front-ends/fastapi-pattern.md:9docs/front-ends/fastapi-pattern.md:15_store_lock_store_lockdocs/front-ends/fastapi-pattern.md:15docs/front-ends/fastapi-pattern.md:19party_to_documentproduces andparty_from_documentvalidates — or with a save idparty_to_documentproduces andparty_from_documentvalidates) or with a save iddocs/front-ends/fastapi-pattern.md:31docs/front-ends/fastapi-pattern.md:33docs/front-ends/fastapi-pattern.md:33docs/front-ends/fastapi-pattern.md:38Interpreteris registeredInterpreteris registereddocs/front-ends/fastapi-pattern.md:38docs/front-ends/fastapi-pattern.md:44docs/front-ends/fastapi-pattern.md:50docs/front-ends/fastapi-pattern.md:54Nonefor acommand_typeit has never heard ofNonefor acommand_typethat isn't in the registrydocs/front-ends/fastapi-pattern.md:60docs/front-ends/fastapi-pattern.md:62docs/front-ends/fastapi-pattern.md:64accepted, the rejections, and the events — filtered toVisibility.PLAYERaccepted, the rejections, and the events, filtered toVisibility.PLAYERdocs/front-ends/fastapi-pattern.md:68docs/front-ends/fastapi-pattern.md:68docs/front-ends/fastapi-pattern.md:70docs/front-ends/fastapi-pattern.md:76-79[Error][…] — gloss[Error][…] - glossdocs/front-ends/fastapi-pattern.md:79docs/front-ends/fastapi-pattern.md:81ValueErrororTypeError— a bug in the calling code, not a condition to map — and in-fiction refusals, as above, aren't exceptions at allValueErrororTypeError, a bug in the calling code rather than a condition to map. In-fiction refusals, as above, aren't exceptions at alldocs/front-ends/fastapi-pattern.md:100docs/front-ends/fastapi-pattern.md:136docs/front-ends/fastapi-pattern.md:136docs/front-ends/fastapi-pattern.md:138eventseventsdocs/front-ends/fastapi-pattern.md:138accepted: falseresponseaccepted: falseresponsedocs/front-ends/fastapi-pattern.md:142docs/front-ends/fastapi-pattern.md:148Interpreter— the one listener this server runs, shown in the served content section — and hands backInterpreter(the one listener this server runs, shown in the served content section), and hands backdocs/front-ends/fastapi-pattern.md:148docs/front-ends/fastapi-pattern.md:152-155[link] — gloss[link] - glossdocs/reference/rng-streams.md:5docs/reference/rng-streams.md:15RngStreams.getforks a stream of its own for any string, so a mistyped key draws plausible numbers from that stream instead of raising.StreamName's docstring insrc/osrlib/core/rng.py: "A mistyped name raises no error:getforks a stream of its own for it and draws plausible numbers from that stream instead of the one you meant."docs/reference/rng-streams.md:19docs/reference/rng-streams.md:21RngStreamscontainer built from the session's master seedRngStreamscontainer from the session's master seedcore/rng.py's module docstring: aGameSession"builds its own container from the seed you give it".docs/reference/rng-streams.md:25docs/reference/rng-streams.md:123docs/front-ends/tui-crawler.md:48_statuswalks the active quests only, so the fact is that a finished quest is not there.docs/front-ends/tui-crawler.md:15docs/guides/ruleset-options.md:54docs/front-ends/fastapi-pattern.md:31docs/front-ends/fastapi-pattern.md:33Open questions
1. "Owns" for software holding state.
sessions-commands-events.md:3("It owns every piece of mutable state"),:35("the session-owned surface"),:50("engine-owned session state"),gates-triggers-quests.md:93("a state the engine owns"),fastapi-pattern.md:38("The server owns that wiring"). Strictly this is a quieter form of the same defect, and the house prose rules name it. I left every one of them, because #72 protects software acting and "engine-owned" is the established term in these pages and in the command docstrings. The one I did change isfastapi-pattern.md:79, where a front end "owns" a mapping decision, which is a metaphor about a person's choice rather than about state.2. "Holds" for containment. The house prose rules would push "contains" wherever a thing holds another thing. #72's "what is NOT the defect" protects containers containing, and these pages use "holds" throughout, including for the literal case ("the cache that holds the quest's MacGuffin", "whether the party holds the idol"). Left alone.
3. The heading
### Activation, and the quest that needs none.gates-triggers-quests.md:115. A quest cannot need anything, but headings are anchor targets and the packet rules them out. Worth a decision with the other headings, not on its own.4. The metaphorical carry survives inside fenced code comments.
authoring-custom-content.md:402,:434,:462,:466,:493,:527: "the adventure document carries the template", "a weapon carries damage and qualities", "the templates the adventure carries".tests/test_docs_examples.pyexecutes those blocks and the constraint forbids editing them, so they stay for now. They are the same sentence pattern the prose no longer uses.5. Hard-wrapped prose on the RNG streams page.
AGENTS.mdsays Markdown prose is never hard-wrapped, anddocs/reference/rng-streams.mdis wrapped at about 88 columns throughout. I kept the wrapping and re-wrapped only the two paragraphs I edited, because unwrapping the page would bury the wording changes under a whole-file reflow. Unwrapping it is a separate, mechanical change.6. "Five endpoints in
examples/fastapi_crawler/app.py".fastapi-pattern.md:5. It's a numeric count in prose, whichAGENTS.mdrules out, though it counts an example app's routes rather than a library surface. It drifts the same way. Left as it was.7. Sentence length on the RNG streams page. It still runs a median of about 27 words against the 20 the house style measures, because the page is built as one long sentence per stream. Splitting them would change the page's shape, which the edit-in-place instruction rules out.
8. "You" never appears on the two front-end pages. Both describe what an example does rather than instructing the reader, so I didn't add second person to reach the house numbers.
9. The register in the guide interiors is untouched. "a standing charge from round 0", "the walked-home-with-it test", "Coin weighs a coin apiece", "a script may sprinkle them anywhere".
AGENTS.md's voice gradient keeps the interiors rich, and none of these gives an inert thing a verb.10. In-fiction actors are untouched, per #72: "the brass key the sentinel wants" (
gates-triggers-quests.md:49), the bronze sentinel's refusal text, and everything in the captured transcripts, including "The temple wants the Jade Idol off the barrow king's altar".Undefined jargon found
Location and term only. Nothing here was changed.
docs/front-ends/tui-crawler.md:52.docs/front-ends/tui-crawler.md:48,docs/front-ends/fastapi-pattern.md:138.docs/guides/authoring-custom-content.md:111(the heading),:552,:554.docs/guides/gates-triggers-quests.md:29.docs/guides/authoring-custom-content.md:445;docs/guides/ruleset-options.md:46.docs/guides/authoring-custom-content.md:61.docs/guides/authoring-custom-content.md:31.docs/guides/ruleset-options.md:13,:30.docs/getting-started/building-an-adventure.md:57.docs/guides/authoring-custom-content.md:447.Vocabulary decisions for the owner
1. "Carrier", the specification's word.
docs/spec.md:207("the voice of carriers whose display beat the players never see") and:209("it applies while its carrier is in play"). Nothing renamed. After this pass no hand-written page in scope uses "carrier" at all: the guide sentence that used it was already rewritten onmainas "the blocks whose display beat the players never see". The literal sense is live in the code as well, where_spread_coins(carriers, …)insrc/osrlib/crawl/exploration.pymeans the party members holding the haul. Whether the spec keeps "carrier" for the structural sense is your call.2. "Seam".
docs/guides/authoring-custom-content.mdcalls theload_classesrebinding "the one seam", in a heading (#the-one-seam-characters-of-a-custom-class) and twice in the body. The house prose rules treat "seam" as a stock word and would write "the one place an id has to resolve", which the page already says in the next sentence. The heading is an anchor target linked from the same page, so renaming it is yours to decide.3. "Beat". A beat is authored narrative text on a narrative block, introduced in the index's vocabulary table.
tui-crawler.md:140also used "beats" for "points of advice"; that one is now "habits". Worth deciding whether "beat" is reserved to the narrative sense everywhere.4. "Keys" as an authoring verb.
tui-crawler.md:58said "Level 1 also keys a goblin-guarded guard room". A level keys nothing, so it now reads "has". If you want an authoring verb here, "you key an area to a level" puts the author in the subject position instead.5. "Room".
ruleset-options.md:54used "the room" for available floor space while "room" everywhere else in the docs is a keyed area. It now reads "the space the party stands in".Cross-repository effects
1. The gate docstring still gives the door a want, in a quieter word.
src/osrlib/crawl/gates.py:108reads "so a door that swings shut needs another key", while the guide sentence beside it,gates-triggers-quests.md:29, already read "takes another key" at this branch's merge base and is untouched here. "Needs" is on #72's own list of verbs an inert thing cannot perform, so the docstring half of the issue still has this sentence to fix. It reaches osr-editor through the generated types (frontend/src/types/generated/api.ts), and the same wording appears independently in that editor's gate condition builder help text, so neither copy changes until osrlib's docstrings are corrected and osr-editor's osrlib pin moves.2. Nothing else propagates. This pull request changes no schema, no code identifier, and no generated page, so osr-forge and osr-editor see nothing from it.
3. The second chunk.
docs/guides/views-and-visibility.md,docs/guides/listeners-and-flags.md,docs/front-ends/llm-referees.md, anddocs/adaptations.mdstill need the same pass, including the four carry sentences and the "expects the payout to follow on its own" sentence #72 names on the LLM referees page.Part of #72.
https://claude.ai/code/session_01NmCezTw8hKKujkaEZ3YGAs