DEV Community

Avery Li
Avery Li

Posted on

Three Dead Ends and One Routing Table: A Pairing Session on Free-Tier AI Work

The decision that survived the session had nothing to do with model quality. It was a routing table: disposable work goes to free-tier capacity, and anything a reviewer would have to re-litigate stays with the reviewer. The protocol below is presented as a template for running that session, not as a transcript of one team's meeting; the dialogue is reconstructed to show the shape of the exchange.

Why a pairing session beats a benchmark for this question

Benchmarks answer how a model scores on someone else's tasks, and they say nothing about which of your tasks should leave your machine. A pairing session answers the narrower question that actually blocks adoption. Two people, one hour, a shared screen, and a written decision at the end cost less than a week of private evaluations. Earlier coverage on this account examined retry probes, fixture contracts, and CI gates; this piece covers the routing decision that logically precedes all three.

The setup: four artifacts before anyone opens an editor

The session works best when both participants arrive with something concrete: a task list, a failure history, a test oracle, and a blank decision record. Without the task list, the conversation drifts into opinions about model quality. Without the failure history, nobody remembers which past incident made the team cautious in the first place.

Step 1 — Write twelve candidate tasks on one page

Twelve is enough to expose a pattern and small enough to finish in a single sitting. Each line carries the task name, the file or module it touches, and how long a wrong answer would take to undo. Tasks that cannot be named at that level of detail are usually not ready for any assistant.

