Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Three committed contributor docs carry the parser's normative rules and their re

**Counting claims.** A bare count in prose is either an assertion or a liability, keyed by who observes its staleness: asserted counts (a test holds the number) fail CI at change time — the useful kind; dated snapshots ("51 sites at spec time") cannot go stale; standing present-tense prose counts are the forbidden class — promote to an assertion, add a date, or state the invariant and let a test count. After changing how many times something runs, sweep for counts, not for the thing's name.

**Release-log claims.** Quantified or universal behavior claims in release bullets must come from the snapshot's diff since the last release, be verified against rules.md examples, or -- for a view the snapshot cannot see -- carry a recompute recipe stored with the design entry the bullet cites; never write one from memory. `uv run python tools/differential/snapshot.py --since v<last release>` prints every corpus name the release moved, grouped by changed field; for a release tagged before the snapshot existed (2.4.0 and earlier), `compare.py --baseline <version>` prints the same report against the PyPI wheel, with the Latin-only count. The snapshot records the seven role fields, ambiguity kinds and `initials()` for every name, so an initials count is read off it directly. `corpus_cldr.jsonl`'s fictional renderings are in it: count them out of a release figure (both tools print how many moved names only that file holds), or say the figure includes them. `capitalized()` and any other render view stay invisible to the snapshot (decisions.md#R4, #R3), and for those the first two sources cannot reach a claim: the snapshot is byte-identical across the change, and an example line witnesses an output without counting anything. A recipe names the corpus files, the policy sweep, and -- the part that is easy to omit and fatal -- THE COMPARATOR, which must be something the shipped tree is not: #408's first recipe said to compare `initials()` against a folded-first partition, which is what `initials()` now IS, so it reproduced 0 where the bullet claimed 660 and was the only stated provenance for the number. Run the recipe as written before shipping the bullet. Cross-version numbers (a released wheel, the pre-change tree) are dated snapshots under Counting claims, since nothing in the repository re-runs them. The same standard binds decisions entries and PR bodies: a claim that a change restores the released reading is measured over the whole moved population against the wheel, never spot-checked (#625 claimed its 774 moves landed on the 1.4.0 and 2.3.0 readings from three names; measured, the tree matched 2.3.0 on 0 of 258 moved texts, master on 152), and a population size is re-counted from its recipe, never copied from another entry (the same entry carried #624's 137,810 for a grid of 395,148). Code comments citing rule IDs follow the excerpt discipline, checked by tests/v2/test_doc_citations.py: a rule's statement and its `Accepted:` clauses are quotable, its example lines are not; `rules.md#H` names the H section, whose Background is quotable; a decisions.md citation may paraphrase, but what it quotes must be verbatim; and a reference with no quote must still name something that exists. The check's reach is a quote within four words of the ID or chained to one that is: a quote further off reads exactly like a name written in double quotes, so it is NOT checked, and the second review of #632 found 14 such quotes stale by hand. Keep a quote beside its ID. Quotes of AGENTS.md itself are not checked at all.
**Release-log claims.** Quantified or universal behavior claims in release bullets must come from the snapshot's diff since the last release, be verified against rules.md examples, or -- for a view the snapshot cannot see -- carry a recompute recipe stored with the design entry the bullet cites; never write one from memory. `uv run python tools/differential/snapshot.py --since v<last release>` prints every corpus name the release moved, grouped by changed field; v2.4.1 is the first tag carrying a snapshot, and for an older release `compare.py --baseline <version>` prints the same report against the PyPI wheel, closing with the entries compared and how many moved names are Latin-only. Both say how many moved names only `corpus_cldr.jsonl` holds. The snapshot records the seven role fields, ambiguity kinds and `initials()` for every name, so an initials count is read off it directly. `corpus_cldr.jsonl`'s fictional renderings are in it: count them out of a release figure (both tools print how many moved names only that file holds), or say the figure includes them. `capitalized()` and any other render view stay invisible to the snapshot (decisions.md#R4, #R3), and for those the first two sources cannot reach a claim: the snapshot is byte-identical across the change, and an example line witnesses an output without counting anything. A recipe names the corpus files, the policy sweep, and -- the part that is easy to omit and fatal -- THE COMPARATOR, which must be something the shipped tree is not: #408's first recipe said to compare `initials()` against a folded-first partition, which is what `initials()` now IS, so it reproduced 0 where the bullet claimed 660 and was the only stated provenance for the number. Run the recipe as written before shipping the bullet. Cross-version numbers (a released wheel, the pre-change tree) are dated snapshots under Counting claims, since nothing in the repository re-runs them. The same standard binds decisions entries and PR bodies: a claim that a change restores the released reading is measured over the whole moved population against the wheel, never spot-checked (#625 claimed its 774 moves landed on the 1.4.0 and 2.3.0 readings from three names; measured, the tree matched 2.3.0 on 0 of 258 moved texts, master on 152), and a population size is re-counted from its recipe, never copied from another entry (the same entry carried #624's 137,810 for a grid of 395,148). Code comments citing rule IDs follow the excerpt discipline, checked by tests/v2/test_doc_citations.py: a rule's statement and its `Accepted:` clauses are quotable, its example lines are not; `rules.md#H` names the H section, whose Background is quotable; a decisions.md citation may paraphrase, but what it quotes must be verbatim; and a reference with no quote must still name something that exists. The check's reach is a quote within four words of the ID or chained to one that is: a quote further off reads exactly like a name written in double quotes, so it is NOT checked, and the second review of #632 found 14 such quotes stale by hand. Keep a quote beside its ID. Quotes of AGENTS.md itself are not checked at all.

**Writing the user docs (docs/*.rst) has its own AGENTS.md too.** `docs/AGENTS.md` carries the style the docs are written in — tables as indexes, subheadings per task, measured claims, recipe doctests — distilled from PR #588. It loads the same way as the docs/design/ one below; if your tool does not do nested discovery, read it before editing a `.rst` file under docs/.

Expand Down Expand Up @@ -116,10 +116,8 @@ uv run sphinx-build -b html docs dist/docs
# first — pyproject floats >=0.4 so fresh installs get the newest namedivider, but
# CI's ja-extra job installs from uv.lock and only tests what the lock pins
# 1. Read what the release moved: `uv run python tools/differential/snapshot.py
# --since v<last release>`, or, while the last tag predates the snapshot
# (2.4.0), `uv run python tools/differential/compare.py --baseline <last
# release>`. Both print every corpus name that reads differently, grouped
# by changed field. That report is the source for the release notes'
# --since v<last release>`. It prints every corpus name that reads
# differently, grouped by changed field. That report is the source for the release notes'
# behavior claims (see Release-log claims above); a move nobody can
# account for is a finding to settle before the log is drafted.
# 2. Clear PRE_RELEASE in nameparser/_version.py — it carries 'dev' through the
Expand Down
4 changes: 4 additions & 0 deletions docs/release_log.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Release Log
===========
* 2.5.0 - Unreleased

nameparser 2.5 is under development.

* 2.4.1 - October 13, 2026

nameparser 2.4.1 fixes two readings: an accented abbreviation written in decomposed form, and a comma inside a nickname.
Expand Down
4 changes: 2 additions & 2 deletions nameparser/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
#: cannot carry the dev marker, so `VERSION >= (2, 5, 0)` is already
#: true here while 2.5.0 is unreleased. Compare `__version__` instead
#: where that distinction matters.
VERSION = (2, 4, 1)
VERSION = (2, 5, 0)
#: PEP 440 pre-release/dev segment appended to the numeric version, or
#: "" for a final release. Joined WITHOUT a dot ("2.0.0rc1", not
#: "2.0.0.rc1"); setuptools reads __version__ as the package version.
#:
#: "dev" through the cycle, cleared at release. It normalizes to
#: 2.5.0.dev0, which sorts above 2.4.0 and BELOW 2.5.0, so an install
#: from master can never masquerade as the release it precedes.
PRE_RELEASE = ""
PRE_RELEASE = "dev"
__version__ = ".".join(map(str, VERSION)) + PRE_RELEASE
2 changes: 1 addition & 1 deletion tools/differential/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from typing import NamedTuple

HERE = Path(__file__).resolve().parent
DEFAULT_BASELINE = "2.4.0"
DEFAULT_BASELINE = "2.4.1"
REPO_ROOT = HERE.parents[1]


Expand Down
Loading