It's December. You're buying presents for five people, you have one budget, and everyone has a different taste. You open ten tabs and do the math in your head. Then you overspend on two people and forget the third. Everybody has lived this, and almost nobody calls it what it is: a planning problem. It is a set of yes-or-no choices competing for one shared budget, with a goal you can write down.
So I treated it like one. On October 21, 2026, I presented Costelinha, the gift-sniffing dog, at a webinar hosted by Harumi, a Brazilian optimization platform.1 You tell Costelinha who you're buying for and how much you can spend. It gives you back a basket that fits the budget and fits each person: one well-matched gift per person, or a complete outfit. The name comes from my own dog, an orange vira-lata caramelo (Brazil's famous caramel street dog). The math is the same that runs fleets, shifts and supply chains.
Four parts and one budget bar
The pipeline is deliberately boring, because every piece has exactly one job.
- Conversation → profile. Gemini turns “mom, dad, our fourteen-year-old, six hundred reais” into a structured profile (relation, age, sizes, taste), and you confirm it before anything is searched.
- Catalog → attributes. The catalog is a real snapshot of two Brazilian stores, Hering and Lojas Pompéia: 2,776 products, collected in one polite pass that respects robots.txt. A product is only a name and a price until Gemini reads it and writes twelve attributes, such as which part of a look it is, its style, palette, formality, season and occasion.
- Candidates. Hard filters come first (gender, age range, size, price), then local multilingual embeddings build a shortlist per person. Without that step the “do these two pieces go together” terms explode: a 50,000-product catalog has over a billion pairs.
- Fit scores. TypeSafe's Jev answers a typed question, “would this person like to get this product as a Christmas gift?”, and returns a calibrated probability.2 It also scores how well two pieces of the same look combine.
- Optimization. A binary program picks the basket. It is solved with OR-Tools CP-SAT on Harumi's kernel.3
Taste isn't a number until a calibrated model makes it one
An optimizer will faithfully maximize whatever you hand it, noise included. So before a taste score went into the objective, I checked it. A one-week build had no room for a human labelling study, so I used an automated judge instead. A stronger model graded 180 person-product pairs on a 0–4 scale, without seeing the price or the generated attributes. Jev's fit agreed with the judge with a Spearman rank correlation of 0.85 over all 180 pairs. On the 93 pairs that survive the hard filters, where the choice is actually hard, it scored 0.73 to 0.79, depending on the language of the prompt. A semantic embedding, the usual shortcut, managed 0.32 on those same pairs.
A caveat, stated plainly: a judge model is a stand-in for human preference, not the real thing. It answers “is this score sane enough to optimize?” It doesn't prove your aunt will love the sweater.
The model: a grid of yes-or-no switches
Every decision is one cell in a grid: this person, this product, yes or no. There are few rules. The basket stays inside the shared budget, everyone gets at least one gift, and each person gets at most one piece per category. Sizes are handled when the shortlist is built. In the default mode the objective is simply total fit, which makes this a multidimensional knapsack.4 An exact solver doesn't guess at it; it proves the best basket.
A full outfit adds two more ideas. For the same person, the pieces have to go together (top with bottom, bottom with shoes), and Jev scores those pairs. Across people, the looks can be coordinated for the family photo, scored from palette and style. Both are products of two decisions, so they are quadratic terms. The model linearizes them in the standard way, so the whole thing stays a binary linear program.5 For the demo's five-person family it has 2,110 variables and 3,897 constraints, and CP-SAT closes it with a zero gap in about half a second.
The demo: watch the budget bar
The live demo was a single story that grows. It starts with a family of three on R$ 600. Then the daughter brings her best friend, and then the uncle nobody has seen in years confirms he's coming. Each event changes the instance, and Costelinha re-plans the whole basket. Every answer is the proven best, never a patch on the previous one.
The two mode switches are the point. Economy asks a different question: what is the cheapest basket in which every gift still clears a minimum fit? The same five people are covered for R$ 163.60, which frees R$ 436. Full look asks for a complete outfit per person, with pieces chosen to go together and coordinated across the family. That spends R$ 598.17 of the R$ 600. The data and the model stay the same; only the objective changes, with one click. Keeping what you want separate from how you compute it is the whole craft of operations research.
Every basket also comes with a short “why this gift” for each person. Gemini writes it from the product's real attributes. The optimizer proves which choice is best, and the explanation is what makes a person trust it enough to buy.
Why the solver runs on a platform
All of this could run on a laptop. OR-Tools is free, and the math fits on one page. But getting a model to solve on a laptop takes an afternoon. A business needs more before it can rely on one: a managed runtime, versioned models with rollback, and an objective you can change without a redeploy. It also needs a history of every run, dashboards, and an API to read the results. That is the 80% of the work that nobody budgets for.
So Costelinha's optimizer lives as a project on Harumi. The AI scores are computed upstream and baked into the instance. Harumi runs the CP-SAT model on its OR-Tools kernel, and the app reads the basket back through the platform's API, with the same numbers to the cent. The goal (best fit, full look or economy) is a run setting, not code. I bring the model, and the platform carries the system around it.
Swap “family” for “team”
None of this is really about Christmas. Replace the family with six employees and the budget with a R$ 1,200 gifting budget capped at R$ 200 per person. Economy mode covers all six for R$ 179.40, about R$ 30 a head. Best-match spends R$ 928.59, with every cap respected. Replace the gifts with shifts, vehicles, crews or credit lines, and it is the same kind of problem: yes-or-no choices competing for shared resources, where being a few percent better compounds over time.
That is what BIS builds: a model for the judgment, a solver for the optimum, and the engineering to run both in production. Your hard decision is probably not a gift basket. It might be a fleet, a schedule, an allocation or a pricing rule, and it has the same structure.
Honest caveats
This is a proof of concept, built in about a week. The profiles in the demo are fictional, so no real third-party data was used. The catalog is a one-time snapshot of two stores, without photos. Taste scores were validated against a judge model, not against people. For the live demo every possible guest was scored ahead of time and cached, so nothing on stage depended on the network. The corporate example uses placeholder fit scores; its prices and the optimization are real. There are no affiliate links anywhere: the basket is chosen for the person and the budget, and nothing else. You can try a different family or budget yourself in the live demo.6

