Skip to content

feat(lens): geographic filter on Discover lenses (locations)#116

Open
ArtyETH06 wants to merge 4 commits into
mainfrom
ArtyETH06/lens-geo-filter-3759
Open

feat(lens): geographic filter on Discover lenses (locations)#116
ArtyETH06 wants to merge 4 commits into
mainfrom
ArtyETH06/lens-geo-filter-3759

Conversation

@ArtyETH06

@ArtyETH06 ArtyETH06 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What

leadbay_new_lens and leadbay_adjust_audience now accept locations / exclude_locations — a geographic dimension on the Discover lens, mirroring the existing sector path:

  • free text (["Indre-et-Loire"], ["Texas"]) auto-resolves via /geo/search (reusing resolveLocations from _geo-helpers.ts), or pass admin-area ids directly;
  • resolution happens first — ambiguous/unresolved text returns ambiguous_locations and the lens is not mutated (no half-built lens);
  • the resolved ids are merged into the lens filter as a location_ids criterion via mergeFilter.

Why

The MCP could already geo-filter the Monitor side (pull_followups + location_ids) but had no way to set geography on a Discover lensadjust_audience/new_lens took only sector/size. A sales director couldn't scope a rep's territory (a département) and ask for net-new accounts there without leaving the agent for the web UI. This unblocks the "scope a territory → net-new accounts there" cockpit workflow.

The backend already supported a location_ids lens criterion — only the MCP never exposed it. This is a pure MCP-layer fix.

Changes

  • mergeFilter extended with optional toAddLocations / toExcludeLocations (additive — existing callers unchanged).
  • new_lens + adjust_audience: new params, schema, ambiguous_locations bail, preview surfacing.
  • Templates updated (routing triggers + body) and descriptions regenerated.
  • WORKFLOWS.md row 35 (territory scoping) + contract.
  • New tests: new-lens-geo.test.ts, adjust-audience-geo.test.ts (9 cases — happy path, ambiguity bail, id-passthrough, exclude, sector coexistence).

Verification

  • pnpm -r build / pnpm -r test / pnpm -r typecheck — all green (948 tests; 9 new).
  • Live geo smoke (prod): new_lens(locations:["Texas"]) → created with {type:"location_ids",is_excluded:false,locations:["6029"]}; read-back populated the locations echo block [{id:"6029",name:"Texas"}]; adjust_audience(exclude_locations:["California"]) added an is_excluded:true criterion alongside; test lens deleted.
  • Live /eval — Workflow 35 (prod): MM 5 / IA 5 / NF 5 / TSF 5, invariants 3/3 PASS. Prompt "Create a lens for net-new accounts in Texas" routed to leadbay_new_lens with locations:["Texas"], hit the confirm gate, never misrouted geography to a sector/refine_prompt; leadbay_report_outreach absent. Not covered: the ask_user_input_v0 widget didn't render in the minimal eval harness (fell back to prose) — a harness artifact, not a product issue.

Closes https://github.com/leadbay/product/issues/3759

new_lens and adjust_audience now accept `locations` / `exclude_locations`
(free text auto-resolved via /geo/search, or admin-area ids), writing a
`location_ids` lens-filter criterion. Mirrors the existing sector path:
resolve first, bail with `ambiguous_locations` before mutating, merge into
the filter via mergeFilter. The backend already supported a `location_ids`
lens criterion (verified live: POST /lenses/:id/filter → 204, populates the
locations echo block); only the MCP never exposed it.

Unblocks programmatic sales-territory scoping on the discovery surface — the
"scope a territory → net-new accounts there" cockpit workflow (product#3759).

Co-Authored-By: Claude <noreply@anthropic.com>
@ArtyETH06 ArtyETH06 self-assigned this Jun 22, 2026
ArtyETH06 and others added 3 commits June 22, 2026 15:48
When an exclude_locations entry resolved ambiguously, the recovery message
told the agent to re-call with location_ids — the include-only param — which
silently flipped "exclude Springfield" into "include Springfield". Split the
include vs exclude ambiguity messages so each steers to its correct retry
param (exclude_locations for excluded picks), in both new_lens and
adjust_audience. Regression test added.

Addresses PR #116 review (P2).

Co-Authored-By: Claude <noreply@anthropic.com>
The execute-path message was already exclude-safe, but the outputSchema
descriptions for ambiguous_locations still told clients to always re-call
with location_ids — so a schema-driven agent could re-submit an ambiguous
EXCLUDE pick via the include param and add an area the user asked to exclude.
Make the schema guidance route by axis (include → location_ids/locations;
exclude → exclude_locations) in both adjust_audience and new_lens.

Addresses PR #116 review (P2, follow-up).

Co-Authored-By: Claude <noreply@anthropic.com>
The runtime message and output schemas were already exclude-safe, but the
tool-description templates still told the model to re-call ambiguous locations
with location_ids unconditionally — so a model following the description could
turn "exclude Springfield" into "include Springfield". Route the retry by axis
(include → location_ids/locations; exclude → exclude_locations) in both
adjust-audience and new-lens templates; regenerated descriptions.

Addresses PR #116 review (P2, third surface).

Co-Authored-By: Claude <noreply@anthropic.com>
@ArtyETH06 ArtyETH06 marked this pull request as ready for review June 22, 2026 23:01
@ArtyETH06 ArtyETH06 requested a review from milstan June 22, 2026 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant