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