Conversation
Promote the gateway-configured AsyncOpenAI client builder out of retriever into a new shared package, executing the ADR 0028 follow-up. - New packages/llm (dist evermore-llm, import evermore_llm), mirroring packages/auth: hatchling, py.typed, Apache-2.0 headers, ruff/mypy/pytest. - build_gateway_client moves there with its body unchanged. A structural GatewaySettings Protocol is the settings seam, so the package imports nothing from any service (ADR 0001). - retriever consumes it via a path-editable [tool.uv.sources] entry and drops its own copy. GatewayScope now has one definition, in the package. - Tests split: 6 pure-builder tests move to packages/llm/tests driven by a Protocol stub; the 3 that need the real retriever.config.Settings stay. - retriever.config imports GatewayScope under TYPE_CHECKING, keeping the openai SDK out of the settings import chain. Gates: test and lint both exit 0. retriever 379 passed at 89.43% coverage, packages/llm 6 passed, stacker build and svelte-check clean, bandit clean.
The retriever Dockerfile builds from the repo root and COPYs each packages/* path source named in [tool.uv.sources]. Adding evermore-llm as a path source without a matching COPY left /app/packages/llm absent, so uv sync --frozen failed with 'Distribution not found at: file:///app/packages/llm' and the container-build (retriever) CI job exited 2.
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Executes the ADR 0028 follow-up: promotes
build_gateway_clientout of retriever into a new shared package so petdata and biowriter can import one helper rather than copying it.Closes #93
What changed
packages/llm(distevermore-llm, importevermore_llm), mirroringpackages/auth: hatchling,py.typed, Apache-2.0 SPDX headers, same ruff/mypy/pytest config.build_gateway_clientmoves there with its body unchanged. A structuralGatewaySettingsProtocol is the settings seam, so the package imports nothing from any service (ADR 0001).retriever.config.Settingssatisfies it structurally with no runtime change.[tool.uv.sources]entry and drops its own copy.GatewayScopenow has a single definition, in the package.packages/llm/tests, driven by a Protocol-conforming stub; the 3 that need the realretriever.config.Settingsstay in retriever (moving them would import a service into a package).retriever.configimportsGatewayScopeunderTYPE_CHECKING, keeping theopenaiSDK out of the settings import chain.import retriever.configno longer loadsopenai.Pipeline phases
base_shaancestral, body digest matches). Design pass skipped, complexity score 2.TYPE_CHECKINGimport move); delta re-reviewed APPROVE.Test results
(cd services/retriever && uv sync && uv run python -m pytest tests/ --ignore=tests/integration) && (cd apps/stacker && npm ci && npm run build)(cd services/retriever && ruff check + ruff format --check + mypy --strict) && (cd services/petdata && same + bandit) && (cd apps/stacker && npm run check)cd packages/llm && ruff check + ruff format --check + mypy src/ + pytestEval scores
No evals configured in this repo.
Verification beyond the gates
Mutation replay against the split suite (scratch copy; worktree restored and checksum-verified):
default_headersset unconditionally..._omits_auth_header_when_token_absentapi_key=token(placeholder dropped)..._uses_configured_header_namescope is Noneinverted..._uses_scoped_chat_tokenBoth branches of the token logic stay covered across the split.
On acceptance criterion 3
"petdata and biowriter import the same helper" is satisfied by construction, not as current fact: petdata has no
openaidependency and biowriter is not scaffolded, so neither consumes the gateway yet. What this PR delivers is a single shared home with no copy and no cross-service-import path remaining. The ADR and package README state this as forward-looking rather than claiming consumers that do not exist.Accepted risks and deferrals
GatewaySettingsis structural, so any duck-typed object now type-checks whereretriever.config.Settingswas previously required, andllm_gateway_base_urlreachesAsyncOpenAI(base_url=...)with no scheme or host check while the real bearer is attached. Runtime enforcement is unchanged (the old annotation wasTYPE_CHECKING-only too, so nothing validated at runtime before either). Not reachable today: retriever's call sites passget_settings(). Accepted for this no-behavior-change extraction; adding a scheme or allowlist guard in the builder is a design change worth its own issue.packages/**fans out to the retriever and petdata jobs, but those runworking-directory: services/<svc>and invoke only that service's pytest. This matches the existing gap forpackages/authandpackages/schema; a standalone packages CI job was deliberately deferred rather than adding a one-package job here.packages/llm/uv.lockresolvesopenai2.48 while retriever runs 2.26. The package's credential-placement assertions test against SDK internals at a version production does not run.docs/security/coverage-ledger.mdline 183 asserts its row set equalsgit ls-files apps/stacker packagesexactly. That count invariant is now stale, and 6 of the 7 newpackages/llm/files have no ledger row. This PR only re-pointed the one existing row's path.packages/**CI job, no pydantic settings mixin, no move ofgateway_token_for/llm_gateway_base_urlinto the package.