fix: resolve ContextProvider values live so late set_context propagates#216
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ContextProvider-backed factory params now go into a dedicated context_kwargs bucket and are resolved on every resolve (value lookup + default/None/raise + override handling deferred to resolve time), instead of baking the value-absent decision into the per-container compiled-kwargs memo at first resolve. A late set_context on any container is therefore picked up across scopes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With ContextProvider values resolved live, the compiled-kwargs memo never goes stale, so set_context no longer needs to invalidate it. Removes CacheRegistry.invalidate_compiled_kwargs and its sole caller in set_context. Adds a direct test for the by-type self-reference guard (factory.py:115), which was previously only covered incidentally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clarify that late context is picked up live by subsequent resolves of non-cached providers (including deeper-scoped child factories), while a cached factory's instance is fixed at first build and not rebuilt by a later set_context. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update containers.md (set_context) and resolution.md (Steps 4–5) to describe the three-bucket kwargs compilation (provider/static/context), live context resolution on every resolve, and the cached-factory limitation. Removes the now-obsolete compiled-kwargs invalidation description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lesnik512
added a commit
that referenced
this pull request
Jun 14, 2026
…ipped in #216) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
lesnik512
added a commit
that referenced
this pull request
Jun 14, 2026
Full 25-finding report (bugs/security/perf/UX-DX/refactor) with adversarial verification verdicts. B-1/B-2/X-1 (the set_context cluster) shipped in #216; remaining findings are low-severity and open. Includes two main-agent read-through observations (A-1 concurrency, A-2 __enter__ reopen). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Fixes the sole ship-blocker from the 2026-06-14 deep audit: an
APP-scopedContextProviderconsumed by a deeper (REQUEST) scopedFactorywould silently serve a stale value whenset_contextwas called after the factory first resolved.Root cause:
set_contextinvalidated only the calling container's compiled-kwargs memo, but a deeper-scoped factory caches its memo in the child container. When the context was unset at first resolve, the absence (None/default/skip) got baked into that child memo and never invalidated → permanently stale, no error. The present-value path was already live; only the absence was frozen.Fix:
ContextProvider-backed params now go into a dedicatedcontext_kwargsbucket and are resolved live on every resolve — value lookup + default/None/raise + override handling deferred to resolve time. The compiled memo is now type-matching only, so it never goes stale andinvalidate_compiled_kwargsis deleted (net simplification). Cached (singleton) factories are built once and can't pick up late context — documented, not changed.Changes:
factory.py: three-bucket kwargs compilation (provider/static/context); live_resolve_context_valuecache_registry.py: addcontext_kwargs; removeinvalidate_compiled_kwargscontainer.py:set_contextno longer invalidates; docstring scoped to non-cached providersarchitecture/: promoted intocontainers.md+resolution.mdplanning/changes/active/2026-06-14.02-set-context-cross-scope-staleness/Side effects (improvements): an override on a context param applied after first resolve now takes effect; a required context param raises until set, then resolves.
Test Plan
main, pass herejust test-ci)just lint-ci(ruff format + ruff check + ty) cleanmkdocs build --strictOK🤖 Generated with Claude Code