DEV Community

Casey Sun
Casey Sun

Posted on

Four Workloads That Should Never Touch a Free Model Tier: An Anti-Use Field Guide

A retry storm at 02:14

Consider a familiar pattern. A nightly cron worker calls a shared model endpoint for classification. The endpoint throttles under load, the worker retries, and the loop outlives its window. Nobody owns the endpoint. Nobody wrote a stopping condition.

Adoption checklists ask one question: can this run here? The stronger question is what disqualifies this workload. That flips the default. Teams then need a catalog of refusals instead of a list of features.

This post builds that catalog. It ships a small linter that runs in CI. Nothing below depends on a single vendor.

The five fields of an anti-use entry

Each refusal must be arguable and testable. Five fields do that.

  1. id — a stable key, quoted in reviews and PRs.
  2. when — machine-checkable tags and workload fields.
  3. why — the failure mode, not the policy wording.
  4. alternative — where the workload belongs instead.
  5. exit_signal — the observation that proves the refusal was right.

An entry without alternative is a complaint. An entry without exit_signal is a guess.

Four entries that earn a block

AU-01: anything on a signed request path

Webhooks, payment callbacks, and ledger writes share a property. Their receiver owns the timeline, not the caller. A throttled free lane inserts delay into a signed request. Idempotency keys and signature windows do not negotiate.

  • Alternative: a pinned runtime with a named on-call owner.
  • Exit signal: one signature failure or duplicate delivery in 24 hours.

AU-02: bulk backfills and migrations

A backfill turns quota into a wall-clock dependency. Partial progress is hard to resume. Partial progress is harder to explain to whoever reruns it.

  • Alternative: a queue with a fixed concurrency budget, or a batch job with a paid contract.
  • Exit signal: the job window exceeds the retry budget on two consecutive runs.

AU-03: customer-facing latency budgets

A free lane can change limits or capacity without notifying the caller. That is a legitimate property of shared infrastructure. It is also incompatible with a p95 promise made to a customer.

  • Alternative: a reserved runtime, or a queue that absorbs variance.
  • Exit signal: upstream 429 responses inside any customer-visible window.

AU-04: regulated data classes

Data class is not a performance question. A summarizer for public docs and a summarizer for health records share code and share nothing else. The workload field decides, not the model quality.

  • Alternative: an environment approved for that data class, with an audit trail.
  • Exit signal: any request that crosses a data-class boundary.

The artifact: a catalog plus a linter

First, the catalog. Keep it in the repo next to the workloads it judges.

# antiuse.yaml
version: 1
entries:
  - id: AU-01
    name: signed-request-path
    severity: block
    when:
      any_tags: [webhook, payment, signature, ledger]
      fields:
        stage: production
    why: >
      Retries and throttling shift the delivery timeline of a signed request.
      The receiver owns the signature window, not the lane.
    alternative: pinned runtime with a named on-call owner
    exit_signal: one signature failure or duplicate delivery in 24h

  - id: AU-02
    name: bulk-backfill
    severity: block
    when:
      any_tags: [backfill, bulk, migration]
    why: >
      A backfill converts quota into a wall-clock dependency with weak resume points.
    alternative: fixed-concurrency queue or a contracted batch job
    exit_signal: job window exceeds retry budget twice in a row

  - id: AU-03
    name: customer-facing-latency
    severity: warn
    when:
      fields:
        p95_budget_ms: 800
    why: >
      Shared capacity can change without notice; a p95 promise cannot.
    alternative: reserved runtime or an absorbing queue
    exit_signal: upstream 429 inside any customer-visible window

  - id: AU-04
    name: regulated-data
    severity: block
    when:
      fields:
        data_class: regulated
    why: >
      Data class is a boundary question, not a model-quality question.
    alternative: environment approved for that data class
    exit_signal: any request crossing a data-class boundary
Enter fullscreen mode Exit fullscreen mode

Next, a workload manifest. Three lines of metadata do most of the work.

# workloads/checkout.yaml
name: checkout-callback
owner: payments-team
stage: production
data_class: regulated
p95_budget_ms: 800
tags: [webhook, signature, payment]
Enter fullscreen mode Exit fullscreen mode

Now the linter. It reads two files and exits non-zero when a block-level rule matches.

#!/usr/bin/env python3
"""fieldguide.py - refuse a workload before it reaches a free-tier lane."""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

import yaml

SEVERITY = {"warn": 1, "block": 2}


def load_yaml(path: Path) -> dict:
    with path.open(encoding="utf-8") as handle:
        return yaml.safe_load(handle) or {}


def matches(rule: dict, workload: dict) -> list[str]:
    reasons, tags = [], set(workload.get("tags") or [])
    for tag in rule.get("any_tags") or []:
        if tag in tags:
            reasons.append(f"tag:{tag}")
    for field, expected in (rule.get("fields") or {}).items():
        if workload.get(field) == expected:
            reasons.append(f"{field}={expected}")
    return reasons


