Skip to content

config model cannot express per-index searchControls (or the full searchControls schema) #16

Description

@chuckmeyer

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions