Problem
build_tool() accepts a single searchControls key and copies it to every index:
if "searchControls" in config:
for idx in tool["indices"]:
idx["searchControls"] = config["searchControls"]
The API stores searchControls per index, and the dashboard writes them that way. Observed on agent 47d6a15c:
| Index |
searchControls |
tcg_cards_msft-build-2026 |
set |
tcg_cards_msft-build-2026_price_asc |
null |
tcg_cards_msft-build-2026_price_desc |
null |
There is no way to express that in agent-config.json. A round-trip of this agent through the CLI necessarily pushes the primary's controls onto both replicas. The dry-run reports this correctly, but the underlying config model cannot represent the desired state.
Note this is separate from #6, which moved searchControls per-index in the payload. The config model is still one shared block.
Suggested fix
Accept searchControls on a replica entry, overriding (or opting out of) the shared block:
{
"index": "tcg_cards_msft-build-2026",
"searchControls": { "hitsPerPage": { "exposed": true, "default": 10 } },
"replicas": [
{ "index": "tcg_cards_msft-build-2026_price_asc", "description": "...", "searchControls": null },
{ "index": "tcg_cards_msft-build-2026_price_desc", "description": "..." }
]
}
_index_entry() already handles dict-shaped replica entries, so this extends an existing path. Semantics to settle: does an omitted key inherit the shared block (convenient) or mean "none" (explicit)? Inheriting matches current behavior and is the smaller change; null would mean "explicitly none".
Also: the documented schema is incomplete
searchControls parameters do not share one shape. Observed across 15 agent records:
| Parameter |
Fields |
hitsPerPage, page |
exposed, default, constraint: {min, max} |
attributesToRetrieve, responseFields |
exposed, default: [], constraint, merge |
distinct |
exposed, default (boolean) — no constraint, no merge |
facets |
exposed, default: [] — no constraint, no merge |
query, custom |
never observed non-null |
constraint appears only on the numeric parameters, merge only on the two list-valued ones. Any validation or docs work should not assume a uniform shape. The README's searchControls section (#8) predates distinct/facets being observed and is worth extending.
merge semantics are still unknown — null in every record seen.
Problem
build_tool()accepts a singlesearchControlskey and copies it to every index:The API stores
searchControlsper index, and the dashboard writes them that way. Observed on agent47d6a15c:searchControlstcg_cards_msft-build-2026tcg_cards_msft-build-2026_price_ascnulltcg_cards_msft-build-2026_price_descnullThere is no way to express that in
agent-config.json. A round-trip of this agent through the CLI necessarily pushes the primary's controls onto both replicas. The dry-run reports this correctly, but the underlying config model cannot represent the desired state.Note this is separate from #6, which moved
searchControlsper-index in the payload. The config model is still one shared block.Suggested fix
Accept
searchControlson a replica entry, overriding (or opting out of) the shared block:{ "index": "tcg_cards_msft-build-2026", "searchControls": { "hitsPerPage": { "exposed": true, "default": 10 } }, "replicas": [ { "index": "tcg_cards_msft-build-2026_price_asc", "description": "...", "searchControls": null }, { "index": "tcg_cards_msft-build-2026_price_desc", "description": "..." } ] }_index_entry()already handles dict-shaped replica entries, so this extends an existing path. Semantics to settle: does an omitted key inherit the shared block (convenient) or mean "none" (explicit)? Inheriting matches current behavior and is the smaller change;nullwould mean "explicitly none".Also: the documented schema is incomplete
searchControlsparameters do not share one shape. Observed across 15 agent records:hitsPerPage,pageexposed,default,constraint: {min, max}attributesToRetrieve,responseFieldsexposed,default: [],constraint,mergedistinctexposed,default(boolean) — noconstraint, nomergefacetsexposed,default: []— noconstraint, nomergequery,customconstraintappears only on the numeric parameters,mergeonly on the two list-valued ones. Any validation or docs work should not assume a uniform shape. The README'ssearchControlssection (#8) predatesdistinct/facetsbeing observed and is worth extending.mergesemantics are still unknown —nullin every record seen.