Agent brief — tier: mid (above-average). One PR (Closes #<this>); branch from main. House rules: AGENTS.md.
Goal
ROADMAP milestone 3's recorded remaining item: P-006 open question #3. A singleton that injects IServiceScopeFactory, opens a scope per operation, resolves scoped services inside the scope and does not cache them is the correct pattern — it must not be flagged as captive. Today the DI family covers the wrong shapes (DI001–DI005); this adds recognition of the right one.
Sources of truth
docs/proposals/P-006-di-lifetimes.md — OQ#3 and the captive-family semantics.
- The DI001–DI005 end-to-end machinery and
DiCaptiveSample.cs — the sample/test conventions.
docs/notes/di-captive-extractor.md — extractor-side design notes.
Deliverable
- Extractor + core support so the scope-per-operation pattern produces no captive finding.
- The critical regression: DI005 must keep firing — the same singleton +
IServiceScopeFactory but caching a scope-resolved scoped service into a field stays flagged. That contrast pair (ok: resolve-use-dispose inside scope; bad: cache into field) is the acceptance test.
- Sample set extended (both variants side by side in the DI sample), CI-validated.
Guardrails
- Precision-first: recognize only the provable shape (factory injected directly, scope disposed, nothing scope-resolved escapes the scope). Anything fancier (factory passed around, scope stored) stays at today's conservative verdict.
- Do not touch the dynamic-registration non-goals of P-006.
Done when
Both fixtures pinned (ok silent, DI005 bad still fires), python tests/run_tests.py + ruff check . + mypy green, CI DI job green.
Agent brief — tier: mid (above-average). One PR (
Closes #<this>); branch frommain. House rules:AGENTS.md.Goal
ROADMAP milestone 3's recorded remaining item: P-006 open question #3. A singleton that injects
IServiceScopeFactory, opens a scope per operation, resolves scoped services inside the scope and does not cache them is the correct pattern — it must not be flagged as captive. Today the DI family covers the wrong shapes (DI001–DI005); this adds recognition of the right one.Sources of truth
docs/proposals/P-006-di-lifetimes.md— OQ#3 and the captive-family semantics.DiCaptiveSample.cs— the sample/test conventions.docs/notes/di-captive-extractor.md— extractor-side design notes.Deliverable
IServiceScopeFactorybut caching a scope-resolved scoped service into a field stays flagged. That contrast pair (ok: resolve-use-dispose inside scope; bad: cache into field) is the acceptance test.Guardrails
Done when
Both fixtures pinned (ok silent, DI005 bad still fires),
python tests/run_tests.py+ruff check .+ mypy green, CI DI job green.