以腳本檢查範圍預算,控制週末 AI 示範專案
A Machine-Checked Scope Budget for One-Weekend AI Demos
文章提出一套控制週末 AI 示範專案範圍的方法,以可執行的黃金路徑冒煙測試、可由腳本否決的工時預算和預先制定的刪減表,限制計劃擴張。示例把預算設為 12 小時,限制必做項目最多 4 項、每項最多 3 小時;延後項目則須列明重新納入的觸發條件。作者提醒,涉及真實用戶、憑證或受監管資料的產品,不應採用這種缺少身份驗證和資料持久化的示範級設定。
A Machine-Checked Scope Budget for One-Weekend AI Demos
The demo ships or it does not. What decides which is a file, not an intention.
Weekend AI side projects usually fail at the same place: the plan grows faster than the clock. A single-path demo needs a much smaller surface than most people budget for, and that surface has to be enforced by something other than willpower at 11 p.m. on Sunday.
The pattern below uses three artifacts: a golden-path smoke test, a scope budget that a script is allowed to veto, and a cut table that decides in advance what gets deleted rather than deferred. The running example is a small "summarize one file into a changelog stub" service with exactly one model call in the path.
MonkeyCode's free model access and free server option are relevant here for one narrow reason: they remove two classic weekend sinks, key provisioning and deploy plumbing. The pattern itself is independent of any provider. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Rule one: the golden path is a command, not a paragraph
Write the demo as one shell command that either exits 0 or exits non-zero. If the golden path cannot be expressed as a command, the scope is not yet small enough to start.
#!/usr/bin/env bash
# smoke.sh - the golden path end to end, no mocks, no manual steps
set -euo pipefail
BASE_URL="${BASE_URL:-http://localhost:8080}"
FIXTURE="${FIXTURE:-fixtures/tiny_repo.txt}"
OUT="$(mktemp)"
# 1. the service is up and self-reports
curl -fsS --max-time 5 "$BASE_URL/health" | grep -q '"status":"ok"'
# 2. one real request against a frozen fixture
curl -fsS --max-time 45 -X POST "$BASE_URL/summarize" \
-H 'content-type: text/plain' \
--data-binary "@$FIXTURE" \
-o "$OUT"
# 3. the response is markdown with a heading, not an error page
grep -q '^## ' "$OUT" || { echo "FAIL: no markdown heading"; exit 1; }
grep -qi 'summary' "$OUT" || { echo "FAIL: no summary section"; exit 1; }
echo "GOLDEN PATH OK ($(wc -c <"$OUT") bytes)"
The important property is that step 2 crosses a real network boundary. A smoke test that stubs the model call proves nothing about the demo, because the model call is the part most likely to break during a live walkthrough.
Rule two: the plan is a file a script can reject
Scope creep is easier to catch as a validation error than as a feeling. Put the whole weekend in weekend.yml, then let a small checker refuse plans that cannot fit.
# weekend.yml - the plan the checker is allowed to veto
budget_hours: 12
golden_path:
name: "summarize one file into a changelog stub"
must_pass_by: "sunday 20:00"
items:
- id: read-fixture
hours: 1
tier: must
- id: model-call
hours: 2
tier: must
- id: render-markdown
hours: 2
tier: must
- id: deploy-hosted
hours: 1
tier: must
- id: auth
hours: 4
tier: later
tripwire: "only if the demo needs more than one user"
- id: history-db
hours: 6
tier: later
tripwire: "only if a reviewer asks for past runs"
- id: settings-ui
hours: 5
tier: later
tripwire: "only if a config value must be edited by a non-developer"
#!/usr/bin/env python3
"""scope-check.py - reject the plan before the weekend rejects it."""
import sys
import yaml # pip install pyyaml
MAX_MUST_ITEMS = 4
MAX_MUST_HOURS_PER_ITEM = 3
def load(path):
with open(path, encoding="utf-8") as fh:
return yaml.safe_load(fh)
def check(plan):
problems = []
budget = plan["budget_hours"]
musts = [i for i in plan["items"] if i["tier"] == "must"]
must_hours = sum(i["hours"] for i in musts)
if must_hours > budget:
problems.append(f"must items need {must_hours}h, budget is {budget}h")
if len(musts) > MAX_MUST_ITEMS:
problems.append(f"{len(musts)} must items; the ceiling is {MAX_MUST_ITEMS}")
for item in musts:
if item["hours"] > MAX_MUST_HOURS_PER_ITEM:
problems.append(
f"must item '{item['id']}' is {item['hours']}h; split or demote it"
)
for item in plan["items"]:
if item["tier"] != "must" and not item.get("tripwire"):
problems.append(f"deferred item '{item['id']}' has no tripwire")
return problems
def main():
path = sys.argv[1] if len(sys.argv) > 1 else "weekend.yml"
problems = check(load(path))
if problems:
print("SCOPE CHECK FAILED")
for problem in problems:
print(f" - {problem}")
return 1
print("SCOPE CHECK PASSED")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Example transcript for the plan above:
$ python3 scope-check.py weekend.yml
SCOPE CHECK PASSED
$ python3 scope-check.py weekend.yml # after adding a 4h 'oauth' must-item
SCOPE CHECK FAILED
- must items need 13h, budget is 12h
- must item 'oauth' is 4h; split or demote it
The tripwire requirement matters more than the hour math. A deferred item with a written tripwire has a condition for returning; a deferred item without one is just a wish that will resurface mid-demo.
Rule three: keep one network dependency in the path
Each additional service in the golden path multiplies the number of things that can be down at demo time. In this build, the path has exactly two: the app host and the model endpoint.
The request shape below is a sketch, not a verified contract. Endpoint paths and model identifiers change between releases, so read the project's current documentation instead of copying a blog snippet, including this one.
# shape sketch: confirm base URL and model id against current docs
export MC_BASE="${MC_BASE:?set from docs}"
export MC_MODEL="${MC_MODEL:?set from docs}"
curl -fsS --max-time 45 "$MC_BASE/chat/completions" \
-H "authorization: bearer $MC_TOKEN" \
-H 'content-type: application/json' \
-d "$(jq -n --arg m "$MC_MODEL" --rawfile f fixtures/tiny_repo.txt \
'{model:$m,messages:[{role:"user",content:("Summarize as markdown:\n" + $f)}]}')"
Two properties are worth copying regardless of provider. First, the model identifier lives in an environment variable, so switching providers is a config change rather than a code change. Second, every model call has a wall-clock timeout shorter than the smoke test's patience, so a hung request fails loudly instead of stalling a walkthrough.
Gate the whole thing behind one command and run it before every rehearsal:
check:
python3 scope-check.py weekend.yml
./smoke.sh
The cut table
Decisions get easier when the response to a scope item is chosen by rule instead of by mood.
| Signal | Action | Reason |
|---|---|---|
| Item is not on the golden path | Delete it | Deferral keeps the cost in the plan |
| Must-item exceeds 3 hours | Split or demote | Long must-items are where weekends die |
| Requires a second stateful service | Stub it with a file or constant | A database is a second failure domain |
| Requires a secret that is not on hand | Replace with a public fixture | Provisioning is not demo work |
| Only improves visual polish | Skip, and log it | Polish is the first thing viewers forgive |
| Triggered by a real reviewer question | Re-promote to must | Evidence beats aesthetics |
What this weekend skipped, on purpose
- Authentication. The demo runs as a single anonymous user. Multi-user auth was deferred with a concrete tripwire rather than half-built.
- Persistence. Results are not stored. A file-backed stub would have added a migration story and a second failure mode.
- A settings interface. Configuration stays in environment variables, which is honest about who the demo is for.
- Model comparison. One model, one prompt, one output shape. Comparing providers is a separate project with its own budget.
- Streaming output. The response arrives whole. Streaming is a latency feature, and the demo has no latency claim to defend.
- Test coverage beyond the golden path. Unit tests exist where they were cheap; the smoke test is the gate.
Recent community discussion has been heavy on AI fatigue, and this cut list is the practical response to it. A smaller AI surface is easier to defend to a reader, a reviewer, or a future maintainer.
Limits, and who should not copy this
- The scope checker validates a plan, not a product. It cannot tell whether the golden path is worth building.
- A 12-hour budget suits a single developer with a known stack. Teams coordinate more than they code, so the numbers do not transfer.
- Anything with real users, credentials, or regulated data should not run on a demo-grade setup with no auth and no persistence.
- Free-tier availability, allowances, and server specifications are set by the provider and change over time. Verify current terms on the project's own pages before planning around them, and do not treat a free tier as a production SLA.
- If verification is impossible for a given claim, remove the claim instead of softening it. The scripts above are the only parts that need to be true for the pattern to work.
Closing
A weekend side project succeeds when the golden path runs, the plan is small enough to enforce, and the skipped list is written down. The checker and the smoke test take under an hour to write and they pay for themselves the first time a demo survives a rehearsal it should have failed.
If the free model access or the free server option is what decides whether the weekend happens at all, read the project's current terms first, then start from the smoke test rather than from the feature list. The repository is open source, so the fastest way to verify any capability claim is the source itself.
來源:DEV Community · dev.to