A $0 invoice can still be the expensive default.
I keep landing in the same Monday planning room. Finance is calm. The AI line is blank. Then two seniors wait fourteen minutes on one shared free lane while a docs rewrite and a billing patch sit in the same queue. Security asks the question that should have been on the card already. Did customer code leave the boundary because we treated “free” as “fine for everything”?
That is not a model problem. It is a mix problem.
Most teams still run a binary. Keep the free lane, or stand up something private. Binary feels clean. It also dumps three jobs into one pipe. Commodity text. Boundary code. Deadline bursts. They do not share a cost unit, and they do not share a failure mode.
So here is the card I want an EM to fill. Not buy-or-don't. Which work stays on a free hosted lane, which work must stay in-boundary, and which work needs reserved capacity — with an owner and an expiry date.
Disclosure, and where a free lane actually fits
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
I am not crowning a stack. I am trying to stop a blank invoice from posing as a strategy. If you need a free hosted option for the commodity bucket, MonkeyCode is an open-source project that currently offers free model access and a free server option. I am not treating any posted quota, box size, or duration as durable. Check the project on the day you write the policy.
Strip that name out and the routing card still has to work. That is the bar.
The constraint that reverses “just use free”
Zero dollars is a price. It is not a capacity plan.
Shared free capacity has a queue. Self-hosted capacity has an ops tax. Reserved capacity has a sticker. Your job is to put work on the lane whose failure mode you can live with. Not the lane whose invoice is quiet.
Ask it this way. If the free lane vanished for ten days, which PRs would you still ship by hand, which PRs would you pause, and which PRs should never have been on that lane at all?
If that takes a meeting, you do not have a mix. You have a habit.
Look at the incentives, because they will write the mix if you do not. Finance is paid to keep the line at zero. Security is paid to assume nothing left the building. You are paid to show throughput. Seniors are paid to stop waiting behind docs. An unwritten default lets finance win the meeting and security lose the incident.
Variable definitions — write these first
A scorecard is a conversation tool, not objective truth. Fill the variables before you score a vendor.
- Queue minutes (Q): wall-clock wait from “I submitted” to “the lane started useful work,” sampled over a week, not a lucky hour.
- People stacked (P): how many engineers are blocked on that wait. Idle seniors are not free.
- Fully loaded rate (R): your finance number per engineer-hour, including benefits. Not a blog number.
- Ops hours (H): platform hours per week to keep a private lane alive: upgrades, auth, disks, “why is it 500.”
- Ops rate (S): fully loaded cost of the person who actually gets paged.
- Boundary (B): can this diff include customer code, secrets, or production config? Yes or no. No maybes.
- Blast radius (Z): if the model is wrong, is the miss a typo in docs or a payment path?
- Expiry (E): the date the mix dies unless a named human renews it. No open-ended exceptions.
Queue tax for a bucket, dollars per week:
queue_tax = (Q / 60) * P * PRs_per_week * R
Ops tax:
ops_tax = H * S
Reserved sticker is whatever finance is actually billed for that burst lane. Do not convert it into seats. Seats hide contention.
The 3-bucket routing card
Put every recurring work type into one bucket. If a type fits two, it goes to the stricter one. Argue the row, not the brand.
Bucket A — commodity, public-shaped
Think internal docs, test scaffolding on fake data, changelog drafts, “explain this open module.”
Fit: B is no. Z is low. Q can get ugly before the dollar tax beats a private box.
Default lane: free hosted.
Exit: if a commodity PR starts carrying production config, it is no longer commodity. Move it the same day. “Just this once” is how Bucket B leaks.
Bucket B — boundary or high blast radius
Think billing, auth, migrations, customer payloads, anything you would page on.
Fit: B is yes, or Z is high. Cost is not the decider. The boundary is.
Default lane: self-hosted in-boundary, or no AI on that path.
Exit: if you cannot staff H, you do not self-host. You restrict the work. A free shared lane is not a compliance control.
Bucket C — deadline bursts
Think a freeze window, an incident patch, a launch week when three squads collide on one pipe.
Fit: Q times P spikes, even if B is no.
Default lane: reserved capacity, or a hard cap on who may touch the free lane during the window.
Exit: the freeze ends, the reserved lane expires. Burst is not a lifestyle.
Worked example (labeled hypothetical)
This is a filled card, not a customer case. Do not quote it as evidence. Squad of eight. Planning week of 2026-09-22. Rates are placeholders so you can replace them.
| Bucket | PRs/week | Q (min) | P | R | B | Z | Weekly queue tax |
|---|---|---|---|---|---|---|---|
| A docs/tools | 10 | 8 | 1.0 | $120 | no | low | $160 |
| B billing/auth | 4 | 8 | 1.5 | $120 | yes | high | $96, plus an unacceptable boundary miss |
| C launch burst | 6 | 18 | 3.0 | $120 | no | med | $648 |
Self-host ops: H = 5 hours/week, S = $160, so ops_tax = $800.
Read it slowly.
Bucket A is cheap to leave on free. The tax is real and still smaller than standing up a private box for docs. Bucket B should never have been on the shared free lane, even though its queue tax looks small. The failure mode is not money. Bucket C is where the blank invoice lies. Three people waiting eighteen minutes, six times a week, is already most of a private lane’s ops tax — and that is before review time.
Break-even for moving only Bucket C off free: if queue_tax_C stays above the reserved sticker (or above the share of ops_tax you would actually staff for C) for three weeks, C leaves the free lane. If Q drops to four minutes, C can return. The mix is allowed to move. The card is not.
Sensitivity, same sheet:
- If R is $80, C’s tax falls to $432. Free looks better. The boundary rule for B does not move.
- If Q for C is 4 minutes, tax falls to $144. Do not self-host for pride.
- If H is 12 hours because nobody automated upgrades, self-host loses even when Q is ugly. Buy reserved, or cut AI off that path.
- If B flips to yes on a “docs” PR, the whole row jumps to Bucket B. Cost stops mattering.
Which variable would reverse your call this month? Q, H, or B? Pick one. Write it under the table.
Run the numbers. Do not argue the vibe.
Label this as unexecuted example code. Point it at your samples, not at a vendor dashboard.
# Hypothetical worksheet. Not a benchmark. Not a product result.
from dataclasses import dataclass
@dataclass
class Bucket:
name: str
prs_per_week: float
queue_min: float
people_stacked: float
engineer_rate: float
boundary: bool
blast_high: bool
def queue_tax(b: Bucket) -> float:
hours = b.prs_per_week * b.people_stacked * (b.queue_min / 60.0)
return hours * b.engineer_rate
buckets = [
Bucket("A_commodity", 10, 8, 1.0, 120, False, False),
Bucket("B_boundary", 4, 8, 1.5, 120, True, True),
Bucket("C_burst", 6, 18, 3.0, 120, False, False),
]
ops_tax = 5 * 160 # H * S
for b in buckets:
tax = queue_tax(b)
if b.boundary or b.blast_high:
route = "self_host_or_none"
elif tax > ops_tax:
route = "reserved_or_self_host"
else:
route = "free_hosted"
print(f"{b.name:12} tax=${tax:7.0f} route={route}")
print(f"ops_tax=${ops_tax:.0f}")
Want a queue sample you actually own? Pull wait from your logs. Adjust the pattern. This is a sketch.
# Proposal only. Replace the file and field with your lane's logs.
# Do not pretend a missing log is a zero wait.
awk '
/queue_wait_ms/ {
n++
sum += $2
}
END {
if (n < 20) {
print "not enough samples; do not route on this"
exit 2
}
print n, "samples, avg_min=", sum / n / 60000
}
' /var/log/ai-lane/queue.log
If you do not have logs, you do not have Q. You have folklore. Folklore always says the free lane is fine.
Need a rough split of work types before you fill PRs/week? Use your own tree. This is not a quality metric. It is a mix input.
# Proposal: last week's path hits, not a productivity score.
git log --since='2026-09-15' --name-only --pretty=format: |
grep -E '^(docs|internal|billing|auth)/' |
sed 's#/.*##' |
sort | uniq -c
A tiny routing policy beats a wiki paragraph. Expire it.
# Proposal: commit next to the architecture decision record.
# Owner: platform EM. Expires: 2026-10-22.
mix:
owner: "platform-em"
expires: "2026-10-22"
review_channel: "#ai-mix"
buckets:
commodity:
examples: ["docs", "internal-tools", "fake-data-tests"]
lane: free_hosted
boundary: false
boundary:
examples: ["billing", "auth", "migrations", "customer-payloads"]
lane: self_hosted_or_none
boundary: true
burst:
examples: ["launch-week", "incident-window"]
lane: reserved
expire_with: "the freeze calendar"
hard_gates:
- "no customer code on a shared free lane"
- "no mix without a named owner"
- "no open-ended burst exceptions"
Hard gates, owner, expiry, exit
Gates are yes/no. Scores are for debate.
- Boundary gate. If B is yes, the free shared lane is illegal for that work. Do not average it with queue tax.
- Sample gate. If you have fewer than 20 wait samples in a week, you may pilot. You may not declare the mix “working.”
- Owner gate. One named human renews the YAML. A rotation is fine. “The platform team” is not a name.
- Expiry gate. Thirty days, then the exception archives. Burst lanes die with the freeze, not with “we will revisit.”
- Exit gate. To leave a bucket on free, queue tax must stay below the next alternative for three weeks, and B stays no. To leave self-host, H must stay staffed. If H disappears, AI on Bucket B disappears with it.
Archive rule: when you change a route, keep the old YAML in git. Future-you will ask why billing ever sat on the free lane. Show them the date, not a Slack myth.
Pilot rule: run the card for one planning cycle on two work types only. Commodity plus one boundary path. If you cannot keep the YAML honest for that, you will not keep it honest for a company-wide rollout.
Who should not use this card
Do not run a three-bucket mix if you are a two-person shop with no customer data and no queue. You will spend more hours on the card than on the product. Stay on a free lane and write a one-line boundary rule.
Do not self-host because the invoice is $0 and that feels suspicious. Idle ops hours are a real cost. If nobody can own H, you are buying a second incident surface.
Do not use this if legal already mandated a private cluster. The mix collapsed to Bucket B. Fill the YAML anyway so people stop sneaking commodity work onto the expensive box.
And do not treat my placeholder rates as your rates. If R and S are guesses, the table is theater.
Limitations
This card ignores model quality. A free lane that is empty and wrong is still wrong. It ignores token stickers on purpose. Stickers do not capture stacked seniors. It ignores hiring effects. If juniors only ship from a lane nobody can review, you have a different problem, and a routing table will not save you.
I also cannot certify any vendor’s uptime, quota, or hardware from this chair. Free hosted options change. That is why expiry exists.
The question that actually matters
Would you still keep docs and billing on the same free lane if Q for bursts doubled next week?
If yes, your binding constraint is not money. It is probably H, or a boundary rule you have not written down.
If no, write the three buckets this afternoon. Put an expiry on the YAML. Name an owner. Then decide whether the commodity bucket rides a free hosted option.
Which variable would reverse your mix this month — queue minutes, ops hours, or the boundary flag? Write that variable under the table before you change a lane.
Top comments (0)