CCC Non-Agent `match_all` Convenience API
## Problem/motivation Follow-up to: #3586202 ## Problem/motivation `AiContextRequestFactory::fromParameters()` previously defaulted to `match_all` when there was no agent ID and no explicit `selection_mode`. That made broad, full-catalog context scans the implicit behavior for non-agent integration callers (including the `get_relevant_ai_context_items` function call plugin). That default is useful for preview and tooling, but it is risky for frequent non-agent callers: with empty scope subscriptions, the selector loads and evaluates all published context items on every call. The convenience APIs `getRenderedContext()` and `getResult()` intentionally use `match_all` and document that empty scopes match all published context (subject to item/token limits). That behavior is appropriate for preview and tooling, but callers should understand the cost and site builders should be able to detect accidental broad scans on large catalogs. ## Proposed resolution Use a hybrid approach: 1. **Safe-by-default for integration callers.** `fromParameters()` and the function call plugin default to `minimal` when `selection_mode` is omitted. Broad non-agent selection requires explicit `selection_mode=match_all`. 2. **Keep convenience APIs broad by design.** `getRenderedContext()` and `getResult()` continue to use `match_all`. Document that empty scopes trigger a full-catalog scan and that callers should pass explicit scopes to limit the scan. 3. **Broad-scan diagnostics.** When a `match_all` request runs with no scope subscriptions and loads more than 50 published items, log a **warning** (visible in the admin log on default Drupal sites) identifying the consumer and item count. Throttle to once per consumer per request. 4. **Stricter default caps not in scope.** Existing module item/token limits remain unchanged for convenience methods. ## Implementation summary - Removed the special case in `fromParameters()` that forced `match_all` for non-agent calls without an explicit mode; `normalizeSelectionMode(NULL)` now falls through to `minimal`. - Updated function call plugin parameter docs and constants to match. - Added PHPDoc notes on `getRenderedContext()` / `getResult()` about O(n) full-catalog scans when scopes are empty. - Added broad-scan warning in `AiContextSelector::loadCandidateItems()` at the >50-item threshold, throttled per consumer. - Updated developer docs (`function_calls.md`, `services.md`). ## Breaking change Non-agent callers that relied on the old implicit default now receive `minimal` unless they pass `selection_mode=match_all` explicitly. Agent-backed calls are unchanged: when `agent_id` is provided, the agent's saved context configuration (including selection mode) is still merged into the request. ## Test coverage Kernel tests verify: - Non-agent `fromParameters()` defaults to `minimal`. - Explicit `selection_mode=match_all` still works for non-agent calls. - Function call plugin defaults to `minimal` when `selection_mode` is omitted. - Broad-scan warning fires above the 50-item threshold, stays quiet at or below it, and is throttled per consumer. Manual testing confirmed existing agent context selection and the function call plugin work as expected with no regressions observed. ## Tasks - Check against other issues to make sure it wasn't separately reported - Verify this is still an issue before proceeding - Verify the solution approach before proceeding - Update code - Review and test ## AI usage - [x] AI Assisted Issue - [x] AI Assisted Code
issue