Describe the bug
Caller-controlled scope_id values permanently populate several process-level dictionaries in a long-running Server.
Preparing context for a previously unseen scope creates and retains:
- one BuiltinRuntime scope lock;
- one RelationalContexts PowerContext object;
- one source lock;
- one activation lock.
There is no TTL, LRU, maximum scope count, weak-reference lifecycle, or explicit close operation for a single scope. A valid request does not need to persist any Source or Memory before these objects are retained.
RFC 0019 intentionally caches a scoped Runtime composition, but the remote Server now accepts arbitrary scope IDs at the HTTP/MCP boundary. The original cache assumption therefore becomes an unbounded resource path.
Steps to reproduce
At commit a6e0dfe:
- Start a fresh SQLite-backed Server with Dashboard, MCP, metrics, and access logging disabled.
- Send 250 successful POST /v1/context/prepare requests.
- Use a different valid scope_id for each request and the same short query.
- Inspect the Runtime and RelationalContexts dictionaries.
Observed:
runtime_scope_locks=250
provider_contexts=250
provider_source_locks=250
provider_activation_locks=250
No Source or Memory entries were written.
Relevant paths:
- src/powercontext/builtin/runtime/application.py:1197 and 1383-1396
- src/powercontext/builtin/runtime/relational.py:340-346
- src/powercontext/builtin/runtime/relational.py:449-500
- docs/en/rfcs/0019_local_source_memory_runtime.md:161-167
Expected behavior
A long-running Server should have a concurrency-safe, bounded lifecycle for scope-local objects.
Possible acceptance criteria:
- Define a maximum or idle lifecycle for cached scopes.
- Do not evict a scope lock while an operation still holds or waits for it.
- Allow inactive scope contexts to be reclaimed without weakening per-scope write serialization.
- Expose a bounded metric for active/cached scopes without using scope_id as a metric label.
- Add a public-boundary regression test showing that many one-off scope IDs do not cause permanent linear growth.
Authentication and rate limiting can reduce abuse but do not replace cache lifecycle management for normal long-lived multi-project use.
Actual behavior
Each new valid scope_id permanently increases multiple dictionaries until the process exits. An authenticated caller, or an unauthenticated caller when the Server is publicly bound, can force continued process-memory growth with one-off scope IDs.
Environment
- PowerContext: 0.0.3.dev11+ga6e0dfe8b.d20260823
- Commit: a6e0dfe
- Python: 3.14.3
- Backend: SQLite
- OS: Windows 11
- Probe requests: 250 successful public HTTP prepare_context operations
Are you willing to submit a PR to fix this bug?
Describe the bug
Caller-controlled scope_id values permanently populate several process-level dictionaries in a long-running Server.
Preparing context for a previously unseen scope creates and retains:
There is no TTL, LRU, maximum scope count, weak-reference lifecycle, or explicit close operation for a single scope. A valid request does not need to persist any Source or Memory before these objects are retained.
RFC 0019 intentionally caches a scoped Runtime composition, but the remote Server now accepts arbitrary scope IDs at the HTTP/MCP boundary. The original cache assumption therefore becomes an unbounded resource path.
Steps to reproduce
At commit a6e0dfe:
Observed:
No Source or Memory entries were written.
Relevant paths:
Expected behavior
A long-running Server should have a concurrency-safe, bounded lifecycle for scope-local objects.
Possible acceptance criteria:
Authentication and rate limiting can reduce abuse but do not replace cache lifecycle management for normal long-lived multi-project use.
Actual behavior
Each new valid scope_id permanently increases multiple dictionaries until the process exits. An authenticated caller, or an unauthenticated caller when the Server is publicly bound, can force continued process-memory growth with one-off scope IDs.
Environment
Are you willing to submit a PR to fix this bug?