You sit down on Saturday at 9:12.
The task looks tiny on paper.
Parse one custom header from a log line.
You paste the file into a chat window.
The model rewrites three unrelated modules.
It adds a packaging dependency you never requested.
Your original test still fails on the header.
You close the tab and start over.
The model is not the weekend problem.
An unbounded patch is the weekend problem.
Side projects die when the diff explodes.
You need a budget before any model call.
The real constraint
You do not need a better prompt tonight.
You need a gate that can say no.
A forty-line cap keeps the demo honest.
A required test name keeps the patch on task.
This is not a product launch.
This is a Saturday scope cut.
You will ship a checker, not a platform.
The commands below are a proposed weekend workflow.
Run them locally before you trust the gate.
What you keep
Keep one failing test under tests/.
Keep one function in src/header.py.
Keep a hard cap of forty changed lines.
Keep a forbid list for docs and lockfiles.
That list is the whole weekend product.
You are not building an agent.
You are not building a review bot.
You are building a cheap reject path.
Cheap reject paths save Saturday afternoons.
What you skip
Skip chat history and follow-up turns.
Skip whole-repository context dumps.
Skip "make this production ready."
Skip new third-party dependencies.
Skip README rewrites and extra files.
Skip a web UI and an agent loop.
The demo is one Makefile target.
Stdout from the gate is enough proof.
If a step needs a second prompt, cut it.
If a step needs a new library, cut it.
If a step needs a dashboard, cut it.
Weekend scope is a deletion exercise.
Frozen contract
Write these three checks before any call.
- The patch must mention
test_parse_x_request_id. - Added plus removed lines must stay under 40.
- Paths outside
src/andtests/are rejected.
If any check fails, you discard the patch.
You do not negotiate with the output.
The budget is the product this weekend.
Oral rules will not survive lunch.
Why forty lines
Forty lines is not a scientific constant.
It is a Saturday constraint you can count.
A header parser should fit in that budget.
If it cannot fit, the task is still too big.
Count added lines and removed lines together.
A rewrite can hide inside a deletion.
A rename can hide inside a tiny add.
The gate must see both directions.
Do not raise the cap mid-session.
Raising the cap is how the rewrite sneaks back.
Sunday can change the number.
Saturday cannot.
Step 1: Write the failing test first
Create the smallest test you can stand.
Name the test like a contract, not a novel.
# tests/test_header.py
from src.header import parse_x_request_id
def test_parse_x_request_id():
line = "GET / 200 x-request-id=abc-123"
assert parse_x_request_id(line) == "abc-123"
Run it once before you touch a model.
python -m pytest tests/test_header.py -q
You want a red result on purpose.
Green tests invite the model to wander.
A named failure pins the weekend goal.
If pytest cannot collect the test, stop.
Fix the harness before any generated patch.
Step 2: Stub the tiny source file
Keep the source honest and empty.
Do not pre-write a clever parser.
# src/header.py
def parse_x_request_id(line: str) -> str:
raise NotImplementedError("weekend: implement only this function")
The model may only fill this hole.
Anything else should fail the budget.
A stub also makes revert trivial.
git checkout -- src/header.py is your undo.
Step 3: Freeze the budget file
Put numbers in a file, not a chat.
Chat limits evaporate after one scroll.
# budget.txt
max_lines=40
required_test=test_parse_x_request_id
allow_prefix=src/,tests/
You will read this file in the gate.
You will not "remember" the limits.
Weekend rules die when they stay oral.
Commit budget.txt with the failing test.
The contract should move with the code.
Step 4: Build a local patch gate
This script is the original artifact.
It does not call a model by itself.
It only accepts or rejects a unified diff.
# tools/diff_budget.py
from pathlib import Path
import sys
def load_budget(path: Path) -> dict:
data = {}
for raw in path.read_text().splitlines():
line = raw.strip()
if not line or line.startswith("#"):
continue
key, value = line.split("=", 1)
data[key.strip()] = value.strip()
data["max_lines"] = int(data["max_lines"])
data["allow_prefix"] = tuple(
p.strip() for p in data["allow_prefix"].split(",") if p.strip()
)
return data
def parse_diff(diff: str) -> tuple[int, list[str]]:
total = 0
files: list[str] = []
for line in diff.splitlines():
if line.startswith("+++ b/"):
files.append(line[6:])
elif line.startswith("+") and not line.startswith("+++"):
total += 1
elif line.startswith("-") and not line.startswith("---"):
total += 1
return total, files
def main() -> int:
budget = load_budget(Path("budget.txt"))
diff = sys.stdin.read()
total, files = parse_diff(diff)
errors = []
if budget["required_test"] not in diff:
errors.append(f"missing {budget['required_test']}")
if total > budget["max_lines"]:
errors.append(
f"diff has {total} lines, cap is {budget['max_lines']}"
)
for name in files:
if name == "/dev/null":
continue
if not name.startswith(budget["allow_prefix"]):
errors.append(f"forbidden path: {name}")
if errors:
print("REJECT")
print("\n".join(errors))
return 1
print("ACCEPT")
print(f"lines={total} files={files}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Save a sample patch and run the gate.
python tools/diff_budget.py < sample.patch
echo $?
Exit code 1 means you throw the patch away.
Exit code 0 means you may apply it.
No third status exists this weekend.
Warnings without an exit code are theater.
Step 5: One model call, or a stub
Do not open a chat window.
Write a request file with one job.
# request.txt
Implement parse_x_request_id in src/header.py.
Keep tests/test_header.py as the only test.
Return a unified diff only.
Do not touch README or dependencies.
Stay under forty changed lines.
If you have no host yet, use a stub.
The stub proves the Makefile path.
# tools/stub_patch.sh
cat << 'EOF'
--- a/src/header.py
+++ b/src/header.py
@@ -1,3 +1,8 @@
def parse_x_request_id(line: str) -> str:
- raise NotImplementedError("weekend: implement only this function")
+ marker = "x-request-id="
+ if marker not in line:
+ raise ValueError("missing header")
+ return line.split(marker, 1)[1].split()[0]
EOF
Point the same target at a real host later.
Keep request.txt unchanged when you switch.
The host is not the weekend lesson.
The reject path is the weekend lesson.
When you need a hosted model, MonkeyCode can sit behind that same target. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Free model access and a free server option are enough for this workflow. Treat them as an optional backend for request.txt. Do not add a vendor dashboard to Saturday's demo.
Leave the URL in an environment variable.
Do not hard-code a host into the gate.
The gate should not know who wrote the diff.
# proposed later swap, not required today
# curl -sS "$MODEL_URL" --data-binary @request.txt > /tmp/weekend.patch
That line is labeled on purpose.
Do not invent a vendor payload for it.
If the variable is empty, keep the stub.
Step 6: Wire a single Makefile target
One target. One happy path. One stop.
.PHONY: weekend
weekend:
python -m pytest tests/test_header.py -q || true
./tools/stub_patch.sh > /tmp/weekend.patch
python tools/diff_budget.py < /tmp/weekend.patch
git apply --check /tmp/weekend.patch
Run one command. Then stop.
chmod +x tools/stub_patch.sh
make weekend
If the gate rejects, you do not apply.
If git apply --check fails, you do not apply.
You do not "just this once" raise the cap.
The Makefile is the demo script.
People can replay it without a tour.
Failure analysis: a bad patch
Here is a patch the gate should kill.
Study the reject reasons before you relax rules.
--- a/src/header.py
+++ b/src/header.py
@@ -1,3 +1,20 @@
+import json
+import os
def parse_x_request_id(line: str) -> str:
- raise NotImplementedError("weekend: implement only this function")
+ return os.environ.get("REQUEST_ID", json.dumps(line))
--- a/README.md
+++ b/README.md
@@ -1,1 +1,30 @@
-# header toy
+# Production-ready header platform
Run it through the same command.
python tools/diff_budget.py < bad.patch
You should see REJECT.
You should see a missing test name.
You should see a line-count failure.
You should see forbidden path: README.md.
Three failures beat one vague "looks off."
Notice the source change also drifted.
It stopped parsing the log line.
It started reading an environment variable.
The required test name would have caught that drift.
Even a comment-only mention is a weak signal.
You still read the patch before apply.
The gate is a filter, not a reviewer.
Decision table
| Signal | Action | Why |
|---|---|---|
| Missing test name | Reject | The patch left the weekend goal |
| More than 40 lines | Reject | Unbounded diffs hide extra work |
File outside src/ and tests/
|
Reject | Docs and lockfiles are out of scope |
git apply --check fails |
Reject | The patch is not even applyable |
| Pytest still red after apply | Revert | The budget is not a quality prize |
| Pytest green and gate green | Stop | The demo is done |
Print this table near your desk.
The table beats another prompt tweak.
If you cannot name the action, you are improvising.
Improvisation is how Saturday becomes a rewrite.
Apply, verify, and keep an undo
Only after ACCEPT, try a checked apply.
git apply --check /tmp/weekend.patch && git apply /tmp/weekend.patch
python -m pytest tests/test_header.py -q
If you are still exploring, revert at once.
git checkout -- src/header.py
The last line matters on a Saturday.
You should undo the demo in one command.
A weekend demo that cannot revert is a trap.
Keep generated patches out of main until green.
A file in /tmp is a feature, not a mess.
Limitations
This gate does not prove the code is safe.
It does not catch logic bugs or injections.
It does not replace a human code review.
Forty lines can still contain harm.
The required test name can be faked in comments.
You should read the patch before git apply.
The stub is not a benchmark.
No latency numbers belong in this log.
No model ranking belongs in this log.
Switching hosts must not change the budget.
If a host cannot return a unified diff, skip it.
Do not weaken the gate to flatter a backend.
Line counting is also crude.
Binary files will confuse the parser.
Rename-heavy diffs can look huge.
That is acceptable for this toy.
A header parser should not rename the tree.
Who should not use this
Do not use this for a production incident.
Do not use this for auth or crypto changes.
Do not use this for a multi-package refactor.
Do not use this if review bots already exist.
Do not use this to generate a full application.
Juniors still need a human to read the diff.
The cap is a scope tool, not a skill substitute.
If your real task needs twenty files, stop.
Split the task until one file is enough.
If you cannot split it, this workflow is wrong.
Wrong tools waste a weekend faster than no tools.
What done means Saturday
Done means the failing test is now green.
Done means the gate printed ACCEPT.
Done means you did not touch the README.
Done means you stopped after one pass.
If you still want a UI, wait until next week.
The interesting part is the reject path.
A model that cannot fail your budget is not helping.
Cap the diff before you call anything.
Then ship the tiny parser and go outside.
Top comments (0)