Files
git.stella-ops.org/docs/modules/ui/search-chip-context-contract.md
2026-03-07 01:21:14 +02:00

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 AmbientContextService logic.
  • 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 SearchContextComponent with searchContextId so ownership is explicit.
  • Context definitions must provide:
    • id
    • routePrefixes
    • presentation (titleKey/titleFallback, descriptionKey/descriptionFallback) for the search context rail
    • optional domain
    • optional searchSuggestions[]
    • optional chatSuggestions[]
    • optional chatRoutePattern
  • Search suggestion entries should provide:
    • key / fallback for the executable query text
    • reasonKey / reasonFallback for 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
  • 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:
    • recent chips explain they came from last-page actions
    • strategy chips explain they came from recent intent on the same page scope
  • Mode-aware ranking:
    • the shared SearchExperienceModeService owns the active operator mode
    • chips marked with preferredModes are 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
  • 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

  1. Add/adjust a context in SEARCH_CONTEXT_DEFINITIONS.
  2. Ensure page component exposes the same searchContextId (implements SearchContextComponent).
  3. Define or update presentation copy for the context rail.
  4. Add or update reasonFallback text and any preferredModes metadata for each base chip.
  5. Add/adjust unit tests in ambient-context.service.spec.ts.
  6. Add/adjust Playwright tests for route chips + action-driven chips.
  7. 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).