Search
The page most likely to be mis-diagnosed. Search on this baseline binds a repository that no layer ships, and its failure mode is a 200.
What the baseline guarantees
Layers: surface-swift 1.5.1 (the pages and the bindings). No layer ships an index. Pages: Search result page (+ grid-row-1, grid-row-2) Service Pages/Content search results Service Pages/Product and content search results Desktop Header carries a Swift-v2_SearchField paragraph. Bindings — every eCom_ProductCatalog surface in this composition binds the SAME repository BY PATH: /Files/System/Repositories/ProductsFrontend/Products.query /Files/System/Repositories/ProductsFrontend/Products.facets Bound by: surface-swift Shop PLP (IndexQuery + FacetGroups), surface-swift desktop header search, surface-swift Express Buy, feature-bom-configurator Kit Configurator, and feature-reordering's Quick Order validation feed (1.0.2 repointed it here). ** No layer in this Distribution ships ProductsFrontend. ** base.contract.json `repositories.provisionedByGate: false`. The three files arrive with the HOST's Swift 2.4.0 Files overlay, alongside ProductsBackend. A consumer whose host has no ProductsFrontend gets HTTP 200 with an in-page Lucene "numHits must be > 0" error — never a 500. Second, separate trap, learned on other demos on this VM and in no skill: an index only rebuilds because a `Build+Index.task` file exists INSIDE the repository folder. The `Repository task handler` scheduled task drains those files. A repository without one is never rebuilt, and build_product_index still answers "Full index build queued" and returns success. Not present by design: zero content index, zero user index, zero SQL index, zero saved product queries beyond whatever the host overlay carries.
Which skill covers it
dw-search-indexing (dynamo: true) — references/index-management.md (the build-status contract), references/mcp-query-tools.md, references/query-authoring.md, references/query-expressions.md.
Which MCP tools brand it
The read-edit-verify loop is mandatory and ordered
(dw-search-indexing/references/mcp-query-tools.md:70-88):
get_product_query_expressions(queryId)
-> delete_product_query_expressions (targeted) OR replace_product_query_expressions
(anything structural — send the COMPLETE desired tree)
-> get_product_query_expressions again, and confirm the tree matches the intent
NodeKeys are POSITIONAL and shift after every change. Never reuse keys from an earlier read.
Discovery before authoring: get_standard_fields, get_product_category_fields,
get_macro_fields. Use only the returned field system names.
Build, in this order (mcp-query-tools.md:135-143):
build_product_index — pass indexName EXPLICITLY, as the index FILE name INCLUDING the
.index extension ("Products.index"). The default is "Products" and
a wrong name succeeds vacuously.
wait_for_product_index — or poll get_product_index_status until complete WITH a non-zero
documentCount
then, and only then, trust query results.
Safe deletion (mcp-query-tools.md:170-179): get_product_queries first, copy the id AND the
exact name, pass both. If the user's name is not in the list, stop and confirm; never retry
against a different query. Verify
Three asserts, and you need all three because each hides the others' failure: 1. File: read_file /Files/System/Repositories/ProductsFrontend/Products.query succeeds, and list_files on that folder shows a Build+Index.task. 2. MCP: get_product_index_status reports the PRIMARY instance LifecycleState Completed with a NON-ZERO documentCount. A status with no documentCount means the tool addressed nothing. An index-level State=Warning caused only by an unbuilt secondary balancer instance is a false alarm. 3. Storefront: GET <site-root>/shop and assert product-card count > 0 AND the body contains neither `dw-error` nor `numHits must be > 0`. Never gate this on HTTP status. Standing predicate check before shipping any query filter (dw-search-indexing/SKILL.md:177-180): count(field = X) + count(field != X) == count(no predicate), with neither side degenerate.