ai newsDi., 20. Okt.
EilmeldungCan we detect harmful AI before it's too late? Researchers search for warning signs

The Free Server Is the Fragile Part: A Runtime Readiness Checklist for Hosted AI Prototypes

Your free-tier prototype does not fail at the model call. It fails at 3 a.m., when the instance has been recycled, the write you thought was durable is gone, and nobody wrote down what "working" was supposed to mean. So write it down. Below is a runtime-readiness checklist you can copy into a repo:

dev.toDienstag 11:55 · 20.10.7 Min. Lesezeit
Bild: dev.to

Your free-tier prototype does not fail at the model call. It fails at 3 a.m., when the instance has been recycled, the write you thought was durable is gone, and nobody wrote down what "working" was supposed to mean.

So write it down. Below is a runtime-readiness checklist you can copy into a repo: explicit claims, one evidence artifact per claim, and a fail-closed rule for every row. Missing evidence is never a pass.

This is the server-side companion to model-allowance checks. The model budget is easy to reason about. The runtime contract is where assumptions quietly rot.

Free hosting is not a smaller version of paid hosting. It is a different failure contract. Watch these four in particular:

None of these are bugs. They are the terms. Your job is to record which ones your app actually depends on.

Every row has three parts. A claim without evidence is BLOCKED, not PASS. That single rule removes most of the self-deception in readiness reviews.

Notice R7. A free server makes rollback more important, not less, because you cannot assume the previous instance is still warm or still addressable.

Here is a stdlib-only Python probe. It writes one JSON file per gate so each row of the table has a named artifact. Copy it, set two env vars, run it. Nothing here is MonkeyCode-specific; it talks to whatever URL you point it at.

# probe_runtime.py -- stdlib only import json, os, sys, time, urllib. request, urllib. error BASE = os. environ [ " TARGET " ]. rstrip ( " / " ) TOKEN = os. environ. get ( " PROBE_TOKEN ", "" ) OUT = os. environ. get ( " EVIDENCE_DIR ", " evidence " ) os. makedirs ( OUT, exist_ok = True ) def call ( path, method = " GET ", body = None, timeout = 60 ): data = json. dumps ( body ). encode () if body is not None else None r = urllib. request. Request ( BASE + path, data = data, method = method ) r. add_header ( " content-type ", " application/json " ) if TOKEN: r. add_header ( " authorization ", " Bearer " + TOKEN ) t0 = time. perf_counter () try: with urllib. request. urlopen ( r, timeout = timeout ) as resp: return resp. status, resp. read (), dict ( resp. headers ), ( time. perf_counter () - t0 ) * 1000 except urllib. error. HTTPError as e: return e. code, e. read (), dict ( e. headers ), ( time. perf_counter () - t0 ) * 1000 except Exception as e: return 0, str ( e ). encode (), {}, ( time. perf_counter () - t0 ) * 1000 def save ( name, obj ): obj [ " recorded_at " ] = time. strftime ( " %Y-%m-%dT%H:%M:%SZ ", time. gmtime ()) with open ( os. path. join ( OUT, name ), " w " ) as f: json. dump ( obj, f, indent = 2 ) print ( name, obj. get ( " result ", obj. get ( " status " ))) # R1: cold start (run this as the first request after an idle window) code, _, _, ms = call ( " /health " ) save ( " cold-start.json ", { " status ": code, " ms ": round ( ms, 1 )}) # R3: duplicate write, same key twice key = " probe- " + str ( int ( time. time ())) for i in ( 1, 2 ): code, _, _, _ = call ( " /state ", " POST ", { " id ": key, " value ": " v%d " % i }) code_r, body, _, _ = call ( " /state/ " + key ) save ( " dup-write.json ", { " status ": code_r, " body ": body [: 200 ]. decode ( " utf-8 ", " replace " )}) # R4: document the payload ceiling instead of guessing it for size in ( 1024, 65536, 1048576, 4194304 ): code, _, _, _ = call ( " /state ", " POST ", { " id ": key + " -sz ", " blob ": " x " * size }) if code >= 400 or code == 0: save ( " payload-limit.json ", { " first_failing_bytes ": size, " status ": code }) break else: save ( " payload-limit.json ", { " first_failing_bytes ": None, " status ": " no-limit-hit " }) # R5: outbound egress to the model endpoint code, body, _, ms = call ( " /generate ", " POST ", { " prompt ": " reply with the word ok " }) save ( " egress.json ", { " status ": code, " ms ": round ( ms, 1 ), " body ": body [: 200 ]. decode ( " utf-8 ", " replace " )}) # R6: header hygiene _, _, headers, _ = call ( " /health " ) with open ( os. path. join ( OUT, " headers.txt " ), " w " ) as f: f. write ( " \n ". join ( " %s: %s " % kv for kv in sorted ( headers. items ()))) print ( " headers.txt " ) Enter fullscreen mode Exit fullscreen mode R2 needs a restart, so it is a two-step manual gate on purpose.

Write a value, recycle the instance from the dashboard, then read it back and store the before/after pair. Automating that would hide the exact moment you are trying to observe.

Do not let a human eyeball this. Twenty lines of code make the fail-closed rule mechanical:

# verdict.py -- PASS only with fresh, complete evidence import json, os, time REQUIRED = [ " cold-start.json ", " state-roundtrip.json ", " dup-write.json ", " payload-limit.json ", " egress.json ", " headers.txt ", " rollback.log " ] TTL_DAYS = { " cold-start.json ": 7, " rollback.log ": 30 } blocked = [] for name in REQUIRED: path = os. path. join ( " evidence ", name ) if not os. path. exists ( path ): blocked. append (( name, " missing " )) continue ttl = TTL_DAYS. get ( name ) age_days = ( time. time () - os. path. getmtime ( path )) / 86400 if ttl and age_days > ttl: blocked. append (( name, " stale: %.1f days " % age_days )) for name, why in blocked: print ( " BLOCKED ", name, " - ", why ) print ( " VERDICT: ", " PASS " if not blocked else " BLOCKED " ) raise SystemExit ( 0 if not blocked else 1 ) Enter fullscreen mode Exit fullscreen mode The exit code matters more than the printout. Wire it into CI as a required check so a deploy cannot skip the gate by forgetting to run it.

A hosted prototype on free model access plus a free server is a genuinely cheap way to run this drill, because both halves of the contract are in play at once: the model path (R5) and the runtime path (R1, R2, R4).

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

Because I cannot verify your deployment from here, treat the free-tier specifics — current token allowance, instance sleep behavior, disk durability, and any hardware details — as things you must read off the project's own current documentation and confirm with the probe. Limits on free offerings change; a number quoted in a blog post is not evidence. That is precisely why R1 and R2 exist as gates rather than footnotes.

Step 2 is the one people skip. A probe run right after a warm deploy measures almost nothing.

Who should not use this approach: teams with a hard sub-second p95 SLA, regulated data-residency requirements, or write paths that must be strictly durable. For those, run the checklist anyway — but expect it to correctly block you, and budget for infrastructure that matches the contract.

If you take one thing away: the row you are most tempted to mark "obviously fine" is the row that will page you. Write the claim, name the artifact, define the fail-closed rule, and let an exit code say no for you. Then the next person who inherits the prototype can read seven files instead of guessing what you knew.

Quelle: dev.to (dev.to). Original öffnen