4.1 KiB
4.1 KiB
Search Chip Context Contract
Purpose
- Define one deterministic contract for page-aware search chips.
- Let feature teams add page suggestions without editing
AmbientContextServicelogic. - Blend route context, last few page actions, and bounded suggestion randomization.
- Answer-first self-serve questions and fallback states are governed separately in
docs/modules/ui/search-self-serve-contract.md.
Rule (mandatory for page teams)
- Every page that needs custom search chips must declare a context entry in
SEARCH_CONTEXT_DEFINITIONS. - Page components should implement
SearchContextComponentwithsearchContextIdso ownership is explicit. - Context definitions must provide:
idroutePrefixespresentation(titleKey/titleFallback,descriptionKey/descriptionFallback) for the search context rail- optional
domain - optional
searchSuggestions[] - optional
chatSuggestions[] - optional
chatRoutePattern
- Search suggestion entries should provide:
key/fallbackfor the executable query textreasonKey/reasonFallbackfor the visible "why this suggestion" line- optional
kind(page,recent,strategy) when page teams need non-default styling/priority - optional
preferredModes(find,explain,act) when a chip should rank higher for a specific operator intent
- Suggestion arrays must stay deterministic and bounded:
- at most 3 base chips per page context
- short, action-oriented text
- no tenant/user secrets in fallback text
- keep the query label distinct from rationale text so suggestion clicks always submit the intended query only
- fallback copy should still make sense after mode-aware reordering; do not encode mode-specific rationale into the raw query text
Source of truth
- Contract and registry:
src/Web/StellaOps.Web/src/app/core/services/search-context.registry.ts
- Runtime composition:
src/Web/StellaOps.Web/src/app/core/services/ambient-context.service.ts
Runtime behavior
- The empty-state search panel renders a context rail with:
- page title/description from
presentation - active domain token when available
- last-action token when recent scoped action history exists
- page title/description from
- Base chips come from the page context array.
- A deterministic rotation (session + route scope + 5-minute bucket) varies chip order.
- Last few actions for the current page scope are tracked (bounded history, TTL 15 minutes).
- Up to 2
follow up: ...chips are generated from recent actions and prioritized above base chips. - One strategic chip is generated from dominant/recent action intent.
- Generated chips must also expose rationale metadata:
recentchips explain they came from last-page actionsstrategychips explain they came from recent intent on the same page scope
- Mode-aware ranking:
- the shared
SearchExperienceModeServiceowns the active operator mode - chips marked with
preferredModesare ranked ahead of otherwise-equal chips for that mode - page teams should use this sparingly to express clear intent differences, not to create large per-mode chip forks
- the shared
- Search-surface control rule:
- buttons inside the search surface (mode switch, scope toggle, rescue cards, filters) are part of the same command workspace
- focus transitions into those controls must not collapse the search panel
- teams adding new controls inside the panel must preserve this containment rule in tests
Page ownership workflow
- Add/adjust a context in
SEARCH_CONTEXT_DEFINITIONS. - Ensure page component exposes the same
searchContextId(implementsSearchContextComponent). - Define or update
presentationcopy for the context rail. - Add or update
reasonFallbacktext and anypreferredModesmetadata for each base chip. - Add/adjust unit tests in
ambient-context.service.spec.ts. - Add/adjust Playwright tests for route chips + action-driven chips.
- If the page adds custom controls inside the search panel, add focus-containment coverage so those controls do not dismiss the panel.
Non-goals
- No unbounded per-page suggestion memory.
- No runtime remote fetch for chip definitions.
- No randomization based on
Math.random()(must remain replayable).