core/docs: a failed create() leaves no manual behind; fixtures load plugins first
Into dev, ahead of the dev → main release (#111) — cubic's four findings on that PR.
create() left a sibling manual behind on failure
It rolled back the protocols it created but not the manuals it registered: when one manual of a batch fails after a sibling has saved, the sibling stayed in the tool repository — which may be caller-supplied and shared. The manuals this attempt added are now deregistered before the owned protocols are closed (deregistration needs them open). Only this attempt's: a manual already present before — whose re-registration fails as a duplicate without raising — is left alone. The manual-name rule lives in one helper (_sanitize_manual_name), so create() computes the same names register_manual will use.
The registry-isolating fixtures could silently unregister every plugin
Both fixtures swapped the class-level dicts before plugins had loaded. Plugins load lazily on the first create() of the session and register into whatever dict holds the attribute at that moment — so if the session's first create() ran inside an isolated test, every shared instance landed in the throwaway dict and was lost on restore. Both fixtures now call ensure_plugins_initialized() first.
Extractor: an inline code span crossing a newline was linked inside
The scanner ran per line and reset at each. Everything between fences is now handed to it as one segment.
Docs: no "pooled HTTP session"
utcp-http and utcp-gql open a session per request; the only shared state is the OAuth token cache. README, interface docstring and registry docstring corrected.
Tests
A manual registered by a failed create() is removed from the caller's repository; a manual present before the attempt survives it; the multi-line span is unit-checked. Mutation-checked: dropping the rollback fails exactly the two rollback tests. Core 56/56.
🤖 Generated with Claude Code
Summary by cubic
Failed UtcpClient.create() previously rolled back its owned protocols but left manuals registered during the attempt; it now removes exactly those manuals before closing protocols. Rollback remains safe when cancelled, so shared repositories keep pre-existing or concurrently registered manuals and created protocols are still closed.
Bug Fixes
- Successful manual names are recorded during registration instead of inferred from repository state.
- Duplicate registrations are never removed during rollback.
- Registry-isolating fixtures initialize plugins before replacing class-level registries.
- The extractor keeps inline code spanning newlines unlinked.
Documentation
utcp-httpandutcp-gqlnow describe per-request sessions with shared OAuth token caches.