Skip to content

Remove false agency and the metaphorical carry from the hand-written pages - #138

Merged
mmacy merged 5 commits into
mainfrom
chunk/prose-agency
Sep 15, 2026
Merged

mmacy merged 5 commits into
mainfrom
chunk/prose-agency

Conversation

@mmacy

@mmacy mmacy commented Sep 15, 2026

Copy link
Copy Markdown
Owner

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.md said a mistyped stream key "cannot fork a stream of its own", which is the opposite of what RngStreams.get does. StreamName's own docstring in src/osrlib/core/rng.py says 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, and docs/adaptations.md. docs/reference/rejection-codes.md and docs/reference/message-codes.md are generated from the source at build time and have no file to edit.

Verification

  • uv run mkdocs build --strict passes, 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.
  • The full gate: ruff format --check (157 files already formatted), ruff check (all checks passed), pyright (0 errors), uv run pytest (2906 passed, 146 skipped, 10 xfailed).
  • No CHANGELOG.md entry: prose corrections are not behavior changes.

Review table

File and line Before After Reason
docs/index.md:18 a door that needs a key a door that opens only with the right key A door cannot need. The vocabulary table lower on the same page already says "a locked door that opens only with the right item".
docs/getting-started/quickstart.md:134 a door that needs a key a door that opens only with the right key The same sentence, on the second of the three pages that used it.
docs/getting-started/building-an-adventure.md:51 Left unpinned, surprise and reactions roll normally Left unpinned, the engine rolls surprise and reactions normally The engine rolls.
docs/getting-started/building-an-adventure.md:88 Stepping in spawns the goblins, surprise and reaction roll Stepping in spawns the goblins, the engine rolls surprise and reaction Same defect, same page.
docs/guides/gates-triggers-quests.md:3 a door that needs a key a door that opens only with the right key The third copy of the sentence.
docs/guides/gates-triggers-quests.md:27 Locks and gates are separate layers, and a door with both requires both Locks and gates are separate layers: on a door with both, the party must open the lock and satisfy the gate A door cannot require, and "both" did two different jobs in one clause. Same fix as osr-editor#65 made to map-editor.md:77.
docs/guides/gates-triggers-quests.md:87 a spawn that arrives to find an encounter already open or a grant naming an item the catalog lost a spawn refused because an encounter is already open, or a grant naming an item the catalog no longer has A spawn does not arrive or find, and a catalog does not lose things.
docs/guides/gates-triggers-quests.md:89 A firing the bound suppresses is recorded as a note rather than a mark When the bound suppresses a firing, the interpreter records a note rather than a mark The interpreter issues the RecordNote (_truncated in crawl/interpreter.py); the passive hid the actor.
docs/guides/gates-triggers-quests.md:117 its offer beat displays and lands in the journal its offer beat goes on the activation event and into the journal A beat does not display itself. ActivateQuest's docstring: the activation appends the beat to the journal and the event includes the same line.
docs/guides/gates-triggers-quests.md:133 Coin paid on the doorstep earns no treasure XP Coin paid on the doorstep never converts to treasure XP Coin does not earn. "Converts" is the verb the same sentence pair uses on the TUI page.
docs/guides/sessions-commands-events.md:11 the journal entry that recorded it the journal entry that recorded the opening "It" could point at the move or at the portcullis.
docs/guides/sessions-commands-events.md:24 the record_note beside them says which consequence was dropped the record_note beside them records which consequence was dropped A note does not speak.
docs/guides/sessions-commands-events.md:35 illegal in both terminal modes illegal in both terminal modes, game_over and victory The quantifier named neither member.
docs/guides/sessions-commands-events.md:46 RevealObjective surfaces a hidden objective RevealObjective shows the players a hidden objective "Surfaces" as a verb. The command's own docstring says "show the players a hidden objective".
docs/guides/sessions-commands-events.md:96 a command_type this version of the library has never heard of a command_type this version of the library doesn't define Cognition given to a library.
docs/guides/sessions-commands-events.md:109 types the parser has never seen types the parser doesn't recognize Same defect, same page.
docs/guides/determinism-saves-replay.md:70 a declaration that carried the value beside some other action a declaration that had the value beside some other action Metaphorical carry.
docs/guides/rules-without-a-session.md:5 A stream's name is just a label A stream's name is a label Minimizer.
docs/guides/ruleset-options.md:54 measures the room, meaning the widest square of unbroken floor around the party measures the space the party stands in, the widest square of unbroken floor around them "Room" is the keyed-area word everywhere else in the docs; the sentence means available floor.
docs/guides/authoring-custom-content.md:61 leveling and energy drain move which row a character reads leveling and energy drain change which row applies to a character A character model does not read.
docs/guides/authoring-custom-content.md:550 Bundling unions per session through the adventure document that contains the templates Bundling joins your templates to the shipped catalog per session through the adventure document that contains them "Unions" as a verb is jargon for the union the session builds.
docs/front-ends/tui-crawler.md:3 built on osrlib and nothing else — no curses, no Textual, no web framework, just input() built on osrlib alone: no curses, no Textual, no web framework, only input() Absolute qualifier, minimizer, em dash.
docs/front-ends/tui-crawler.md:3 It exists to make one claim concrete: everything a session needs to run — rules, dice, state, the event log — lives in the library, everything a front end supplies — rendering, input handling — is ordinary application code … Three sentences, each with its parenthetical in parentheses A 60-word sentence spliced with four em dashes, announced by a sentence that only said the next one was coming.
docs/front-ends/tui-crawler.md:3 a graphical client instead**;** nothing about it assumes a terminal a graphical client instead**, and** nothing about it assumes a terminal Semicolon.
docs/front-ends/tui-crawler.md:5 This page walks that split section by section, excerpting the crawler's real source. Every code snippet below comes from the crawler's own source. The page describing itself, and "excerpt" for a snippet. The fact that the snippets are the real source survives, in the form the guides already use.
docs/front-ends/tui-crawler.md:5 see the example's own README one command starts an interactive game see the example's README**.** One command starts an interactive game Em dash.
docs/front-ends/tui-crawler.md:9 the library has no idea "move e" is a sentence the library takes typed commands, not sentences Cognition given to the library.
docs/front-ends/tui-crawler.md:15 the compass words MoveParty expects the compass words MoveParty takes A command model does not expect anything.
docs/front-ends/tui-crawler.md:15 the envelope already carries everything: whatever a nested listener-issued command logged the interpreter's reactions above all folds into the result the result envelope already contains everything. Whatever a nested listener-issued command logged (the interpreter's reactions above all) folds into the result Metaphorical carry, em-dash pair, and one sentence holding three facts.
docs/front-ends/tui-crawler.md:15 the authored refusal text when a gate wrote one — the one rejection family carrying words the player is meant to read the authored refusal text when the gate has one: the one rejection family that includes words the player is meant to read A gate cannot write; metaphorical carry.
docs/front-ends/tui-crawler.md:21 Every event carries a Visibility; filtering Every event has a Visibility. Filtering Metaphorical carry, semicolon.
docs/front-ends/tui-crawler.md:36 the result envelope earning its keep what the result envelope is for Stock phrase.
docs/front-ends/tui-crawler.md:36 what printed it was a command the interpreter issued inside the player's enter folded into the line came from a command the interpreter issued inside the player's enter, folded into Em dash, and a cleft that made the printing the subject.
docs/front-ends/tui-crawler.md:38 rendering a typed event a different front end could format rendering a typed event**.** A different front end could format Em dash.
docs/front-ends/tui-crawler.md:42 they ask the session for a whole snapshot built for players, rather than reaching into referee-only state themselves rather than reaching into referee-only state itself, the crawler asks the session for a whole snapshot built for players The crawler asks; its two verbs do not.
docs/front-ends/tui-crawler.md:48 called with Visibility.PLAYER hit points, gold, and carried valuables called with Visibility.PLAYER: hit points, gold, and carried valuables Em dash. The carried valuables are literal and stay.
docs/front-ends/tui-crawler.md:48 a finished quest leaves the projection, and its record is the journal The view drops a quest once it's finished, and the journal is where its record stays A quest cannot leave anything. The view is built from the active ones, as the same sentence already says.
docs/front-ends/tui-crawler.md:48 directly to render status**;** it renders the same view directly to render status**.** It renders the same view Semicolon.
docs/front-ends/tui-crawler.md:52 binds content descriptive text, an encounter, features to a set of cells**;** the shrine below binds content (descriptive text, an encounter, features) to a set of cells**.** The shrine below Em-dash pair, semicolon.
docs/front-ends/tui-crawler.md:58 Level 1 also keys a goblin-guarded guard room, but level 2 keys no monsters at all its only area Level 1 also has a goblin-guarded guard room, but level 2 has no keyed monsters at all**:** its only area A level keys nothing; the author keys an area to a level. Em dash.
docs/front-ends/tui-crawler.md:64 disables wandering checks there entirely every encounter on that level disables wandering checks there entirely**, so** every encounter on that level Em dash.
docs/front-ends/tui-crawler.md:64 Both are ordinary AreaSpec and EncounterTable instances**;** nothing about authoring them The guard room is an ordinary AreaSpec and the rival table an ordinary EncounterTable. Nothing about authoring either one "Both" named neither member, and the pairing of two nouns with two types was left to the reader.
docs/front-ends/tui-crawler.md:68 function used in the quickstart**;** only where the choices come from differs function used in the quickstart**.** Only where the choices come from differs Semicolon.
docs/front-ends/tui-crawler.md:68 The scripted party one of each core class, fighter, cleric, thief, and magic-user, kitted out from its own starting gold is what the non-interactive --script mode always builds The scripted party is one of each core class, fighter, cleric, thief, and magic-user, each kitted out from its own starting gold. That's the party the non-interactive --script mode always builds Em-dash pair around a 15-word aside inside the subject.
docs/front-ends/tui-crawler.md:80 The barrow's hook "the temple pays 200 gp for the Jade Idol's return" is part of the adventure The barrow's hook ("the temple pays 200 gp for the Jade Idol's return") is part of the adventure Em-dash pair.
docs/front-ends/tui-crawler.md:86 in the same file an activation clause, two objectives, three rewards, and the marker that says finishing it finishes the adventure in the same file**:** an activation clause, two objectives, three rewards, and the field that makes finishing it finish the adventure Em dash, and a marker that cannot say anything.
docs/front-ends/tui-crawler.md:98 acts the only way anything outside the engine may by executing referee commands, each stamped with what it acted for: source="quest:the-idol" on every command this quest causes acts the only way anything outside the engine may**, by executing referee commands. Each command is stamped** with what it acted for: source="quest:the-idol" on every command the interpreter issues for this quest Em dash, three facts in one sentence, and a quest that cannot issue a command.
docs/front-ends/tui-crawler.md:127 Two details of that output are the whole chapter in miniature Two details of that output are worth reading closely Literary flourish.
docs/front-ends/tui-crawler.md:127 The cache spreads across the party by the ordinary loot rules, so which character walks home with the idol is whatever the split decided — here the fighter, and the cleric is not in the list at all, having died in the vault - and the objective's has_item condition tests whether the party holds the idol, not who The engine spreads the cache across the party by the ordinary loot rules, so which character walks home with the idol is whatever the split produced. Here it's the fighter, and the cleric is not in the list at all, having died in the vault. The objective's has_item condition tests whether the party holds the idol, not which member does A cache does not spread itself and a split does not decide; _distribute_haul in crawl/exploration.py does both. One 60-word sentence with an em-dash pair becomes three.
docs/front-ends/tui-crawler.md:127 each event carries the authored line and the formatter appends whatever beat rides the event it is given each event includes the authored line and the formatter appends the beat on whatever event it's given Metaphorical carry, and text that cannot ride.
docs/front-ends/tui-crawler.md:131 not a return the objective simply does not fire not a return**:** the objective doesn't fire Em dash, minimizer.
docs/front-ends/tui-crawler.md:134 buys a temple healing town commands that are legal here and nowhere later buys a temple healing**. Those** town commands are legal here and nowhere later Em dash.
docs/front-ends/tui-crawler.md:136 - the quest carrying concludes_adventure=True - ends the session in victory , because the quest has concludes_adventure=True, ends the session in victory Metaphorical carry, em-dash pair.
docs/front-ends/tui-crawler.md:138 the loop condition a front end checks true in victory and game_over alike, it answers "has this session ended?" in one read the loop condition a front end checks**. It's** true in victory and game_over alike, so one read tells a front end whether the session has ended Em dash, and a property that cannot answer a question.
docs/front-ends/tui-crawler.md:140 Two beats of authoring discipline fall out of the reward ordering Two authoring habits fall out of the reward ordering "Beat" is the docs' word for authored narrative text. Using it for "point" is a second vocabulary for one word.
docs/front-ends/tui-crawler.md:140 by the time the rewards issue so the temple's 200 gp arrives as real, spendable coin, but no XP will ever be minted from it by the time the rewards issue**.** The temple's 200 gp arrives as real, spendable coin, but it never converts to XP Em dash, and coin that nothing mints into XP.
docs/front-ends/tui-crawler.md:146-150 five "Where next" bullets, each [link] — gloss each [link] - gloss The em dash inside a list item.
docs/front-ends/fastapi-pattern.md:3 behind an HTTP API — the same authored content behind a terminal and a web server, which is the point: osrlib doesn't care what's on the other side behind an HTTP API: the same authored content behind a terminal and a web server. Nothing in osrlib turns on which of the two sits on the other side Em dash, and software that cannot care.
docs/front-ends/fastapi-pattern.md:3 This page teaches the server patterns the example exists to demonstrate: The server patterns the example demonstrates are The page describing itself.
docs/front-ends/fastapi-pattern.md:3 to HTTP statuses — this last one makes the page the home of osrlib.errors to HTTP statuses. The exception hierarchy and the status map below covers osrlib.errors in full Em dash, and a cross-reference in the shape the docs already use.
docs/front-ends/fastapi-pattern.md:5 The example is small — five endpoints in examples/fastapi_crawler/app.py — and every server fragment below is excerpted directly from that file The example is small, five endpoints in examples/fastapi_crawler/app.py, and every server fragment below comes straight out of that file Em-dash pair, and "excerpt" for a snippet.
docs/front-ends/fastapi-pattern.md:5 don't run standalone**; the page's** one self-contained runnable block don't run standalone**. The** one self-contained runnable block Semicolon, and the page referring to itself.
docs/front-ends/fastapi-pattern.md:9 not safe to share across threads — while FastAPI runs plain def endpoints not safe to share across threads, while FastAPI runs plain def endpoints Em dash.
docs/front-ends/fastapi-pattern.md:9 The store resolves that tension by pairing every session with its own lock The store makes that safe by pairing every session with its own lock Stock phrase.
docs/front-ends/fastapi-pattern.md:15 proceed in parallel**;** the outer _store_lock proceed in parallel**.** The outer _store_lock Semicolon.
docs/front-ends/fastapi-pattern.md:15 an async facade would add nothing — the threadpool provides the concurrency an async facade would add nothing. The threadpool provides the concurrency Em dash.
docs/front-ends/fastapi-pattern.md:19 a stamped party document — the JSON envelope party_to_document produces and party_from_document validates — or with a save id a stamped party document (the JSON envelope party_to_document produces and party_from_document validates) or with a save id Em-dash pair.
docs/front-ends/fastapi-pattern.md:31 Two details carry the trust story The trust model rests on two details Metaphorical carry, and a story nothing tells.
docs/front-ends/fastapi-pattern.md:33 no response ever contains it — a client that knows the seed can predict every roll the dungeon will ever make no response contains it**, because** a client with the seed can predict every roll the engine will make Em dash, absolute qualifier, and a dungeon that does not roll.
docs/front-ends/fastapi-pattern.md:33 for reproducible demos and tests**;** even when the client supplies it, it never comes back for reproducible demos and tests**, and** even when the client supplies it, the server never sends it back Semicolon, and "it" that could be the field or the seed with nobody named as the sender.
docs/front-ends/fastapi-pattern.md:38 The barrow is authored content — gated doors, a fetch quest, the works — and content plays only when the Interpreter is registered The barrow is authored content: gated doors, a fetch quest, the works. Nothing plays that content until the Interpreter is registered Em-dash pair, and content that cannot play itself. "Nothing plays them until" is how the gates guide states the same rule.
docs/front-ends/fastapi-pattern.md:38 it happens on both entry paths it happens on both entry paths, the fresh session and the restored one The quantifier named neither member.
docs/front-ends/fastapi-pattern.md:44 a save carries data and a listener is code — the save has a save contains data and a listener is code: the save has Metaphorical carry, em dash.
docs/front-ends/fastapi-pattern.md:50 That pair is the page's own lesson — listeners are code, saves are data — made concrete: forget the second registration Listeners are code and saves are data: forget the second registration The page describing itself, em-dash pair.
docs/front-ends/fastapi-pattern.md:54 returning None for a command_type it has never heard of returning None for a command_type that isn't in the registry Cognition given to a parser.
docs/front-ends/fastapi-pattern.md:60 Three distinct fates for a request Three outcomes for a request Literary register.
docs/front-ends/fastapi-pattern.md:62 a newer client may know commands this server doesn't, and the honest answer is "I don't understand", not a guess a newer client may send commands this server doesn't have, and the server answers that it doesn't understand rather than guessing Cognition given to a client, and "honest" as a stock word.
docs/front-ends/fastapi-pattern.md:64 accepted, the rejections, and the events — filtered to Visibility.PLAYER accepted, the rejections, and the events, filtered to Visibility.PLAYER Em dash.
docs/front-ends/fastapi-pattern.md:68 The split that decides every status code on this page: One split decides every status code in this API: A split does not decide, and the sentence was about the page rather than the API.
docs/front-ends/fastapi-pattern.md:68 the game said no — that's a rules outcome the game says no. That's a rules outcome Em dash, tense.
docs/front-ends/fastapi-pattern.md:70 the caller broke the out-of-fiction contract — sent a malformed document, replayed an incompatible save — and those map The caller broke the out-of-fiction contract by sending a malformed document or replaying an incompatible save, and those map Em-dash pair.
docs/front-ends/fastapi-pattern.md:76-79 four error-type bullets, each [Error][…] — gloss each [Error][…] - gloss The em dash inside a list item.
docs/front-ends/fastapi-pattern.md:79 a front end that replays command logs owns the same mapping decision a front end that replays command logs faces the same mapping decision A front end does not own a decision.
docs/front-ends/fastapi-pattern.md:81 raises stdlib ValueError or TypeError — a bug in the calling code, not a condition to map — and in-fiction refusals, as above, aren't exceptions at all raises stdlib ValueError or TypeError, a bug in the calling code rather than a condition to map. In-fiction refusals, as above, aren't exceptions at all Em-dash pair that pushed the two families into one sentence.
docs/front-ends/fastapi-pattern.md:100 The hierarchy is easy to exercise without a server — this block runs as written You can exercise the hierarchy without a server. This block runs as written The reader decides what is easy; em dash.
docs/front-ends/fastapi-pattern.md:136 an enumerated whitelist — explored cells, public character sheets, … — so unexplored geometry an enumerated whitelist of explored cells, public character sheets, … . Unexplored geometry Em-dash pair around a 25-word list.
docs/front-ends/fastapi-pattern.md:136 A client that renders only what this endpoint returns literally cannot cheat A client that renders only what this endpoint returns cannot cheat Filler.
docs/front-ends/fastapi-pattern.md:138 The player-visible quest and journal events — a quest activated, an objective completed, a beat added — cross in the response's events The player-visible quest and journal events (a quest activated, an objective completed, a beat added) cross in the response's events Em-dash pair.
docs/front-ends/fastapi-pattern.md:138 authored words the player is meant to read, riding an ordinary accepted: false response authored words the player is meant to read, in an ordinary accepted: false response Text does not ride.
docs/front-ends/fastapi-pattern.md:142 everything the wire withholds — the master seed, referee state, the full logs — so the example never sends one anywhere everything the wire withholds: the master seed, referee state, and the full logs. The example never sends one anywhere. Em-dash pair.
docs/front-ends/fastapi-pattern.md:148 re-registers the Interpreter — the one listener this server runs, shown in the served content section — and hands back re-registers the Interpreter (the one listener this server runs, shown in the served content section), and hands back Em-dash pair.
docs/front-ends/fastapi-pattern.md:148 a deliberate simplification — swapping in a database changes nothing a deliberate simplification, and swapping in a database changes nothing Em dash.
docs/front-ends/fastapi-pattern.md:152-155 four "Where next" bullets, each [link] — gloss each [link] - gloss The em dash inside a list item.
docs/reference/rng-streams.md:5 the identical sequence of draws — and it produces that sequence the identical sequence of draws, and it produces that sequence Em dash.
docs/reference/rng-streams.md:15 a key has one spelling in the library and a mistyped one cannot fork a stream of its own a key has one spelling in the library. Draw with a member rather than a string you type out: RngStreams.get forks a stream of its own for any string, so a mistyped key draws plausible numbers from that stream instead of raising. The claim was false. StreamName's docstring in src/osrlib/core/rng.py: "A mistyped name raises no error: get forks 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:19 Code that uses the kernel functions directly — standalone, outside of a running game — passes Code that uses the kernel functions directly (standalone, outside of a running game) passes Em-dash pair. The paragraph also splits in two where the topic turns.
docs/reference/rng-streams.md:21 it owns an RngStreams container built from the session's master seed it builds an RngStreams container from the session's master seed core/rng.py's module docstring: a GameSession "builds its own container from the seed you give it".
docs/reference/rng-streams.md:25 what it governs**; the sections that follow give more detail on each** what it governs**.** The page announcing its own sections.
docs/reference/rng-streams.md:123 freeform adjudication — dice commanded through the seeded session freeform adjudication: dice commanded through the seeded session Em dash.
docs/front-ends/tui-crawler.md:48 The view drops a quest once it's finished, and the journal is where its record stays A finished quest is not in the projection, and its record is the journal Correction after review: a view does not drop anything. The sentence before it already says _status walks the active quests only, so the fact is that a finished quest is not there.
docs/front-ends/tui-crawler.md:15 the authored refusal text when the gate has one the authored refusal text when a gate has one Correction after review: no gate had been named for "the gate" to point at.
docs/guides/ruleset-options.md:54 and measures the space the party stands in, the widest square of unbroken floor around them and measures the widest square of unbroken floor around the party Correction after review: "the space the party stands in" opened the same sentence pair two sentences earlier, so the second occurrence now says what was measured.
docs/front-ends/fastapi-pattern.md:31 The trust model rests on two details: Two details of that handler matter: Correction after review: "trust model" is vocabulary the docs do not use. The page and the views guide say "never trust the client", and the two bullets name themselves.
docs/front-ends/fastapi-pattern.md:33 no response contains it no response ever contains it Correction after review: the absolute is the security claim, so it goes back.

