AI & ML
Weekend Build Log: The Timeout Is the Product
Riley Zhang DEV Community
7 views
You sit down Saturday with one failing test file. The stack trace is ugly and long. You want a tiny helper that groups those failures.
Ninety minutes later you are still retrying a model. The helper never became a demo. The weekend dissolved into another chat.
This log cuts that loop. You freeze three files. You wrap the run in a timeout. You write a receipt. Then you stop.
The Saturday trap
You do not lack ideas on Saturday morning. You lack a stop rule. Chat tools invite one more retry.
Each retry feels cheap in the moment. The clock still moves. The demo stays imaginary.
Treat the timeout as the product. If the job misses the window, it failed. You ship the failure, not another prompt tweak.
Cut the job to one verb
Pick one verb before you open an editor. Group. Summarize. Rank. Stop there.
Write the verb on a sticky note. If a second verb appears, it waits. Sunday is not a second product.
Here is a tight job statement you can reuse.
Job: group pytest failures by file path.
Input: tests/last-run.txt
Output: groups.json
Limit: 90 seconds wall clock.
That statement is the scope cut. Everything else is skip work.
Freeze three files first
Do not start inside a chat window. Create three files on disk. They outlive the session.
job.md holds the verb, input, and output.
prompt.txt holds the only instruction you will send.
budget.yaml holds time, retries, and output path.
Keep those files boring. Boring files survive Saturday better than clever agents.
# budget.yaml
job: group-failures
wall_clock_seconds: 90
max_attempts: 1
input: tests/last-run.txt
output: groups.json
receipt: receipts/saturday.json
max_attempts: 1 is the point. A second attempt is a new weekend.
Label this layout as a proposal until you run it. Do not fake a green build.
Put a kill switch on the process
Unix already ships the feature. Use timeout. Do not write a scheduler.
mkdir -p receipts tests
cat > tests/last-run.txt << 'EOF'
FAILED tests/test_api.py::test_timeout
FAILED tests/test_api.py::test_retry
FAILED tests/test_auth.py::test_expired_token
EOF
timeout 90s python3 group_failures.py \
--input tests/last-run.txt \
--output groups.json \
--receipt receipts/saturday.json
echo "exit:$?"
Exit 124 means the clock won. That is a valid demo. Write it down.
Do not catch that exit and retry. Retry is how Saturday dies.
Write a receipt after every run
A chat log is not evidence. A receipt file is. You want four fields only.
# group_failures.py
# Proposed weekend helper. Run it locally before you trust it.
from __future__ import annotations
import argparse
import json
import time
from collections import defaultdict
from pathlib import Path
def group_lines(raw: str) -> dict[str, list[str]]:
groups: dict[str, list[str]] = defaultdict(list)
for line in raw.splitlines():
line = line.strip()
if not line.startswith("FAILED "):
continue
body = line[len("FAILED "):]
path = body.split("::", 1)[0]
groups[path].append(body)
return dict(groups)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--input", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("--receipt", required=True)
args = parser.parse_args()
started = time.time()
source = Path(args.input)
grouped = group_lines(source.read_text(encoding="utf-8"))
Path(args.output).write_text(
json.dumps(grouped, indent=2) + "\n",
encoding="utf-8",
)
receipt = {
"job": "group-failures",
"seconds": round(time.time() - started, 3),
"input": args.input,
"output": args.output,
"groups": len(grouped),
"timed_out": False,
}
receipt_path = Path(args.receipt)
receipt_path.parent.mkdir(parents=True, exist_ok=True)
receipt_path.write_text(json.dumps(receipt, indent=2) + "\n")
print(receipt_path.read_text(), end="")
return 0
if __name__ == "__main__":
raise SystemExit(main())
The script does no model call. That is the scope cut talking. You can add a model later. You may not need one.
Make the demo one command
Your demo is not a UI. Your demo is a command a friend can paste.
python3 group_failures.py \
--input tests/last-run.txt \
--output groups.json \
--receipt receipts/saturday.json
cat groups.json
cat receipts/saturday.json
Expected groups.json looks like this.
{
"tests/test_api.py": [
"tests/test_api.py::test_timeout",
"tests/test_api.py::test_retry"
],
"tests/test_auth.py": [
"tests/test_auth.py::test_expired_token"
]
}
If those two files exist, the weekend shipped. If they do not, you failed closed. Either result is honest.
Decision table for the next hour
Use this table when the helper feels small. Small is the goal.
Urge
Do this
Skip this
Add retries
Keep max_attempts: 1
Sleep loops
Add a web page
Print groups.json
Flask, auth, CSS
Add a model
Freeze prompt.txt first
Agent memory
Add flags
Keep three flags
Config frameworks
Miss the timeout
Commit the receipt
"One more run"
Read the skip column twice. That column is the build.
When a free model is actually useful
Sometimes the grouping rule is messy. Regex will lie. A short model pass can draft group_lines.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
MonkeyCode is relevant here only as a place with free model access and a free server option. Use those two things to draft the helper. Then run the same timeout on the result. Do not turn the server into a chat room.
Keep the model outside the kill switch at first. Generate group_failures.py once. Paste it into git. Run timeout 90s against the file you saved. If the draft needs a second generation, that is Sunday work.
Do not invent extra surfaces around that draft. No dashboard. No plugin. No background worker. The receipt still decides whether the hour counted.
If you try MonkeyCode for this gate, keep the same three files. The product should not replace budget.yaml.
What you skip on purpose
Write the skip list in job.md. A skip list is part of the demo.
No retry loop around the model.
No extra libraries for HTTP or agents.
No UI beyond stdout and two JSON files.
No streaming tokens into a log you will never read.
No "memory" file that grows every run.
You already published helpers that refuse extra flags. This log is different. The clock is the contract. The receipt is the proof.
A five-step Saturday checklist
Follow the order. Do not reorder under stress.
Write job.md with one verb only.
Freeze prompt.txt and budget.yaml.
Implement the smallest local function.
Run it under timeout 90s.
Commit groups.json plus the receipt.
If step 4 fails, commit the failure receipt. Then close the laptop. That is still a shipped weekend.
Limitations
This gate is blunt. Blunt tools miss nuance. A ninety-second wall clock cannot see queue delay.
The sample script only groups FAILED lines. Real pytest output is richer. You will need more parsing later.
A free model draft can still be wrong. The timeout will not catch logic bugs. It only catches hangs.
A free server option does not remove your review duty. You still read the diff. You still own the exit code.
Do not treat this article as a benchmark. No latency numbers were claimed. No quota numbers were claimed. No model names were claimed.
Who should not use this
Do not use this if you are paging production at 2am. On-call work needs a real runbook.
Do not use this if your job needs multi-step tools. A single timeout will starve that design.
Do not use this if you cannot freeze the prompt. If stakeholders change the verb hourly, the receipt lies.
Do not use this if you need a hosted UI today. You will overbuild before lunch.
Close the weekend
You started with a noisy test file. You end with two JSON files and a clock. That is enough product for Saturday.
Keep the kill switch in the Makefile. Keep the skip list in git. Let Monday argue with the receipt, not with your memory.
Read original: https://dev.to/hackgo_6978/weekend-build-log-the-timeout-is-the-product-3bpj
Related
Comments0
No comments yet — be the first