The Other Half of the 90-Minute Spike: Does the Free Server Match Your CI?
Most free-tier spikes fail on drift, not on model quality. The agent wrote a correct patch. The host could not run it. That is an environment bug. You can find it in 90 minutes. The rule: fingerprint both sides before
Most free-tier spikes fail on drift, not on model quality.
The agent wrote a correct patch. The host could not run it.
That is an environment bug. You can find it in 90 minutes.
The rule: fingerprint both sides before you prompt anything.
One hypothesis, written before the timer starts
A spike without a falsifiable sentence is a demo. Demos always pass.
Write exactly one line:
A patch produced on the free server passes the same five-command contract test as local CI.
Commit that line to a file in your repo. Now you cannot move the goalposts later.
Why drift is the interesting failure
Model quality shows up as a bad diff. You see it in review.
Drift shows up as a bad host. You see it 40 minutes later, as EACCES.
Drift is cheaper to measure and more expensive to ignore.
Pre-register the thresholds
Write these numbers down before you touch the server. Fill the observed column last.
| Metric | Pre-registered threshold | Observed |
|---|---|---|
| Time to first green contract test | โค 25 min | |
| Fingerprint fields that differ | โค 2 | |
| Repair time per drift field | โค 10 min | |
| Files touched by environment fixes | โค 3 | |
| Review cost vs local baseline | โค 1x |
Two rules keep this honest.
- Thresholds are written first, in the same commit as the hypothesis.
- Any change to a threshold is a new spike on a new day.
The 90-minute budget
| Minutes | Activity | Output |
|---|---|---|
| 0โ5 | Hypothesis and thresholds |
spike/ledger.json committed |
| 5โ20 | Fingerprint local | local.json |
| 20โ40 | Fingerprint server, diff | drift.diff |
| 40โ65 | One real patch, timed | timing.txt |
| 65โ80 | Fill the ledger | Facts, no opinions |
| 80โ90 | Verdict |
ship or kill
|
When the timer ends, the spike ends. A partial ledger is still a result.
Step 1: fingerprint both environments
The script below is a template. I have not run it against your machines.
#!/usr/bin/env bash
# drift.sh - capture an environment fingerprint
set -euo pipefail
OUT="${1:-fingerprint.json}"
row() { printf ' "%s": "%s",\n' "$1" "$2"; }
{
printf '{\n'
row os "$(uname -srm | tr '"' "'")"
row node "$(node -v 2>/dev/null || echo missing)"
row python "$(python3 -V 2>&1 | awk '{print $2}' || echo missing)"
row lock "$(sha256sum package-lock.json 2>/dev/null | cut -c1-16 || echo none)"
row tz "$(cat /etc/timezone 2>/dev/null || date +%Z)"
row locale "${LANG:-unset}"
row cores "$(nproc 2>/dev/null || echo unknown)"
row mem_mb "$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null || echo unknown)"
printf ' "_end": "ok"\n}\n'
} > "$OUT"
echo "wrote $OUT"
Run it on both hosts. Then diff the JSON, not the vibes.
./drift.sh local.json
ssh <free-server> 'bash -s' < drift.sh > server.json
diff <(jq -S 'del(._end)' local.json) <(jq -S 'del(._end)' server.json) | tee drift.diff
A thirteen-line diff is a finding. A missing node is a kill signal.
Step 2: one contract test, five commands, both hosts
Use the same commands, in the same order, on both machines.
set -e
npm ci --no-audit --no-fund
npm run lint
npm test -- --runInBand
git status --porcelain # must print nothing
node -e 'console.log(process.version)'
Do not add || true. Do not skip npm ci.
The last two commands catch the quiet failures. Dirty checkouts and version drift.
Step 3: one patch, timed, not five
Pick a real ticket from your backlog. Toy functions hide environment bugs.
/usr/bin/time -f '%e s wall, %M KB peak' \
npm test -- --runInBand 2> timing.txt
cat timing.txt
Record three numbers: time to first run, time to first green run, time to review.
Review time is the one people forget. Ask a colleague to read the diff cold.
The ledger
{
"hypothesis": "A patch produced on the free server passes the local five-command contract test.",
"thresholds": { "green_minutes": 25, "max_drift_fields": 2, "max_repair_minutes_per_field": 10 },
"observed": {
"green_minutes": null,
"drift_fields": null,
"repair_minutes_total": null,
"review_minutes": null
},
"verdict": null,
"next_review_date": "2026-12-07"
}
Nulls are permitted entries. Guesses are not.
How to read the verdict
| Drift fields | Repair time | Verdict |
|---|---|---|
| 0 | any |
ship โ server becomes primary |
| 1โ2 | โค 10 min each |
ship with pins โ codify fixes |
| 1โ2 | > 10 min each |
defer โ pin first, re-spike |
| 3+ | any |
kill โ do not chase it |
| any | green > 25 min |
kill โ the loop is too slow |
defer is not a soft ship. It has a date and an owner, or it is a kill.
Where the free tier fits this worksheet
MonkeyCode is presented by its maintainers as an open-source coding-agent project.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Two operator-supplied availability claims matter for this spike. Free model access and a free server option.
The quota is reported as roughly 10 million free tokens at the time of writing (2026-11-07). Treat that as a moving number, not a contract, and check the project page before you plan around it. Free allowances change.
Why this fits the drift test: the test needs a second host. A second host is the expensive part of the experiment.
Why free models are sufficient here: you grade the patch with npm test, not with prose. The contract test is the judge.
One practical note. Record the model name and the quota snapshot in your ledger. A spike with an unrecorded variable is a memory.
If you want a second host for this worksheet, run the drift step on MonkeyCode's free server and keep the ledger in your repo either way.
Limitations
- Availability and quotas can change without notice. Re-run the spike monthly.
- A free host is not your production host. Passing drift does not prove production parity.
- Fingerprints cover language runtimes and lockfiles, not kernel behavior or syscalls.
- Single-patch timings are noisy. Treat one run as one data point, not a benchmark.
- Secrets handling on any shared host needs review before you paste a token anywhere.
- Nothing here proves a model is good. It only proves a host is compatible.
Who should not use this approach
- Teams handling regulated or customer data on a host they have not reviewed.
- Repos with native toolchains, GPU builds, or long compile steps.
- Monorepos where
npm cialone exceeds ten minutes. - Anyone who will not re-run the spike when the free terms change.
For those teams, a pinned devcontainer is the cheaper answer.
What a kill verdict buys you
You spent 90 minutes. You avoided a month of intermittent CI failures.
Keep the fingerprint script. It is reusable on every new host.
Pin the drift fields in a devcontainer and re-spike next month.
Short spikes, written thresholds, recorded verdicts. That beats a lucky demo.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes โ full credit and traffic to the original publisher.