Task architecture

Search Approved Android AI History with AppSearch

Keep the repository authoritative while an app-local lexical projection tracks namespace, source revision and per-document outcomes.

Review status: Fact and editorial QA complete; owner review pending · 2026-10-08 · Fact IDs: RAG-01, PRIVACY-01, ANDROID-APPSEARCH-HISTORY-2026-10

Direct answer

For searchable local AI history, treat AppSearch as a derived query index, not the canonical history database. Keep the source of truth in the application repository and index only the fields needed for a user-requested lookup. Each indexed document should point back to a stable history record and revision; a search hit must load the current authorized row before it is displayed or exported. RAG-01 supports separating source ingestion, an index and retrieval into independently verified stages. PRIVACY-01 is a reminder that on-device inference does not prove every app data path is local or private. Neither fact establishes an AppSearch integration in Cove. The AndroidX release table lists 1.1.0 stable and 1.2.0-alpha02 alpha; the guide samples the alpha, not any app’s resolved dependency. Pin actual artifacts and API introductions. LocalStorage is per-app; PlatformStorage and PlayServicesStorage use central indexes. Default private history to LocalStorage. If central storage is explicitly required, set package visibility with SetSchemaRequest.Builder.setSchemaTypeVisibilityForPackage; on PlatformStorage, setSchemaTypeDisplayedBySystem(schemaType, false) where supported, reapplying it after schema updates. App storage does not settle backup/restore. Give each search document a stable namespace and ID plus only approved fields: source ID, result revision, task, language, time and perhaps a short title. Keep full prompts, private documents, credentials and unchecked output out by default. Configure StringPropertyConfig for lexical terms; AppSearch has separate feature-gated embedding properties, but this page does not use them. A match locates history; it is not a verified answer. AndroidX AppSearch 1.1 putAsync(PutDocumentsRequest) returns a ListenableFuture; after success, AppSearchBatchResult keys are document IDs only, not (namespace, ID). An exceptional future has no per-document map. Keep namespace context; scope a batch to one namespace or prevent duplicate IDs across namespaces, then map results to composite identities. Room and AppSearch are separate writes. On deletion, persist a tombstone/revision, serialize or reconcile older puts/rebuilds, and recheck the authorized source row before serving a hit so stale jobs cannot resurrect a deleted snippet. Use AndroidX AppSearchSession.setSchemaAsync(SetSchemaRequest); handle future failure before expecting SetSchemaResponse. After success, inspect incompatible/deleted/migrated types and migration failures. Use a Migrator or planned rebuild for incompatible schema; forceOverride may delete documents. Build a deletion request with RemoveByDocumentIdRequest.Builder(namespace).addIds(ids).build(), pass it to removeAsync, and inspect per-ID results. Removed items stop appearing in queries, but physical reclamation may wait for database thresholds; this is not secure wipe or backup deletion. close() persists changes but is not removeAsync. These are androidx.appsearch 1.1 APIs, not similarly named framework methods. Evaluate lexical retrieval with synthetic queries for exact terms, prefixes, punctuation, languages, revised rows, and deletions. Assert result IDs and source resolution, not generated-answer quality. Reconcile out-of-order writes and test schema changes from populated fixtures. Do not claim universal tokenization, privacy, latency, semantic retrieval, or Cove integration; report only the dependency and backend tested.

A user searches a saved local translation

A traveler wants to find a saved translation by a short phrase months later. The history repository holds the complete source and reviewed output, but the list screen has no fast way to locate one entry. Some records contain sensitive source text that should not automatically become searchable.

Decision

Add an app-local lexical index with an explicit field allowlist, stable record references and deletion synchronization; retrieve full content from the source of truth only after checking the current record.

Expected outcome

Search returns a verifiable history entry or no result, never a stale copied answer or text from an unapproved field.

Evidence to collect

The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:

  • Resolved backend, schema and field allowlist
  • Async per-ID outcomes with namespace context
  • Tombstone, stale-write and deletion reconciliation fixtures

Task quality needs a versioned corpus and acceptance rules. Fluent sample output is not an accuracy result.

Implementation workflow

  1. Choose storage and pin the dependency. Record the resolved AndroidX AppSearch artifact, backend, Android API range and supported feature checks. The current guide sample uses an alpha version while the release table lists a stable line; document the version actually tested. Prefer app-local LocalStorage. Only use a central backend for an explicit requirement; if so, configure package visibility and system-surface visibility in each schema request, checking feature support, and separately inspect backup/restore rules.
  2. Define a minimal search projection. Use a deterministic namespace and document ID tied to the source history row and revision. Select only user-approved searchable fields, declare their indexing and tokenizer types, and keep raw prompts or documents out by default. Treat title/snippet text as a search projection, not as the stored source record.
  3. Synchronize source rows and index outcomes. Write the canonical row first, then project it with AndroidX AppSearchSession.putAsync. Handle future exceptions separately from per-document results. Keys are document IDs only; scope batches to one namespace or prevent duplicate IDs across namespaces, and map results to composite identities in app state. Reconcile stale revisions and tombstones after interruption.
  4. Version schema and query behavior. Call AndroidX AppSearchSession.setSchemaAsync and handle future failure before reading a response. After success, inspect incompatible/deleted/migrated types and migration failures; do not force-override user history. Test populated old schemas, exact/prefix queries, pagination and zero hits. This guide uses lexical matching; embedding properties are a separate feature/version contract.
  5. Delete and audit the full lifecycle. On source deletion, persist a tombstone/revision, call AndroidX AppSearchSession.removeAsync and inspect per-ID results. Reconcile older in-flight puts/rebuilds before marking the projection current, then query and resolve hits against authorized source rows. Query removal is not secure erase; physical reclamation and backups are separate. close() persists but does not delete.

Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.

Acceptance criteria

  • The source repository stays authoritative, and every hit resolves through a namespace, ID and revision to the current authorized row before full content is shown.
  • Only approved fields are indexed; the resolved StringPropertyConfig exact/prefix behavior and chosen LocalStorage backend are recorded without claiming semantic search.
  • Exceptional async futures are handled separately; successful AppSearchBatchResult keys are treated as document IDs with namespace context and no collisions in a batch.
  • Schema migration results, deletion results, tombstones and in-flight projection races are tested. Session close is not treated as remove, and query removal is not described as secure physical erasure or backup deletion.

Decision table

DimensionChoice or evidenceHow to interpret it
Canonical history databaseRoom or the existing source repository stores complete recordsOwns edits, provenance and deletion; it remains the source from which an index can be rebuilt.
AppSearch LocalStorage projectionApp-specific indexed fields for full-text lookupCan support local lexical search, but partial writes and schema versions need explicit reconciliation.
Platform or Play Services storageCentral index backend with additional integration surfacesHas distinct sharing, system-surface and availability behavior; do not choose it silently for private history.
Embedding/vector indexSimilarity retrieval over vectorized contentA different retrieval contract; AppSearch has separate embedding-property APIs, but this guide does not configure or evaluate them.

Failure patterns to prevent

  • Treating search hits as authorized source rows
  • Confusing token search with embedding features
  • Calling query removal a secure wipe

Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.

Minimum reproducibility record

LayerRecord
DeviceManufacturer, model, chipset, RAM class, operating-system build
SoftwareApplication version and git commit
ModelFamily, variant, revision, format, file length, hash, quantization
RuntimeName, revision, requested backend, observed backend evidence
WorkloadFixture revision, input hash, prompt hash, output policy
OutcomeCompleted, failed, cancelled, fallback, and privacy-safe diagnostics

Release checklist

  • ☐ The primary query is answered without an unsupported number.
  • ☐ Every artifact and runtime is pinned.
  • ☐ The representative task and failure policy are explicit.
  • ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
  • ☐ User-content and network boundaries are documented.
  • ☐ Result wording applies only to the recorded configuration.
  • ☐ The page links to raw method or evidence when results are added.

Sources and related evidence

Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.

Frequently asked questions

Is AppSearch the source of truth for AI history?

No. Keep the canonical history row in the app repository and treat AppSearch as a derived projection. Resolve every hit against the current source row, namespace, ID and revision before displaying full content.

Does LocalStorage mean history can never leave the device?

No. It is an app-specific local index, but Android backup, device transfer, exports and other network requests have separate rules. Audit those paths instead of turning local inference into a whole-app privacy guarantee.

Does prefix indexing provide semantic search?

No. The StringPropertyConfig exact/prefix setup here is lexical. AppSearch has separate, feature-gated embedding property APIs in some versions and backends; they need their own resolved-dependency, capability and evaluation contract.

Do batch-result keys identify a namespace and ID together?

No. AndroidX AppSearch 1.1 putAsync returns per-document results keyed by document ID only. Keep namespace context per batch, avoid cross-namespace ID collisions, and retain composite identity in app-owned synchronization state.

Does closing AppSearchSession delete indexed records?

No. close() persists schema and document changes; it does not remove a document. Use AndroidX AppSearchSession.removeAsync(RemoveByDocumentIdRequest) and separately reconcile source tombstones and old writes.

Does removeAsync guarantee a physical secure wipe?

No. A completed remove stops that document from appearing in AppSearch queries, but disk reclamation can wait for database thresholds. It is not secure erase: reconcile old writes, source copies and backups separately. close() persists updates but is not deletion.