# Search and Command Palette Architecture

**Status:** Approved target-state baseline  
**First product realization:** I3  
**UI substrate:** `dip/cmdk`, subject to normal dependency/reuse verification  
**Backend reuse candidate:** `@platform-modules/search`

## Target State

AWP provides one global find/navigate/act surface through `Cmd/Ctrl+K` plus a URL-restorable full Search page for larger result sets.

```text
Shell search affordance / Cmd+K
        ↓
AWP Command Palette
        ├─ CommandRegistry
        └─ SearchQuery
              ↓
        Search application service
              ↓
        SearchRegistry / providers
              ↓
        authorized AWP read models
```

The palette is an interaction layer, not a data authority or authorization bypass.

## Mental Model

```text
Search
  find/open exact product objects and commands

Advisor
  analyze/explain/recommend over product state
```

The two may cross-link, but one input does not ambiguously switch modes on its own.

## `cmdk` Role

Use `cmdk` for accessible command-menu/combobox behavior and keyboard navigation.

AWP owns:

```text
visual styling
search data
ranking policy
entity grouping
authorization
commands
URL state
analytics
```

`cmdk` must not become the product search datastore.

### Local vs remote filtering

Static navigation/command entries may use cmdk local filtering.

Global entity search must use server/backend-ranked results and render them with cmdk internal filtering disabled conceptually as:

```tsx
<Command shouldFilter={false}>...</Command>
```

This avoids preloading large AWP datasets into the React tree.

## Platform Search Reuse

Current `@platform-modules/search` already provides generic concepts matching AWP needs:

```text
Hit { entityType, id, rank, title?, snippetHtml? }
SearchProvider
SearchRegistry
SearchGroup
SearchResult
cursor/pagination
query sanitization
```

Before custom generic search registry/ranking infrastructure, the consuming increment must prove this package's current fit and reuse it where appropriate.

AWP-specific work remains:

```text
entity-specific providers/read models
authorization/scoping
result presentation
command registry
product ranking/boost rules
search telemetry
```

## Searchable Entity Families

Target set as domains activate:

```text
Project
ProjectVision
Plan / PlanRevision
Task
FactoryRun
AgentRun / Attempt
ChangeSet / Review
Decision / Approval
CIExecution / VerificationEvidence
Artifact / Release / Deployment
Machine / Workload
Incident / ResolutionAttempt
Connection / supported Settings destinations
```

No entity becomes searchable before its access-control and stable navigation contract exists.

## Query Contract

Conceptual search query:

```text
SearchQuery {
  query
  scope: system | project?
  projectId?
  entityTypes[]?
  status[]?
  attentionOnly?
  timeRange?
  sort?
  limit
  cursor?
}
```

Search-provider authorization is applied before returned title/snippet content is exposed.

## Command Registry

Commands are registered application/control-surface actions, for example:

```text
Open Project
Open Plan
New Plan
Open Needs Your Attention
Open active FactoryRun
Ask Project Manager
Ask AWP
Open Settings
```

Navigation commands can execute directly. Mutating/protected commands invoke the same application command/PolicyEvaluation/Approval path used everywhere else.

The palette never executes a hidden shortcut around current revision, confirmation or authorization requirements.

## Ranking

Ranking should combine only explainable product signals, such as:

```text
text relevance
exact/prefix match
current Project boost
recently opened
active/needs-attention boost where useful
entity-type intent
```

Do not overfit opaque AI ranking for baseline navigation.

Full ranking policy can evolve behind a stable result contract.

## Full Search Page

Complex/large result sets continue to a stable route, conceptually:

```text
/search?q=translation&type=plan,task&project=...
```

The full page supports filters, pagination/cursors, grouping/sort and shareable URL truth. It uses the same Search service/providers as the palette.

Palette shows a bounded number of top results by group plus `View all results`.

## Realtime / Freshness

Search is not required to be realtime-to-the-millisecond. Index/read-model freshness is surfaced when material.

Opening a result fetches the authoritative primitive; stale search results cannot authorize a protected action.

Deleted/archived/superseded results either disappear after index refresh or are clearly marked when historical search intentionally includes them.

## Security / Privacy

- Principal/project scope is part of provider query context;
- do not fetch unauthorized global result rows then hide them only in browser;
- snippets respect sensitive-data/redaction policy;
- credentials/secrets/tokens are never searchable content;
- search analytics store only allowed query telemetry under retention/privacy policy;
- command visibility is capability-aware, but hidden commands do not replace backend authorization.

## Performance

- debounce/throttle high-frequency remote queries;
- cancel/supersede stale in-flight searches;
- bounded per-group results in palette;
- cursor/pagination for large lists;
- no all-entities preload;
- partial provider failure should not block unrelated result groups.

Exact debounce/caching values are implementation tuning, not domain semantics.

## Accessibility

- `Cmd+K` on macOS and `Ctrl+K` on Linux/Windows;
- visible shell search affordance advertises shortcut;
- semantic input/listbox/menu behavior via cmdk;
- arrow navigation, Enter select, Escape close/back;
- focus returns to opener;
- loading/result-count changes use restrained polite announcements;
- result group/entity/status is available in text, not color alone.

## Observability

Track product-level search behavior without storing sensitive content indiscriminately:

```text
palette opened
query issued
result group counts
zero-result
query reformulation
selected entity/command type
search -> destination success
full-search continuation
latency/error/partial failure
```

These metrics support future UX research and ranking changes.

## Failure / Recovery

```text
backend unavailable
  -> keep static navigation commands available where safe
  -> show search unavailable/retry

one entity provider fails
  -> partial results + explicit source failure

no results
  -> broaden/clear filters + full Search option

stale/disconnected
  -> historical/recent navigation can remain visible
  -> protected mutations still require live authoritative state
```

## Invariants From Day 1

- one search backend contract serves palette and full Search page;
- cmdk is UI substrate only;
- search cannot broaden authorization;
- query/filter state on full Search is URL-restorable;
- mutation commands use canonical application authority;
- large datasets are not forced into cmdk's client DOM filtering model;
- Search and Advisor remain distinct mental models.

## Increment Realization

| Increment | Search realization |
|---|---|
| I1 | not active as product feature; shell does not show dead search controls. |
| I2 | query/search seams may be used internally by Planning/onboarding if useful. |
| I3 | Cmd/Ctrl+K palette + full Search for Project/Vision/Plan/Task/Decision/Approval and active lifecycle entities. |
| I4 | richer Agent/Factory/history search and Advisor commands. |
| I5–I8 | CI/Release/Cluster/Incident entity providers activate with domains. |
| I9 | organization/tenant scope/filter/governance if productized. |

## Current Implementation State

Target specification only.

## Deferred Realization

Semantic/vector search, natural-language search rewriting and cross-tenant federated search are not baseline requirements. Add only if measured search behavior justifies them.

## Temporary Dogfood Behavior

Do not implement a temporary client-only global entity search in I1. Existing browser/navigation may suffice until I3, while final routes/IDs remain searchable-ready.

## Decisions / ADRs

`cmdk` is the selected interaction direction because it fits the unstyled React command-palette seam. Dependency integration must still pass the normal Astryx/accessibility/React-version and reuse compatibility gate before code.