Skip to content

refactor: one word per concept in the configuration chain - #400

Merged
thodson-usgs merged 6 commits into
DOI-USGS:mainfrom
thodson-usgs:chore/configuration-vocabulary
Sep 2, 2026
Merged

refactor: one word per concept in the configuration chain#400
thodson-usgs merged 6 commits into
DOI-USGS:mainfrom
thodson-usgs:chore/configuration-vocabulary

Conversation

@thodson-usgs

@thodson-usgs thodson-usgs commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Why

Follow-up to #396, which was documentation-only: this is the code half, plus a
scan of every CONTEXT.md term against the package.

_resolve returned (raw, source, tier). The glossary's source — the
ordered category a value came from — was the third element; the second was
the origin label, the exact origin such as $API_USGS_RETRIES or a path
to the config file. One word, two grains, in one signature. And tier was our
own vocabulary misapplied: ADR 0010 uses tier for the scope axis, and ADR
0011's rungs are ladder positions.

#405 (merged) supplies the rule that licenses touching identifiers: terms we
invented take one spelling everywhere, identifiers included. This PR is that
rule applied to the configuration chain.

What changed

_resolve now returns (raw, label, source):

concept was is
source — the ordered category (block / environment / file / built-in) tier source
origin label — the exact origin, printed by show_configuration() source label
the helpers that build origin labels _source_label, _env_source_label, BaseConfiguration._source _origin_label, _env_label, ._label

label is not a coinage: _show_adapter_overrides already used it, and
_parse_int documented its parameter as "Human-readable origin". Prose
follows the code: the show_configuration docstring and the user guide said
"source" where they describe an origin label.

Behaviour unchanged, mechanically

Applying the rename to main's AST — docstrings stripped — reproduces this
branch's AST exactly for both renamed modules, and the other touched files are
identical in code terms. No string constant changed except two docstrings;
show_configuration()'s output is byte-identical. mypy --strict is clean,
and all 1139 offline tests pass.

Stripping docstrings is also that check's blind spot, and it bit: the rename
left "a label label" in _resolve's docstring, wrote "source" in three places
where the glossary means scope, and missed tier in
waterdata/configuration.py and four test docstrings. The follow-up commits
fix the wording; each message says what it fixed.

Commits

  1. 17f9cdc — the rename.
  2. 934d4ed — the wording the rename got wrong.
  3. b242704..._the_tiers_below..._the_rungs_below, with ADR 0011's
    compliance citation annotated the way ADR 0008 annotated the wateruse
    rename.
  4. f5f29ee — two pre-existing docstrings that called a rung a scope.
  5. b10fb35 — merge of main after docs: separate the terms we own from the terms the services own #405 landed. One conflict, in CONTEXT.md's
    Origin label entry: kept docs: separate the terms we own from the terms the services own #405's Core terms. marker and first
    sentence, then this branch's statement that the code now matches.
  6. 590a683 — one docstring that said "sources below" for what are rungs 4
    and 5.

Raised, not fixed — needs your call

The scan cross-checked all 40 CONTEXT.md terms; everything audits clean (no
tier or rung survives in the package) except one thing: the package says
service in places where the glossary's term is adapter — eleven sites
in the two configuration modules, including "<service default>", which
show_configuration() prints, and base_url's docstring ("the service
passes its own") in a function whose parameter is adapter.

Left alone deliberately: some may be legitimate — a base URL arguably is the
service's, even though the setting is adapter-scoped — so each site needs its
own judgement, and the printed one changes user-visible output, which has no
place in a PR whose whole claim is that behaviour is unchanged.

`_resolve` returned `(raw, source, tier)`: `source` held the exact origin
(`$API_USGS_RETRIES`, a path to the config file) and `tier` held the
ordered category CONTEXT.md calls the source. One word, two grains, in
one signature.

It now returns `(raw, label, source)`. The category takes the glossary's
name, and the origin string takes `label` -- the name
`_show_adapter_overrides` already used for it, and the one `_parse_int`
documented as "Human-readable origin". Renamed to match: `_source_label`
to `_origin_label`, `_env_source_label` to `_env_label`, and
`BaseConfiguration._source` to `._label`; all three build an origin
label, none names a source.

The rename is mechanical: applied to the parent's AST with docstrings
stripped, it reproduces this commit's AST exactly, for both modules.
`show_configuration()`'s output stays byte-identical. The
`show_configuration` docstring and the user guide said "source" for what
is an origin label; both now say origin. CONTEXT.md drops the paragraph
recording that the code spelled the pair backwards.