def evaluate(catalog: dict, workload: dict) -> dict:
    hits = []
    for entry in catalog.get("entries", []):
        reasons = matches(entry.get("when") or {}, workload)
        if not reasons:
            continue
        hits.append(
            {
                "id": entry["id"],
                "name": entry["name"],
                "severity": entry.get("severity", "warn"),
                "matched": reasons,
                "alternative": entry.get("alternative", ""),
                "exit_signal": entry.get("exit_signal", ""),
            }
        )
    verdict = "pass"
    if any(hit["severity"] == "block" for hit in hits):
        verdict = "block"
    elif hits:
        verdict = "warn"
    return {"workload": workload.get("name", "<unnamed>"), "verdict": verdict, "hits": hits}


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--catalog", type=Path, default=Path("antiuse.yaml"))
    parser.add_argument("--workload", type=Path, required=True)
    parser.add_argument("--fail-on", choices=["warn", "block"], default="block")
    parser.add_argument("--json", action="store_true")
    args = parser.parse_args(argv)

    result = evaluate(load_yaml(args.catalog), load_yaml(args.workload))

    if args.json:
        print(yaml.safe_dump(result, sort_keys=False))
    else:
        print(f"{result['workload']}: {result['verdict'].upper()}")
        for hit in result["hits"]:
            print(f"  {hit['id']} {hit['name']} ({hit['severity']}) via {', '.join(hit['matched'])}")
            print(f"    instead:      {hit['alternative']}")
            print(f"    exit signal: {hit['exit_signal']}")

    worst = max((SEVERITY[h["severity"]] for h in result["hits"]), default=0)
    return 1 if worst >= SEVERITY[args.fail_on] else 0


if __name__ == "__main__":
    sys.exit(main())
Enter fullscreen mode Exit fullscreen mode

Run it against the checkout manifest. The output is short and blunt.

$ python fieldguide.py --workload workloads/checkout.yaml
checkout-callback: BLOCK
  AU-01 signed-request-path (block) via tag:webhook, tag:signature, tag:payment
    instead:      pinned runtime with a named on-call owner
    exit signal: one signature failure or duplicate delivery in 24h
  AU-04 regulated-data (block) via data_class=regulated
    instead:      environment approved for that data class
    exit signal: any request crossing a data-class boundary
$ echo $?
1
Enter fullscreen mode Exit fullscreen mode

Two tests pin the behavior. They run without touching the catalog file.

from fieldguide import evaluate

CATALOG = {
    "entries": [
        {
            "id": "AU-04",
            "name": "regulated-data",
            "severity": "block",
            "when": {"fields": {"data_class": "regulated"}},
            "alternative": "approved environment",
            "exit_signal": "data-class crossing",
        }
    ]
}


def test_regulated_workload_blocks():
    result = evaluate(CATALOG, {"name": "checkout-callback", "data_class": "regulated"})
    assert result["verdict"] == "block"


def test_internal_tool_passes():
    result = evaluate(CATALOG, {"name": "docs-summarizer", "data_class": "public"})
    assert result["verdict"] == "pass"
Enter fullscreen mode Exit fullscreen mode

Wire it into CI. A blocked workload fails the pull request, not the incident channel.

# .github/workflows/fieldguide.yml
name: fieldguide
on: [pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install pyyaml
      - run: python fieldguide.py --workload workloads/checkout.yaml --fail-on block
Enter fullscreen mode Exit fullscreen mode

Where a free tier does earn its place

Refusal is not the whole story. Low-stakes lanes are the right home for shared infrastructure. Internal tools, demo servers, prototype spikes, and test fixtures qualify. The cost of a bad response stays inside the team that asked for it.

MonkeyCode is one option in that space. Its project offers free model access and a free server option, per the operator's description. Quotas and terms change; read the project page instead of a blog post, this one included.

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

When a lane is adopted, write the exit signal first. The catalog above still applies. Internal tools can graduate into customer paths without anyone editing a document.

What the linter cannot do

Be honest about the ceiling.

  • Tag matching is coarse. A mislabeled manifest defeats every rule.
  • Data class is declared by a human, not discovered by the tool.
  • The script judges intent, not runtime behavior. It is not a security control.
  • A passing verdict is the start of a review, not the end of one.

Every block needs a human sign-off with a name attached. A file that nobody owns will drift within a quarter.

Who should skip this approach

Some teams should not adopt the catalog yet.

  • Teams handling regulated data without an approved environment for it.
  • Teams without a named owner per workload.
  • Teams already running more CI jobs than they can maintain.
  • Teams that want a scoring model instead of a decision.

Those teams need an inventory first. A refusal list without owners is decoration.

The point of writing refusals down

The catalog costs an afternoon and saves arguments later. It records why a workload stays off a shared lane. It gives reviewers a link instead of an opinion. If one lane survives the catalog, run it there for a week and record what broke.

Top comments (0)