Open 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 is fastapi-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.py executes 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.md says Markdown prose is never hard-wrapped, and docs/reference/rng-streams.md is 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, which AGENTS.md rules 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.

  • MacGuffin - docs/front-ends/tui-crawler.md:52.
  • beat, used on pages a reader can land on directly without meeting the index's vocabulary table - docs/front-ends/tui-crawler.md:48, docs/front-ends/fastapi-pattern.md:138.
  • seam - docs/guides/authoring-custom-content.md:111 (the heading), :552, :554.
  • marching order - docs/guides/gates-triggers-quests.md:29.
  • drop pile - docs/guides/authoring-custom-content.md:445; docs/guides/ruleset-options.md:46.
  • name level - docs/guides/authoring-custom-content.md:61.
  • stature prose - docs/guides/authoring-custom-content.md:31.
  • facet, in "every weapon and gear facet" - docs/guides/ruleset-options.md:13, :30.
  • the unguarded-treasure band - docs/getting-started/building-an-adventure.md:57.
  • treasure-weight rows - 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 on main as "the blocks whose display beat the players never see". The literal sense is live in the code as well, where _spread_coins(carriers, …) in src/osrlib/crawl/exploration.py means 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.md calls the load_classes rebinding "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:140 also 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:58 said "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:54 used "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:108 reads "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, and docs/adaptations.md still 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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant