Skip to content

fix: resolve ContextProvider values live so late set_context propagates#216

Merged
lesnik512 merged 5 commits into
mainfrom
fix/set-context-cross-scope-staleness
Jun 14, 2026
Merged

fix: resolve ContextProvider values live so late set_context propagates#216
lesnik512 merged 5 commits into
mainfrom
fix/set-context-cross-scope-staleness

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Summary

Fixes the sole ship-blocker from the 2026-06-14 deep audit: an APP-scoped ContextProvider consumed by a deeper (REQUEST) scoped Factory would silently serve a stale value when set_context was called after the factory first resolved.

Root cause: set_context invalidated 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 dedicated context_kwargs bucket 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 and invalidate_compiled_kwargs is 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_value
  • cache_registry.py: add context_kwargs; remove invalidate_compiled_kwargs
  • container.py: set_context no longer invalidates; docstring scoped to non-cached providers
  • architecture/: promoted into containers.md + resolution.md
  • Planning bundle: planning/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

  • New regression tests (cross-scope defaulted/nullable/required, override-after-resolve, cached-singleton limitation) — fail on main, pass here
  • Full suite: 205 passed, 100% coverage (just test-ci)
  • just lint-ci (ruff format + ruff check + ty) clean
  • mkdocs build --strict OK

🤖 Generated with Claude Code

lesnik512 and others added 5 commits June 14, 2026 12:14
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 lesnik512 merged commit 2b1dfff into main Jun 14, 2026
7 checks passed
@lesnik512 lesnik512 deleted the fix/set-context-cross-scope-staleness branch June 14, 2026 09:30
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>
lesnik512 added a commit that referenced this pull request Jun 14, 2026
Deep-audit fixes (#216-#220): cross-scope set_context, gapped-enum child scope,
new public API (fetch_context_value, display_name, exceptions export), perf, DX.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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