Free inference is a poor default for architecture, security review, and anything that can block a merge. The invoice for tokens is not the invoice for being wrong. A complimentary model on a complimentary machine looks like spare capacity. It behaves more like an unpaid intern with production credentials: fast, eager, and uninsured.
The industry conversation in early September 2026 keeps circling cheap generation. Code got cheaper to emit. Review did not. Brownfield systems still punish a confident diagram that never met the actual auth flow, the actual migration lock, or the actual cache key. That gap is the subject here. The working rule is simple. Free inference may draft. It may not decide.
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. Those two facts are useful for rehearsal. They are not a reason to point the merge gate at whichever endpoint answered first.
A useful analogy is airport security, not a chat window. Cheap tickets do not move a passenger into the cockpit. The classifier below treats architecture notes, secret handling, public contracts, and merge-blocking review as cockpit work. Local scratch, changelog tone, and test-name suggestions stay in the terminal. The point is not moral purity. The point is blast radius.
The artifact is a local policy gate. It reads a change request, scores risk from path and intent, and prints a verdict before any HTTP client is allowed to fire. The script is a proposal. It has not been executed against a vendor account, and it does not claim latency, quota, or quality numbers.
# propose: merge_gate.py — classify before any free-model call
from __future__ import annotations
import json
import re
from pathlib import Path
DENY_PATHS = (
r"(^|/)auth(/|$)",
r"(^|/)crypto(/|$)",
r"(^|/)migrat",
r"\.(pem|key|env)$",
r"(^|/)infra(/|$)",
r"(^|/)helm(/|$)",
)
DENY_INTENT = (
"architecture", "system design", "threat model",
"approve pr", "merge", "rotate secret", "public api",
"breaking change", "data retention",
)
ALLOW_INTENT = (
"changelog wording", "comment tone", "rename test",
"commit message", "scratch snippet",
)
class Verdict:
def __init__(self, allow: bool, reason: str, score: int):
self.allow, self.reason, self.score = allow, reason, score
def path_hits(paths: list[str]) -> list[str]:
hits = []
for p in paths:
for pat in DENY_PATHS:
if re.search(pat, p, re.I):
hits.append(f"{p} ~ {pat}")
return hits
def classify(payload: dict) -> Verdict:
paths = payload.get("paths") or []
intent = (payload.get("intent") or "").lower()
blocking = bool(payload.get("blocks_merge"))
score = 0
reasons = []
hits = path_hits(paths)
if hits:
score += 40
reasons.append("sensitive path: " + "; ".join(hits[:3]))
if any(k in intent for k in DENY_INTENT):
score += 40
reasons.append("intent is cockpit work")
if blocking:
score += 30
reasons.append("result would block merge")
if any(k in intent for k in ALLOW_INTENT):
score -= 20
reasons.append("intent looks like drafting")
if score >= 40:
return Verdict(False, "; ".join(reasons) or "default deny", score)
return Verdict(True, "; ".join(reasons) or "low-risk draft", score)
def load_request(path: str) -> dict:
return json.loads(Path(path).read_text())
if __name__ == "__main__":
import sys
req = load_request(sys.argv[1])
v = classify(req)
print(json.dumps({"allow": v.allow, "score": v.score, "reason": v.reason}, indent=2))
raise SystemExit(0 if v.allow else 2)
A gate that never fails is decoration. The tests below pin three denies and one allow. They are the contract. If a later prompt wrapper starts sending architecture questions because the server was free that morning, the tests should go red before a reviewer does.
# propose: test_merge_gate.py
from merge_gate import classify
def test_denies_auth_migration():
v = classify({
"paths": ["app/auth/session.py", "db/migrations/0042_users.sql"],
"intent": "redesign login and migrate sessions",
"blocks_merge": True,
})
assert v.allow is False and v.score >= 40
def test_denies_architecture_note():
v = classify({
"paths": ["docs/adr/0019-event-bus.md"],
"intent": "architecture for the billing event bus",
"blocks_merge": False,
})
assert v.allow is False
def test_denies_secret_rotate():
v = classify({
"paths": ["deploy/prod.env"],
"intent": "rotate secret and update helm values",
"blocks_merge": True,
})
assert v.allow is False
def test_allows_changelog_draft():
v = classify({
"paths": ["CHANGELOG.md"],
"intent": "changelog wording for 1.4.2",
"blocks_merge": False,
})
assert v.allow is True
Run the proposal locally with ordinary tools. No cloud identity is required for the deny path, which is the path that matters.
python -m pytest test_merge_gate.py -q
cat > /tmp/req.json << 'EOF'
{
"paths": ["internal/api/public.go", "docs/adr/0021.md"],
"intent": "approve pr after architecture pass",
"blocks_merge": true
}
EOF
python merge_gate.py /tmp/req.json; echo exit:$?
The expected exit status is 2. That number is the whole product. A free model never sees the payload. A free server never gets a chance to sound certain about a public contract. Certainty is the failure mode. Cheap endpoints are fluent. Fluency is not evidence.
When the classifier denies, the alternative is not silence. A staff engineer writes the threat model. A migration gets a dry-run against a throwaway schema, not a paragraph from a model. Public API changes go through an explicit review checklist that names pagination, authz, and compatibility. Paid, isolated inference can still draft wording after a human has locked the decision. The order is the policy. Decision first. Prose second.
Exit criteria belong in the same file as the code. If a change set includes auth, crypto, or migrations, stop. If the model output would be cited as the reason a pull request merged, stop. If the server is shared and the prompt includes customer data, stop. If nobody can name a human owner for the architectural claim, stop. If the only argument for proceeding is that the tokens and the machine were free, that is the argument for using a scratch branch instead.
Red flags hide in workflow, not in marketing pages. A bot that posts architecture comments on every pull request is a red flag. A prompt that pastes .env files because the context window looked hungry is a red flag. A team that cannot restore last week's service without the chat log is a red flag. Treat those the way operators treat a flapping health check. Do not negotiate with it. Remove the route.
MonkeyCode's free model access and free server option fit one narrow rehearsal: pointing the classifier at harmless drafting tasks and confirming that cockpit work still exits 2. That is a lab use. It is not a production brain. Teams that want a cheap place to practice the deny path can do that rehearsal there. The rehearsal should end when the first real secret, the first real ADR, or the first merge-blocking review appears in the payload.
Who should not use this approach is as important as who might. A solo prototype with no users can ignore the gate for an afternoon. A regulated workload cannot. A repo that already ships secrets through chat cannot use a free server as a second opinion; it needs a containment incident, not another endpoint. A group that wants the model to pick the stack should not run this classifier at all. The classifier will refuse the question, and the refusal is the answer.
Limitations are blunt. Keyword scoring misses a beautifully vague prompt. Path heuristics miss a dangerous patch in utils.py. The script does not measure model quality, uptime, or token burn. It does not prove a server is isolated. It does not replace code review. It only fails closed when the request looks like cockpit work. False denies will annoy people who wanted a summary of a markdown file that happened to live under infra/. Tune the patterns. Do not tune them to zero.
The core conclusion does not soften after the tests pass. Free inference is a drafting instrument. Architecture, security, and merge gates remain expensive because the mistakes are expensive. Keep the complimentary model in the terminal. Keep the complimentary server off the path that can ship.
Top comments (0)