scaffold a new endpoint handler from an existing one     app/api/*        undo: 5 min
regenerate a fixture file from a schema                  tests/fixtures   undo: 2 min
rename a config key across four call sites               config/*         undo: 10 min
refactor the retry policy inside the HTTP client         lib/http/*       undo: 2 days
draft release notes from merged PR titles                docs/*           undo: 1 min
Enter fullscreen mode Exit fullscreen mode

Step 2 — Record the failure history beside each task

The senior's first contribution is the memory the team never wrote down. One column holds the incident, one holds the cost, and one holds whether a test would have caught it. This column decides more routings than any latency measurement taken during the session.

The three questions the senior actually asked

Only three questions came up, and none of them concerned which model performed better. Each one maps to a column in the routing table, which is why the table survives contact with tasks nobody anticipated.

Question one: what happens if this is wrong and nobody notices for a week? Tasks touching service configuration or persisted data fail that question by construction. A rename inside one module usually passes, because a compiler or an existing test notices within minutes rather than days.

Question two: is there anything that fails loudly when the answer is wrong? A fixture regeneration has a schema as an oracle, while release notes have a reviewer and no oracle at all. The presence of a loud failure is the strongest single predictor of safe free-tier routing, stronger than task size or apparent difficulty.

Question three: who re-opens this decision if the output is wrong? If the answer is a senior reviewer with limited hours, the task belongs in reviewed capacity regardless of how good the draft looks. This question reframes the cost of a mistake as someone else's afternoon rather than your own ten minutes.

Three dead ends, in the order they appeared

Dead end one: measuring acceptance rate

The first proposal was to track how often generated patches were accepted without edits. It failed within ten minutes, because nobody had a baseline from before the assistant existed. Acceptance rate also rewards small trivial edits and punishes the difficult refactors that need the most scrutiny. The number would have looked healthy while measuring nothing that mattered to the team.

Dead end two: moving the whole test suite to the free server

The second proposal treated the free server as a CI replacement, which conflated two different guarantees: a machine that runs code, and an environment that reproduces production failures. Cache state, service versions, and network egress all differ, so a green run there proves considerably less than the team assumed. The free server is useful for interactive work, not as a release gate.

Dead end three: routing a security-adjacent refactor to free models

The third proposal looked reasonable on paper, because the refactor carried good test coverage. It failed on the re-litigation question, since the reviewer would re-read every line regardless of the test result. Review attention, not compute, was the scarce resource in that particular case. The task moved to reviewer-owned capacity and the session moved on.

The decision that was kept

The kept decision is a three-lane routing table encoded as a small function, so new tasks get classified by the same rubric the pair agreed on. The function makes no model calls and holds no credentials, which means it can live in the repository and be reviewed like anything else.

# tools/route.py
from dataclasses import dataclass
from enum import Enum

class Lane(str, Enum):
    FREE = "free-tier"
    REVIEWER = "reviewer-owned"
    HYBRID = "free-tier draft + reviewer sign-off"

@dataclass(frozen=True)
class Task:
    name: str
    reversible: bool        # wrong answer undone in under an hour?
    blast_radius: str       # "file" | "module" | "service" | "data"
    has_oracle: bool        # does something fail loudly on a wrong answer?
    reopens_review: bool    # would a reviewer re-read every line anyway?

def route(task: Task) -> Lane:
    if task.blast_radius in {"service", "data"}:
        return Lane.REVIEWER
    if task.reopens_review:
        return Lane.REVIEWER
    if not task.reversible and not task.has_oracle:
        return Lane.REVIEWER
    if task.reversible and task.has_oracle:
        return Lane.FREE
    return Lane.HYBRID
Enter fullscreen mode Exit fullscreen mode

The table the pair filled in during the session, reproduced here with illustrative task names:

Task Reversible Blast radius Oracle Lane
Scaffold handler from sibling file yes file yes free-tier
Regenerate fixture from schema yes file yes free-tier
Draft release notes yes file no free-tier draft + sign-off
Rename config key yes module yes free-tier
Refactor HTTP retry policy no module partial reviewer-owned
Migrate a column type no data yes reviewer-owned

A short test pins the rubric so that a later edit cannot quietly widen the free lane:

# tests/test_route.py
from tools.route import Lane, Task, route

def test_service_work_never_routes_to_free_tier():
    t = Task("rotate credentials", reversible=False, blast_radius="service",
             has_oracle=True, reopens_review=False)
    assert route(t) is Lane.REVIEWER

def test_small_reversible_work_with_oracle_uses_free_tier():
    t = Task("scaffold handler", reversible=True, blast_radius="file",
             has_oracle=True, reopens_review=False)
    assert route(t) is Lane.FREE
Enter fullscreen mode Exit fullscreen mode

Where the free tier actually participates

The free-tier lane is where MonkeyCode's two operator-supplied offerings entered the discussion: free access to hosted models, and a free server option for running the workbench without provisioning a machine. Both claims come from the project's operator, and both should be checked against the project's current page rather than any figure quoted in an article, because quotas, model names, and machine specifications change over time. MonkeyCode is an open-source project, so the workbench itself can be inspected and self-hosted when the hosted path does not fit a team's constraints.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

What made those offerings relevant was not raw capability but the shape of the free lane. Every task in that lane is reversible within an hour and has a loud oracle, so an interrupted session, a rate limit, or a model that changes under you costs minutes. That property holds regardless of which model answers the call, which is why the routing table outlives any particular release.

For the free server, the useful placement is the interactive workbench: generate the scaffold, run the single targeted test, discard the machine. The reviewer-owned lane keeps its own environment, its own credentials, and its own clock.

Keeping the decision after everyone forgets the session

A decision that lives in a chat thread disappears in roughly two sprints. The pair wrote it as an ADR with a reversal trigger, which is the field most teams omit.

# docs/adr/0012-free-tier-routing.yaml
decision: route reversible, oracle-backed, file-or-module work to free-tier capacity
context: three dead ends in one session; review attention is the scarce resource
reversal_trigger: >
  revert if two consecutive weeks pass with more than one free-lane patch
  reopened by a reviewer for a correctness reason
owner: platform-pairing
reviewed_on: <date of the session>
Enter fullscreen mode Exit fullscreen mode

A four-line check keeps the trigger visible, and it runs in the same pipeline as the unit tests above:

#!/usr/bin/env bash
set -euo pipefail
adr="docs/adr/0012-free-tier-routing.yaml"
grep -q "reversal_trigger" "$adr" || { echo "ADR missing reversal trigger"; exit 1; }
grep -q "owner" "$adr" || { echo "ADR missing owner"; exit 1; }
echo "routing ADR intact"
Enter fullscreen mode Exit fullscreen mode

Limitations and who should skip this

The routing table encodes judgement rather than truth, and it will misfile tasks that sit on a boundary between two lanes. Teams under regulated data constraints should not route anything to hosted models, whatever a free tier happens to offer this quarter. Teams without a test oracle will find almost every task landing in the reviewer-owned lane, and that outcome is correct rather than a failure of the tooling.

The free server is not a CI gate, and treating it as one weakens guarantees the team already has. The approach also assumes two people can spend an hour together, which is a real cost for small teams shipping under a deadline. Readers who want a starting point can take the routing function and the ADR template as they are, then adapt the three questions before adapting anything else.

Top comments (0)