DEV Community

Dakota Wu
Dakota Wu

Posted on

Cap Repair Attempts Before a Free Server Restarts

A solo route keeps a zero bill only when each model repair has a local attempt ceiling and a frozen process set. An agreeable patch that adds a listener, a worker, or a second runtime is a failed deploy, not a green check. The workflow below is a local gate for that failure. It does not read a vendor dashboard, and it does not require a paid host.

Free model access makes the loop easier to start. Each retry looks cheap until the free server is restarting a process the original route never declared. The gate records attempts on disk, refuses a wider surface, and stops the loop before the host becomes a second product.

What the gate protects

The protected unit is one process, one port, and one deploy command. Health checks, billing agents, and background trainers stay outside that unit. Patterns that pin a waitlist byte ceiling, or that keep probes off a model, solve different failures. This gate only answers whether another repair attempt is still allowed on the same change.

Two files hold the contract. surface.json freezes the command, the port, and the paths the route may touch. attempts.json counts repair rounds for one change id. Both files live in the repo. Neither file calls a model.

Numbered workflow

  1. Freeze the surface before any model call. Write the binary name, the listen port, and the paths the route may touch. Commit that file with the route, not after the first failure.
  2. Assign a change id. A short slug plus the calendar date is enough. Reuse of an id continues the same attempt count, including across a laptop sleep or a free-host restart.
  3. Request one patch for that change id. Store the raw suggestion next to the attempt record. Do not apply it, and do not restart the host, until the gate exits zero.
  4. Run the local gate. The gate rejects a suggestion that names a forbidden worker, binds a port other than the frozen port, edits a path outside the freeze, or claims success without an assertion.
  5. Apply only a suggestion that passes. Restart the single process named in the surface file. Record the process exit status beside the change id.
  6. Stop when the attempt count hits the ceiling, even if the next suggestion sounds more confident than the last. Ship the last known-good tree, or revert the change id entirely.

The ceiling in the example is three attempts. That number is a local policy chosen for a solo afternoon. It is not a vendor quota, and it is not a measured optimum. Operators who need a longer investigation should edit the constant in the repo, not bury a higher number in a prompt.

Surface file

The freeze is small enough to review by eye. Forbidden markers name libraries that imply a second runtime. The port field is the only listen target the suggestion may mention.

{
  "change_id": "route-quote-2026-10-13",
  "command": ["python3", "app.py"],
  "port": 8080,
  "allowed_paths": ["app.py", "tests/test_quote.py"],
  "forbidden_markers": ["celery", "gunicorn", "rq.Worker", "multiprocess"]
}
Enter fullscreen mode Exit fullscreen mode

A comment that explains why gunicorn is absent can false-positive if the word appears in the diff. That is acceptable for a first gate. A false reject costs one edit. A false accept costs an extra process on a host that was chosen because the bill had to stay at zero.

Unexecuted gate

The script is a proposal. It has not been executed against a live host for this draft. It reads the two JSON files, scores the suggestion, and exits non-zero when the repair must stop. It opens no socket.

#!/usr/bin/env python3
"""Local repair gate. Unexecuted example. No network calls."""
import json
import re
import sys
from pathlib import Path

CEILING = 3
ROOT = Path(".")
surface = json.loads((ROOT / "surface.json").read_text())
attempts = json.loads((ROOT / "attempts.json").read_text())
suggestion = Path(sys.argv[1]).read_text()

def fail(reason):
    print(json.dumps({"ok": False, "reason": reason}))
    raise SystemExit(2)

change_id = surface["change_id"]
count = int(attempts.get(change_id, 0))
if count >= CEILING:
    fail("attempt ceiling reached")

for marker in surface["forbidden_markers"]:
    if marker in suggestion:
        fail("surface widened by marker: " + marker)

found_ports = {int(p) for p in re.findall(r":(\d{2,5})", suggestion)}
extra_ports = found_ports - {int(surface["port"])}
if extra_ports:
    fail("extra ports: " + ",".join(str(p) for p in sorted(extra_ports)))

allowed = set(surface["allowed_paths"])
for line in suggestion.splitlines():
    if not line.startswith("+") or line.startswith("+++"):
        continue
    for token in re.findall(r"[\w./-]+\.py", line[1:]):
        if token not in allowed:
            fail("path outside freeze: " + token)

lower = suggestion.lower()
claims_done = ("all tests pass" in lower) or ("lgtm" in lower)
if claims_done and ("assert " not in suggestion):
    fail("agreeable patch without an assertion")

attempts[change_id] = count + 1
(ROOT / "attempts.json").write_text(json.dumps(attempts, indent=2) + "\n")
print(json.dumps({"ok": True, "attempts": attempts[change_id]}))
Enter fullscreen mode Exit fullscreen mode

Seed the counter as an empty object before the first run. Then point the gate at the saved suggestion.

