# Multi-Goal

Tests every metric together in one planned DOE batch, fits real effects, and picks the best configuration when goals compete.

Status: active

## The Problem

Most "make it faster" work optimizes one number and silently regresses another — latency drops but bundle size grows, or test coverage climbs while build time balloons. Tuning one factor at a time misses interactions between factors, and eyeballing a few configs doesn't tell you which factor actually moved the needle.

## What I Built

> Part of the design-of-experiments optimization pattern (see /toolkit/patterns/design-of-experiments) — here: extracted and extended from build-loop's single-metric `optimize` as a pure Python/NumPy CLI, with the greedy fallback triggered by estimated cost rather than reserved for the single-factor case.

A multi-objective Design of Experiments optimizer, extracted and extended from build-loop's single-metric `optimize`. Given a set of factors (up to 11) and competing objectives, it generates a DOE matrix — full factorial, fractional factorial, or Plackett-Burman depending on factor count — runs the experiments, fits per-objective effects, and selects the best configuration.

Selection supports three strategies: weighted **scalarization**, **Derringer-Suich desirability** (each objective gets a target and a tolerance), and the **Pareto frontier** (surface the non-dominated set and choose). When a full design is too expensive, it falls back to a greedy single-factor autoresearch loop. NumPy is the only runtime dependency; it runs as a Claude Code / Codex plugin or as a standalone CLI.

## Worked Example

Using the competing-objectives case named in "The Problem" — latency and bundle size, where cutting one commonly grows the other:

**Objectives**: minimize `latency`, minimize `bundle_size` — the pair "The Problem" calls out as the kind of trade-off single-metric tuning silently regresses.

**Factors**: up to 11 factors can be entered per run; factor count decides which design gets generated — full factorial, fractional factorial, or Plackett-Burman.

**Selection**: the three strategies read the same matrix differently. Weighted scalarization collapses `latency` and `bundle_size` into one score and returns the best row. Derringer-Suich desirability requires each objective to clear its own target/tolerance band before a row is eligible. The Pareto frontier surfaces every non-dominated row — no config beats another on both metrics — and leaves the final pick to whoever reads it.

**Fallback**: if the selected design is too expensive to run in full, the optimizer drops to the greedy single-factor autoresearch loop instead of running a partial matrix.

**Results**: ⚠️ no benchmark yet — this write-up does not publish measured latency, bundle-size, or run-count figures from an actual optimization run.

## Links

- [HTML project page](https://rosslabs.ai/projects/multi-goal/)
