core/docs: a failed create() leaves no manual behind; fixtures load plugins first

Merged
H3
2mo ago
+248-57

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-http and utcp-gql now describe per-request sessions with shared OAuth token caches.