Problem
Matcher compilation uses a process-global sync.Map keyed by the raw pattern and never removes entries. Successful regex objects, pattern strings, and failed-compilation sentinels are retained for the lifetime of the process.
Code: regexCache and compileAnchored
With staged plan/config updates, a long-lived collector can see an unbounded sequence of matcher patterns even though only the active/staged generations are relevant. Invalid patterns are retained too. This makes controller-driven plan churn translate directly into permanent agent heap growth.
Recommended direction
Compile and validate matchers once when constructing/activating an immutable plan generation, and store the compiled matchers in generation-scoped runtime state. Releasing a retired generation should release its compiled regexes. If cross-generation sharing is retained, use a bounded cache with explicit capacity/eviction and metrics.
Acceptance criteria
- Retired plan/config matcher patterns do not remain permanently reachable solely through a package-global cache.
- Invalid regexes fail plan/config validation before the observation hot path.
- Observation matching performs no compilation.
- Add a churn test that activates/retires many unique valid and invalid patterns and verifies bounded retained heap/cache entries.
- Expose a cache-size metric only if a bounded shared cache remains.
Problem
Matcher compilation uses a process-global
sync.Mapkeyed by the raw pattern and never removes entries. Successful regex objects, pattern strings, and failed-compilation sentinels are retained for the lifetime of the process.Code:
regexCacheandcompileAnchoredWith staged plan/config updates, a long-lived collector can see an unbounded sequence of matcher patterns even though only the active/staged generations are relevant. Invalid patterns are retained too. This makes controller-driven plan churn translate directly into permanent agent heap growth.
Recommended direction
Compile and validate matchers once when constructing/activating an immutable plan generation, and store the compiled matchers in generation-scoped runtime state. Releasing a retired generation should release its compiled regexes. If cross-generation sharing is retained, use a bounded cache with explicit capacity/eviction and metrics.
Acceptance criteria