I watched a teammate click Export last month on a prototype that lived on a free server. The model had drafted the worker, the UI painted a green check, and Slack filled with celebration. Finance opened the same path from a real account twenty minutes later and caught a 401 before any file existed. Have you ever seen a demo succeed on a scratch box and the next hop die like that?
I do not think free models are the scandal, and I do not think free servers are either. The scandal is calling that happy path engineering evidence when it never crossed a handoff. The first layer that fails is almost never the model completion sitting in the chat log. It is identity, persistence, retry, and the boring contract that says which machine may write.
People are arguing this week about vibe coding versus real engineering, as if the insult lives in the autocomplete. I think the insult lives in the missing promotion test that nobody bothered to run. If the only proof you have is a chat session on a scratch box, you have a draft, not a feature. Why would a green button on an anonymous local user tell you anything about production?
Here is the opinion I will defend, without hedging, for the rest of this piece. A free environment is a workshop, and a workshop is allowed to stay messy while you learn. The moment you show that workshop to a user, you owe them a replay of one real action against auth, storage, and retries. Without that replay, you are performing confidence for the team, not delivering a vertical slice.
I started treating every free-server prototype as guilty until a small promotion probe actually passed. The probe is not a platform or a framework, and it should not grow into one. It is a recorded request, a tiny adapter, and three assertions that fail loudly on purpose. You freeze one user action as JSON and refuse to call the work shipped until the production-shaped path returns the same contract.
The action I use is deliberately boring: create an export job for the current billing period. The UI posts JSON, the API enqueues work, and the worker writes a row plus an object key. If any of those hops are fake on the free box, the probe should fail before a human does. If that sounds too small to count as engineering, that smallness is the entire argument I am making.
This is a proposed probe you can paste, not a benchmark and not a claim about any particular model. It does not score the draft. It asks whether the first user action still exists after you stop pretending the workshop user is real.
# probe/test_promotion_export.py
import json
import os
from pathlib import Path
import httpx
FROZEN = Path(__file__).parent / "frozen_export_request.json"
PROD_BASE = os.environ["PROD_SHAPED_BASE_URL"]
PROBE_TOKEN = os.environ["PROBE_BEARER_TOKEN"]
def load_frozen():
return json.loads(FROZEN.read_text())
def test_export_job_survives_the_handoff():
payload = load_frozen()
headers = {
"Authorization": f"Bearer {PROBE_TOKEN}",
"Idempotency-Key": payload["idempotency_key"],
"Content-Type": "application/json",
}
with httpx.Client(timeout=20.0) as client:
first = client.post(f"{PROD_BASE}/v1/exports", json=payload, headers=headers)
retry = client.post(f"{PROD_BASE}/v1/exports", json=payload, headers=headers)
assert first.status_code in (200, 201), first.text
body = first.json()
assert body["status"] in {"queued", "succeeded"}
assert body.get("export_id"), "export_id vanished after the auth handoff"
assert "download_url" not in body or body["download_url"].startswith("https://")
assert retry.status_code in (200, 201)
assert retry.json()["export_id"] == body["export_id"], "retry minted a second job"
I freeze the request next to the test so the argument cannot drift into prompt folklore. The file is the user action, and the user action is the only evidence I will accept.
{
"period": "2026-08",
"format": "csv",
"idempotency_key": "exp_2026-08_probe_01"
}
On the free box I still let a model draft the handler, because speed in the workshop is not a moral failure. I do not let that handler talk to production credentials from a chat window. I put a seam in front of identity, jobs, and object storage so the same function can run against a stub and against staging-shaped adapters. Have you noticed how many vibe-coded handlers hide a global USER_ID = "demo" right next to the business logic?
# app/exports/seam.py
from dataclasses import dataclass
from typing import Protocol
class Identity(Protocol):
def user_id(self) -> str: ...
def can_export(self, period: str) -> bool: ...
class Objects(Protocol):
def put_csv(self, key: str, body: bytes) -> str: ...
class Jobs(Protocol):
def create_or_get(self, user_id: str, period: str, idempotency_key: str) -> dict: ...
@dataclass
class ExportRequest:
period: str
format: str
idempotency_key: str
def create_export(req: ExportRequest, identity: Identity, jobs: Jobs, objects: Objects) -> dict:
if not identity.can_export(req.period):
return {"error": "forbidden", "status": 403}
job = jobs.create_or_get(identity.user_id(), req.period, req.idempotency_key)
if job.get("status") == "queued":
return {"export_id": job["id"], "status": "queued"}
key = f"exports/{identity.user_id()}/{req.period}.csv"
url = objects.put_csv(key, job["csv_bytes"])
return {
"export_id": job["id"],
"status": "succeeded",
"object_key": key,
"download_url": url,
}
Notice what this function refuses to do, because refusals are the actual architecture. It does not call a model, and it does not read leftover environment from a free server. It takes protocols, and the probe supplies the production-shaped implementations. When the workshop version authenticated as a hardcoded local user, the seam made that lie visible instead of painting another green check.
The workshop fake is useful, and it is also the first place I expect the story to cheat. I keep it ugly on purpose so nobody confuses it with staging.
# probe/fakes.py
class WorkshopIdentity:
def user_id(self) -> str:
return "demo"
def can_export(self, period: str) -> bool:
return True # this lie is why the workshop demo always looks green
I run the workshop against in-memory fakes, then I point the same probe at a staging-shaped base URL. The command line is the promotion ceremony, not a screenshot in Slack, and not a chat transcript that says the worker looks right.
# workshop: prove the handler exists at all
PROBE_BEARER_TOKEN=workshop-local \
PROD_SHAPED_BASE_URL=http://127.0.0.1:8000 \
pytest probe/test_promotion_export.py -q
# staging-shaped: prove identity and retries survive the hop
PROBE_BEARER_TOKEN="$STAGING_PROBE_TOKEN" \
PROD_SHAPED_BASE_URL="$STAGING_BASE_URL" \
pytest probe/test_promotion_export.py -q
If the first command passes and the second command 401s, you do not have a product. You have a skit with good lighting. A missing Authorization header is the most common leak I see when a free-server habit travels intact into staging, and curl makes that failure impossible to narrate away.
curl -i -X POST "$STAGING_BASE_URL/v1/exports" \
-H "Content-Type: application/json" \
-d '{"period":"2026-08","format":"csv"}'
# expect 401 when the workshop habit of skipping Authorization leaks into staging
If both pytest commands pass but a double click creates two export rows, you still do not have a product. Idempotency is part of the user action, not a later optimization you will remember after the invoice file duplicates itself. Would you accept a payment API that minted a second charge because the browser retried? Then why accept it from an export job a model drafted on a free box?
This is where a free coding environment actually helps, if you keep it in its lane. I will draft handlers faster on a scratch machine with free model access than I will on a locked-down cluster, and that speed is legitimate workshop behavior. Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode is an open-source project that currently offers free model access and a free server option, which is enough workshop to build the slice and the probe without pretending the workshop is staging. If you want a scratch place to assemble that vertical slice, it is one workshop you can try, then you should immediately aim the probe at something that looks like production.
I do not need the workshop to be eternal, large, or impressive on a slide. I need it to be disposable. The promotion probe is what I keep when the free box goes away, because the recorded request outlives the machine that first made it look easy. The model can rewrite the handler tomorrow. The frozen JSON and the 401 assertion should not rewrite themselves to match the new vibe.
Limitations matter, because this opinion is easy to oversell into a religion. A promotion probe does not evaluate model quality, latency, cost, or whether the CSV is even correct. It will not catch a biased export, a leaked tenant in a file, or a worker that dies after the HTTP 201. It assumes you already know the user action, which many early prototypes simply do not. If you are hacking a throwaway animation for yourself, you should not add this ceremony and then congratulate the process.
Anyone shipping regulated data through a scratch server should not use this as cover. Anyone who cannot name the user action in one sentence should not. Anyone hoping a free environment will replace staging, secrets management, or on-call should not, because a furnace for drafts is not a blast door. I will keep using free workshops. I will not let them testify in the shipping meeting.
Production caveats I keep repeating to myself when the demo looks too clean. Rotate the probe token independently from ordinary user sessions, or the probe becomes another shared password. Never let the workshop process hold production object-store credentials, even for a minute of convenience. Record the status codes you actually got, because it worked on my free box is not a response code you can grep later. If the model rewrites the handler, freeze the contract first and treat the diff as untrusted until the probe is green again.
I still want a short gate readers can paste, even though I dislike ritual lists dressed up as strategy. Call it a closed door, not a vibe, and keep it next to the frozen request.
promotion gate
[ ] one user action frozen as JSON
[ ] identity is a real bearer, not a demo user
[ ] create is idempotent under retry
[ ] persistence is a row plus an object key, not a chat blob
[ ] workshop credentials cannot write to production
[ ] probe fails closed on 401, 403, and duplicate ids
My position, again, without softening it for the current argument on social feeds. A free model can draft the worker by lunch, and that still does not decide whether a signed-in retry creates one job or two. The probe decides. Everything else is theater with a green button.
Which layer handoff is least stable in your app right now, and what status code does it actually return when a signed-in user retries the same click?
Top comments (0)