Skip to content

Docstrings: core combat - #92

Merged
mmacy merged 3 commits into
mainfrom
docs/api-ref-core-combat
Sep 14, 2026
Merged

Docstrings: core combat#92
mmacy merged 3 commits into
mainfrom
docs/api-ref-core-combat

Conversation

@mmacy

@mmacy mmacy commented Sep 14, 2026

Copy link
Copy Markdown
Owner

A reader who has only the published reference can now run a fight with osrlib.core.combat: pick the function for the job, build the AttackContext and the RngStream it needs, read the fields of what comes back, and know which function takes that output next. Every result model field and enum member documents itself on its own row of the page, and every function a reader would call has an example that runs under the docs harness with a fixed seed.

Several docstrings disagreed with the code, and I corrected them to what the code does. attack_facet and damage_roll said a gear item with no fighting stats is the only attack with no combat facet; a magic item whose template names no base weapon is another, and that is most of the magic item catalog. attack_roll and AttackRollResult.auto described the automatic hit as one the rules grant without a roll, which left a reader nothing to act on, so they now name the condition, a defender whose armour_class is None, and the two monsters that have it. drain_monster_hd claimed a floor of 1 on a d8, which is no floor at all, and said a monster drained below 1 Hit Die dies when the kill triggers at exactly 1; it now states the real floor, that hit points clamp at 1, and lists the events each path yields. deal_damage omitted the equipment event that ends a destructive kill and the revive entry that a regenerating monster needs before it can die permanently. resolve_breath did not mention that an absorbed target takes no save. AttackContext.distance_feet said an unstated distance means melee, which holds for a melee weapon but not for a missile-only one. check_morale and MoraleTracker.check gave the score as 2 to 12 when the code accepts any integer and treats anything at or below 2 and at or above 12 as exempt. MoraleResult used ML before the page defined it.

Two things about how the page renders. I indented the continuation lines of every multi-line Returns: body, because the Google-style parser in mkdocstrings reads each unindented line in that section as a separate return value and was rendering a two-line description as two table rows with the type repeated. I also put every field and enum-member description on the member itself rather than in a class-level Attributes: section, because mkdocstrings renders each field again below the class and an Attributes: section leaves those rows bare. Both patterns appear in other modules, which I left alone because they are outside this batch.

The code comments went through the same register pass as the docstrings, with their facts unchanged.

No example is no-run, and nothing is left undocumented on purpose. The module's runtime code is byte-identical: I compared the syntax trees with every docstring stripped.

uv run ruff format --check && uv run ruff check && uv run pyright && uv run pytest -q && uv run mkdocs build --strict passes.

https://claude.ai/code/session_01GL26QnA6dCrvUc3WmhzFSa

Every public member of osrlib.core.combat now answers what it does, why you'd
call it, what you need first, what to call next, what to use instead, and when
not to use it. The result models, the enums, and the two constants gained
attribute documentation, so the reference no longer renders their fields as bare
names, and every function a reader would call has a runnable example.

Continuation lines in Returns sections are indented, because mkdocstrings' Google
parser treats each unindented line as a separate return value and was rendering
one description as several table rows.

Docstrings only. The module's code is byte-identical apart from the docstrings.

Claude-Session: https://claude.ai/code/session_01GL26QnA6dCrvUc3WmhzFSa
mkdocstrings renders each pydantic field and enum member as its own member below
the class, and a class-level Attributes: section left those rows bare. Every
public field and enum member now has an attribute docstring on the line after it,
and the Attributes: sections that would duplicate them are gone.

The code comments get the same register as the docstrings: no em dashes, no
decision-log vocabulary, one idea per sentence. The facts are unchanged.

Docstrings and comments only. The module's code is byte-identical.

Claude-Session: https://claude.ai/code/session_01GL26QnA6dCrvUc3WmhzFSa
Thirteen claims traced back to the code and restated. attack_facet and
damage_roll now name the magic item with no base weapon, which is most of the
catalog. The automatic hit is described by what produces it, a defender whose
armour_class is None. drain_monster_hd states the real hit point floor of 1, that
the kill triggers at exactly 1 Hit Die, and which events each path yields.
deal_damage names the equipment event and the revive entry that permanent death
needs. resolve_breath names the absorbed path that takes no save. AttackContext
states what an unstated distance means for a missile-only weapon. check_morale
and MoraleTracker.check say what the code does with a score outside 2 to 12.
resolve_attack's draw accounting covers the paths that cost one draw and the
extra dice under striking. The morale_modifier example draws from the combat
stream like every other example.

Docstrings only. The module's code is byte-identical.

Claude-Session: https://claude.ai/code/session_01GL26QnA6dCrvUc3WmhzFSa
@mmacy
mmacy merged commit e719ed5 into main Sep 14, 2026
5 checks passed
@mmacy
mmacy deleted the docs/api-ref-core-combat branch September 14, 2026 06:00
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