marlocDiscover · .project/artifacts

marlocDiscover

A thinking business directory. It holds professionals — realtors, advisors — and answers a sentence rather than a form. This page exists because the product's front door is the product: site.aankoopvergelijker.nl sits behind Cloudflare Access, so an internal reader who is not signed in gets a login screen and learns nothing. This is what they can read instead.

19 August 2026 ADR-0009 A-model · SEARCH-001 · CONCEPT-001 5,671 rows live

What it is

A directory that answers, not one that filters

The difference is the whole product. A classical directory gives you controls and leaves the thinking to you. Discover accepts what you actually said, works out which of its fields could answer it, and tells you when it could not.

1 · Listings

The stable fields

Businesses, categories, places, ratings and review aggregates — written by one writer. Discover reads; marloc-md-publisher-worker is the sole author of the serving tables. A reader that can also write is a reader that will disagree with itself.

marloc-md-discover-worker · D1 businesses, business_listings

2 · The query

Filters, and disjunction

A query is { groups: Constraint[][] } — disjunctive normal form. Groups are ORed, constraints within a group ANDed, so "makelaars in Utrecht or taxateurs in Amersfoort" is one request with one set of counts, not two searches stapled together.

@mondial-it/search-and-filters · g<n>.<field> in the URL

3 · The sentence

Free text, tokenised per request

No index, no cron, no token store. q is split at query time, asking words dropped, capped at six tokens, ORed across searchable fields and ANDed across tokens. Nothing outlives the request, so there is nothing to backfill and nothing to prune.

app/lib/ · F9 in the search-and-filters register

4 · The answer

Presented, and explained

Results render through the site manifest — bands and record renders chosen by an interpreter at request time, not baked at build. A moderated change is live without a deploy.

app/components/directory/site-manifest.ts → manifest_active

The decisions that shaped it

Four, and each one closed a real failure

A name lookup is not a relevance query

Someone typing a firm they already know is doing a lookup. Ranking that by relevance is the most damaging failure available: they do not see the firm and conclude it is not listed. So an exact name match leads under every sort, including paid placement — and a query with no distinctive term is refused by the name rank entirely, because ranking makelaar amsterdam by name would promote whichever hundred rows share the generic word.

The audience writes what it hears

A Dutch buyer looking for Brouwer types bouwer or brower, and the directory holds 194 Brouwer businesses a literal match never reaches. Variants are generated — deterministic consonant insertion and elision, the operation a substitution table structurally cannot express — and every candidate is counted from the database before it is offered. A suggestion nobody counted is a guess wearing a number.

Zero results is a conversation, not a dead end

Two halves. Progressive relaxation drops the story terms first, then the location, and says the search was widened. A counted relax offer covers what relaxation cannot reach — a zero produced by filters rather than by text: "removing the reviews filter shows 233 results instead". An empty page is the one place where a counted alternative is the only thing a visitor can act on.

Discover holds no houses

Where a page shows property, Discover asks marlocHomes for a named render and splices the returned HTML. It holds no product model of its own for them, and Homes returns markup that names no colour — it reads --md-frag-* tokens off the host. One recipe, two owners, no duplicated schema.

What it declares

An agent can read the affordances before it asks

GET /api/agent/manifest publishes the fields a query may bind and the methods it may call — derived from the field catalog, not written beside it. A hand-kept affordance list drifts within weeks, and a drifted one promises fields the query cannot answer.

SurfaceWhat it answersWho asks
/api/agent/manifest15 fields, 2 methods, disjunction: trueTorria, Tafelo, any agent
/api/record-renders/:ida declared query shape as concept-keyed JSONdecision surfaces
/api/renders/:id/fragmentthe same shape as spliceable HTMLmarlocHomes
/api/name-suggestcounted spelling candidatesthe results page
/api/healthliveness, unauthenticatedthe fleet monitor

Honest limits

What it does not do

  • Only listings are searched. Editorial pages, FAQs and articles are not — q names business, profile and listing columns only.
  • No permission-scoped results. Every record is public; nothing scopes what a viewer may see.
  • No separate results surface. Results render inside the directory page.
  • Comparison belongs to Tafelo. Discover presents a shortlist; it does not judge it.

Sources: .project/todo/BACKLOG.md · .project/COMPETENCE-MAP.md · .marlocSearchAndFilters-root/README.md (F1–F37) · .project/decisions/. Every figure here was read from the live system or the register, not estimated.