Inspiration
A FireStorm Labs engineer described the reality of a forward edge node: one operator, one 3D printer, and a finite pile of CF‑nylon filament, printer‑hours, and rationed convoy fuel — with resupply days away and a mission to cover tonight. They aren't choosing a CAD file off a shelf; they're deciding what airframes to fabricate from that pile, and how many, before the window closes.
The insight that wouldn't leave us: the mission should drive both the size and the quantity of what you build — and it should do it both directions. A swarm of soft contacts wants many small drones. A single hardened, high‑value target wants one big one. Move the mission, and the right answer should physically reorganize in front of you. That live reorganization — not a dashboard, not a slicer — is the product.
So we built METE. To mete is to measure out under scarcity. That's the whole job.
What it does
METE is a single‑screen, fully‑offline, deterministic optimizer for fabrication at the edge.
- Load the mission (each target's standoff, payload, weather, and value) and tonight's budget (feedstock, printer‑hours, energy).
- In under a second, METE returns the exact build plan: which drone tiers, and how many —
BUILD 5× SCOUT‑S,1× STRIKE‑L, or a mixed fleet. - Change any input and the answer re‑solves live and reorganizes: five small scouts collapse into one long‑range striker, or back. It always names the binding reason — the limiting budget (
FEEDSTOCK) or the exclusion gate (RANGE) — so the why is on screen, not implied. - When the only capable airframe is unaffordable tonight, it doesn't fake an answer — it returns
CANNOT BUILD TONIGHT — recommend resupply. - A second REPAIR tab runs the same engine over a failed‑part catalog (print‑now / can't‑print‑safety / defer), proving METE is a general allocation engine, not a drone toy.
The governing principle: size is a gate, not a score. A bigger airframe wins only when it's the only tier that can reach, lift, and survive — never on a cost bonus.
The math (the credibility core)
The live problem is a tiny CP‑SAT integer program — an assignment of built airframes to targets over a $3 \times M$ binary matrix. With three tiers and a handful of targets, it solves exactly, sub‑millisecond, and cannot fail to converge on an unrehearsed judge input.
Decision variables — build one airframe of tier $t$ and assign it to target $j$:
$$x_{t,j} \in {0,1}, \qquad t \in {\text{SCOUT},\,\text{ISR},\,\text{STRIKE}},\quad j \in {1,\dots,M}$$
Eligibility is a gate, not a score — tier $t$ can service target $j$ only if it clears every requirement (standoff $d_j$, payload $p_j$, weather $w_j$, plus the material/envelope/component hard gates):
$$\text{elig}(t,j) = \mathbb{1}!\left[\,\text{range}_t \ge d_j \;\wedge\; \text{payload}_t \ge p_j \;\wedge\; \text{wind}_t \ge w_j \;\wedge\; \text{gates}_t\,\right]$$
Constraints — only build what's eligible, cover each target at most once, and derive per‑tier counts:
$$x_{t,j} \le \text{elig}(t,j), \qquad \sum_{t} x_{t,j} \le 1 \;\; \forall j, \qquad n_t = \sum_{j} x_{t,j}$$
Budgets — feedstock $G$, printer‑hours $H$, and energy $E$ are summed across built units. Print time is derived from mass via a single editable deposition rate $r$ (no independent fudge factor):
$$\sum_{t} n_t\, g_t \le G, \qquad \sum_{t} n_t\, \frac{g_t}{r} \le H, \qquad \sum_{t} n_t\, e_t \le E$$
Objective — lexicographic: first cover the most mission value, then spend the least to do it:
$$\max \sum_{t,j} v_j\, x_{t,j} \quad\longrightarrow\quad \min \sum_{t} n_t\, c_t$$
This single structure is why the answer flips honestly. A higher tier $t'$ enters the solution for target $j$ only when every cheaper tier is ineligible — $\text{elig}(t,j)=0$ for all $c_t < c_{t'}$. And the count is set by whichever budget binds first:
$$n^{\max}_t = \min!\left(\left\lfloor \tfrac{G}{g_t} \right\rfloor,\; \left\lfloor \tfrac{H}{g_t/r} \right\rfloor,\; \left\lfloor \tfrac{E}{e_t} \right\rfloor\right)$$
With the seeded tiers (SCOUT 380 g, ISR 450 g, STRIKE 1400 g) under a 2000 g budget, that gives $\lfloor 2000/380 \rfloor = 5$ scouts — feedstock binds. Swap to a 120 km hardened target and SCOUT/ISR fail the range gate ($5,30 < 120$), so the only eligible tier is STRIKE — RANGE binds, and 5 → 1. Same printer, same filament; the mission decided the airframe.
How we built it
- Solver‑first, always. Our one law: no screen is styled until the solver is proven to reorganize in a console. The thesis is proven by the math flipping, not by a UI.
- Solver — Python + Google OR‑Tools CP‑SAT, run deterministically (single worker, fixed config), wrapped in a FastAPI
POST /solveservice that also serves the static frontend on a single port. - Frontend — Next.js static export with Tailwind v4 + shadcn/ui, the live reorganization choreographed in Framer Motion (a FLIP animation: small icons deallocate, the larger silhouette scales into the freed space). Fonts are self‑hosted (IBM Plex Mono via
next/font) — zero external requests. - One frozen seam. A single contract (
contracts.pyPydantic ≡contract.tsTypeScript, snake_case, discriminated on mode) let a solver stream and a frontend stream build in parallel against the same fixtures. The frontend developed against mock JSON, then swapped to the live solver with one flag — the integration was a non‑event because the fixtures broke loudly on any drift. - Fixtures as acceptance tests. Five golden scenarios doubled as the solver's spec and the frontend's mock. The live wire bytes match the goldens char‑for‑char.
Challenges we ran into
- The fake‑physics trap. Our first instinct — a continuous "size" slider — is exactly the thing a drone‑literate judge breaks on sight: the square‑cube law makes interpolated airframes structurally invalid. We killed it and committed to discrete, real Group‑1 tiers with size as a hard gate.
- We killed our own flashiest beat. We wanted a reverse "cut the energy and the big drone shatters back into many small ones" morph. While stress‑testing the model we proved it's dishonest — cutting a budget can never make a gated‑out tier eligible. So the second beat became the honest one:
CANNOT BUILD TONIGHT — recommend resupply(the only capable tier needs 380 Wh; you have 300; an 80 Wh shortfall). The constraint it can't satisfy turned out to be the better insight. - Determinism under adversarial input. We ran a 1166‑case adversarial verification sweep (19 parallel agents) against the solver. It found 3 real bugs — most dangerously a tiebreak keyed on request position instead of a stable id, which would have made the demo non‑deterministic the moment a judge re‑typed a value. We re‑keyed every tiebreak on
(cost, tier_id, target_id)and maderate ≤ 0and negative costs fail gracefully. - A self‑contradictory seed. Our swarm demo originally read "5/5 covered, binding = FEEDSTOCK" — which is impossible (if everything's covered, feedstock isn't the limiter). We surfaced it honestly and fixed the scenario, not the math (8 contacts, so demand genuinely exceeds what the budget can build).
- Truly offline. No CDN, no fonts pulled at runtime, no external calls. An offline audit confirmed 0 external requests across 64 resources, with 7 self‑hosted fonts.
Accomplishments that we're proud of
- A provably‑not‑canned wow: a judge types an arbitrary number and the plan re‑solves correctly, live, offline — because the solver is a pure deterministic function, the unscripted input is the demo.
- Byte‑exact determinism: poke a value and poke it back, and the output is identical to the byte.
- Honesty as a feature: every coefficient is cited and editable, every refusal is explained, and we removed effects we couldn't defend.
- One engine, two modes (BUILD + REPAIR) — the generality story is real, not a slide.
What we learned
- Honesty is a better design constraint than spectacle. The moment we refused to fake the energy morph, the demo got more compelling — an operator‑true "wait for the convoy" beats a pretty lie.
- Adversarial verification finds what you can't. A thousand machine‑generated corner cases caught a determinism bug that would have been invisible until it detonated live in front of a judge.
- Lock the interface, then parallelize. Freezing one contract up front let the solver and UI move independently and meet without an integration scramble.
- A small, exact model beats a big, approximate one — three integer variables you can defend will always out‑credential a continuous oracle you can't.
What's next for METE
METE lands with one operator at one node, but the engine — and the mission‑value data it accretes — is the same one that allocates fabrication for the logistics officer across nodes, the commander weighing tradeoffs at echelon, and the depot at industrial scale. The drone tiers are the wedge; the destination is a decision‑OS for fabrication under constraint.
Mete the mission.
Built With
- fastapi
- framer
- google-ortools
- next.js
- python
- react
- shadcn
- three.js
- typescript
- uvicorn
Log in or sign up for Devpost to join the conversation.