echo '{}' > attempts.json
python3 repair_gate.py suggestion.diff
echo "gate_exit=$?"
Enter fullscreen mode Exit fullscreen mode

A non-zero status means the host stays on the previous tree. The suggestion remains in the working directory as evidence. It is not the deployed tree.

Known-good snapshot

Before the first model call, record the commit the host is already running. The gate does not create this snapshot. A human does, so a ceiling hit has a place to return.

git rev-parse HEAD > known_good.txt
git status --short
Enter fullscreen mode Exit fullscreen mode

If known_good.txt is empty, the workflow stops. There is no honest revert target, and a free server should not be the place where the only copy of the route lives. Push the known-good commit to the remote the operator already uses, then start the repair loop.

Restart wrapper

The restart is a separate command, and it stays dumb. It refuses to launch when the gate files are missing, and it launches only the command list from the surface file. No shell string is interpolated from the model suggestion.

#!/bin/sh
set -eu
test -f surface.json
test -f attempts.json
python3 - <<'PY'
import json, os
s = json.load(open("surface.json"))
os.execvp(s["command"][0], s["command"])
PY
Enter fullscreen mode Exit fullscreen mode

execvp replaces the shell with the frozen command. A model suggestion cannot append a second binary to that launch path unless a human edits surface.json on purpose. That edit is a new change id, with its own counter at zero, and it should be rare on a free server.

After the process is up, confirm a single listener. If ss is absent on the host, skip the check rather than binding the port from a probe. A probe that binds the live port is a self-inflicted outage.

ss -ltnp | awk 'NR==1 || /:8080/'
pgrep -af 'python3 app.py'
Enter fullscreen mode Exit fullscreen mode

Two matching lines in the process list mean the surface broke. Roll back before asking the model for a story about why both processes are fine.

Decision table

Signal Attempt count Action
Forbidden marker or extra port any, below ceiling Reject the patch. Do not send a retry prompt that says to try again more carefully.
Path outside the freeze below ceiling Reject. Extend allowed_paths only by a human edit, then use a new change id.
Success claim, no assertion below ceiling Reject. Require a failing test that names the bug before another model call.
Gate passes, process exits 0 1 to 3 Record success. Stop calling the model for this change id.
Gate passes, process exits non-zero below ceiling One more model call, same change id, same surface file.
Count already at ceiling 3 Stop. Revert to last known-good. Ship without the repair.

The table is the decision. A fourth suggestion, however specific it looks, is out of policy. Confidence in the prose is not evidence. The assertion, the exit status, and the process list are the evidence.

Where free model access and a free server fit

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

MonkeyCode, as described in the operator brief for this draft, provides free model access and a free server option. Those are availability claims supplied for the article. This draft does not state a token quota, a hardware profile, a retention window, a model name, or a benchmark. Those figures were not verified against a primary source dated with this draft, and an unverified ceiling would be worse than silence.

The fit is narrow. Use the free model access for the single patch call inside the attempt ceiling. Use the free server option only to run the command frozen in surface.json. If either option changes or disappears, the gate still runs, because it never reads a vendor balance. The attempt file in git is the record of how many repairs were spent.

Keep the product out of the runtime. The host process does not import a vendor SDK for this gate. The model is a text source. The server is a place to run one command. Mixing those roles, by letting the model restart itself or open a second port for logs, is how a zero-bill afternoon becomes an unpaid operations shift.

Limitations

The marker scan misses a widened surface written through string concatenation, a new shell script, or a dependency that pulls a worker at import time. The port regex misses a bind written as a split host and port variable. The path check looks at added lines only, so a renamed file can slip through. The agreement check is a phrase list, and a patch can claim success with different wording.

Rejected patches do not increment the ceiling in this sample. The increment sits after the checks. Operators who want every model response to count, including rejects, should move the write above the marker loop. The script does not parse a unified diff properly, does not run the test suite, and does not talk to a host API.

The ceiling of three is arbitrary. A docstring typo may deserve one attempt. A charge, a login, or a deletion bug deserves zero model repairs on a free host, because a wrong side effect is not a style nit.

The gate cannot classify that risk. A human labels the change id before the first call. A dangerous id never enters the loop. Exit status still has to be captured by the operator, because this draft's wrapper replaces the shell and does not write a status file of its own.

Who should skip this

A team with a staging cluster, a review bot, and a paid error budget does not need a three-attempt file. A service that must autoscale, open extra ports, or run a queue should not pretend a one-process freeze is the architecture. Anyone who needs a measured token price, a named model, or an uptime figure should read current primary documentation before picking a host.

This draft is for a solo founder shipping one route today, willing to revert, and unwilling to let an agreeable repair invent a second runtime. The same gate can live in a pre-push hook. Readers comparing hosts can point that single in-policy patch call at MonkeyCode's free model access, keep the restart on the free server option, and treat attempts.json as the only scoreboard that matters.

Top comments (0)