Left for the pull request: the package still says "service" in places
where the glossary's term is "adapter", including the printed
`"<service default>"`. Each site needs its own judgement, and that one
changes user-visible output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD
@thodson-usgs
thodson-usgs force-pushed the chore/configuration-vocabulary branch from 644262d to ce65415 Compare September 1, 2026 16:44
The rename proved behaviour unchanged by comparing ASTs with docstrings
stripped -- silent, that is, about exactly the text a rename most easily
breaks. Reading the diff found three kinds of damage:

Breakage: `\bsource\b` had matched inside "source label", leaving "a
label label" in `_resolve`'s summary and Returns section, and the
summary still said "tier".

Category errors: three sentences got "source" where the glossary means
scope -- the file's adapter-scoped and package-wide lookups are two
scopes within one source, not two sources.

Leftovers: `tier` survived in `waterdata/configuration.py` and in four
test docstrings the rename never covered; `_configuration_core` counted
"three sources" where its module docstring numbers four, and dropped a
preposition; and `WaterdataConfiguration` said "this service" and "every
other adapter" for one thing in one sentence -- the scope is the
adapter.

Prose only; the AST comparison against upstream/main still holds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD
The glossary now defines the precedence ladder and its rungs (PR DOI-USGS#405),
which makes the one identifier still saying "tiers" for ladder positions
a core-term misspelling rather than a stray. The file's own comments
already say rung. ADR 0011's compliance citation is annotated the way
ADR 0008 annotated the wateruse rename, so the reference stays true.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD
Two docstrings called a rung a scope. The module docstring said ADR 0011
splits three of the four sources "into the scopes they contain", but the
block source's split -- a passed instance vs a profile loaded from the
file -- is the same scope either way. It now counts the ladder plainly:
seven rungs over four sources, three of which hold two apiece. And the
renamed test's docstring said a profile "replaces keys, never whole
sources", where what it does not replace wholesale is the rung.

Both wordings predate the glossary's scope/rung split; this PR owes them
one word per concept.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD
thodson-usgs added a commit that referenced this pull request Sep 1, 2026
* docs: separate the terms we own from the terms the services own

Review of #396 found `CONTEXT.md` using *tier* in its own prose without
defining it. The word was there before that record was written; recording
each explanation once made the gap visible rather than creating it. Fixing
the one word would have left the reason it got there.

The glossary is one flat list, and every place the code disagrees with it is
filed under *Known legacy names* -- a heading whose framing is that the
disagreement is debt. For most of the glossary that is right. For a few terms
it is wrong, and being wrong about those has produced the same argument
repeatedly: may a docstring say *site*, may `service=` name a collection, is
prose about NWIS bound by a word taken from the Water Data API.

The two sets differ in who has authority over them.

*chunk*, *page*, *fan-out*, *plan*, *interruption*, *dialect*, *leaf* appear in
no USGS API's vocabulary. They were invented here for machinery this package
owns. Nothing outside constrains them, so spelling one of them three ways --
the resolution chain's layers have been a source, a tier and a rung -- is an
inconsistency that can be removed by deciding, and should be.

*monitoring location* and *collection* are not like that. The services name
those things and disagree: `site_no` in NWIS, `Station` in WQP,
`monitoring_location_id` in Water Data, a `sites` collection in NGWMN. No
decision here reconciles them. A caller who read WQP's documentation looks for
`Station`; an adapter that renamed it would be harder to use, and the parameter
is public surface besides.

One rule over both forces a choice between losing the glossary, and with it the
vocabulary that lets transport and the OGC engine be written once, or enforcing
it onto every adapter's public surface.

So: ADR 0013 records the split. Core terms take one spelling everywhere,
identifiers included, and a second spelling is a defect. Domain terms fix one
word for prose while each adapter keeps its service's spelling in its
parameters -- which is the adapter doing its job, not debt.

`CONTEXT.md` follows. The preamble names the two kinds. *Monitoring location*
and *collection* carry their per-service spellings in their own entries rather
than as exceptions at the end. *Known legacy names* keeps only core-term
spellings. And the package-wide **source** is called that, in the sentence that
had called it a tier.

This also settles what #400 is. Renaming the configuration chain's `tier` to
`source` looked discretionary while the glossary bound only prose; the chain is
core machinery, so one spelling binds its identifiers too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD

* docs: read tier and rung as the records wrote them

The glossary's Source entry claimed ADR 0010 calls a source a tier and
ADR 0011 a rung. Neither is true. ADR 0009 and 0010 already say source
-- source-major precedence is 0010's own phrase. 0010's tier names a
different axis, the scope: the top-level tier that survives, the
deferred gateway tier. 0011's rung is one position of its seven-rung
ladder, where sources and scopes interleave. The code's tier-for-source
identifiers misapplied 0010's scope word, and the glossary projected
that confusion back onto the records; ADR 0013's standing example
repeated it.

Correcting the history also surfaced what was missing: Scope had no
entry, though ADR 0010's whole subject is scoping, and the axis mixup
is exactly the confusion a definition prevents. The Adapter-scoped
setting entry carried the same error in the other direction -- "does
not replace the package-wide source" named a scope level a source --
so the sentence now names the value rather than either axis.

Also from this pass: portal is defined as the human-facing site
fronting a service rather than left as an undefined near-synonym
(CONTRIBUTING now says service where it meant the module split);
the stall-timeout bullet no longer invites new prose to use either
spelling; Facade is grounded in the design pattern it is named for;
and the Source entry points NLDI's data_source at the domain-term
rule. The preamble's define-before-use rule is restated without the
ordering claim two mutually-referencing axes cannot satisfy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD

* docs: give the precedence ladder and its rungs an entry

ADR 0011, the user guide, and the configuration tests' comments all
say rung; a word in use across three venues has earned its definition.
With rung defined, the user guide's one "tiers below" was a second
spelling of it and now reads "rungs below".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD

* docs: drop the portal entry; group by service in the interface view

Defining *portal* as the human-facing site created three problems it did
not solve. The word already carries three unrelated senses here: WQP's
proper name (the Water Quality Portal), anyio's blocking portal in
transport/fanout.py, and the user guide's page title for a table of
websites. The new definition made five existing wqp.py docstrings
violations -- "the portal serves the legacy and WQX3 interfaces from one
root" is about the service, and reads naturally precisely because that
service is named Portal. A glossary entry that manufactures violations
in correct prose is not carrying its weight.

The CONTRIBUTING change it came with stands on its own: modules are
grouped by service, which is what the Services section enumerates, and
"data portal" maps to neither the modules nor the portal table cleanly.
The architecture interface view said the same thing and now matches.
ADR 0001 keeps its wording, being accepted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD

* docs: state ADR 0013's split where agents actually read it

AGENTS.md's first bullet said "when a term there conflicts with a name
in the code, the term wins" -- the rule in its pre-0013 absolute form.
That sentence is load-bearing: it is the entry point every agent and
contributor reads before writing anything, and read literally it
licenses renaming an adapter's public parameters to match the glossary.
It did exactly that here, producing a rename that had to be reverted.

ADR 0013 splits the rule, so the bullet now does too: a core term binds
identifiers, a domain term binds prose only and each adapter keeps its
service's spelling. The two examples are the ones reviewers keep
asking about.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JAEQqs7XzQHGQQi2KakuXD

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
One conflict, in CONTEXT.md's **Origin label** entry, which DOI-USGS#405 and this
branch both rewrote. Kept both, as this PR's description proposed: DOI-USGS#405's
`*Core terms.*` marker and its first sentence, which ADR 0013 now requires
of every entry, followed by this branch's statement that the code matches.
DOI-USGS#405's sentence calling the `tier`/`source` identifiers "a defect to
correct" is dropped -- this branch corrects it.

DOI-USGS#405's additive **Precedence ladder** entry is kept verbatim.

The rest merged clean. DOI-USGS#405 had already changed the user guide's line 319
from *tiers* to *rungs*, which does not overlap this branch's line 437.
`BaseConfiguration.load` said a selected profile inherits the adapter's
default profile and the package-wide keys "from the sources below". Both
sit inside the file source -- rungs 4 and 5 -- so the sentence names
positions, which is what CONTEXT.md reserves *rung* for. The user guide
has said "the rungs below" since DOI-USGS#405; the two now agree.

Also joins the "apiece." the ladder sentence left orphaned on its own
line.
@thodson-usgs
thodson-usgs force-pushed the chore/configuration-vocabulary branch from cd6b267 to 590a683 Compare September 2, 2026 01:58
@thodson-usgs
thodson-usgs marked this pull request as ready for review September 2, 2026 14:14
@thodson-usgs
thodson-usgs merged commit bb17656 into DOI-USGS:main Sep 2, 2026
11 checks passed
@thodson-usgs
thodson-usgs deleted the chore/configuration-vocabulary branch September 2, 2026 14:14
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