DEV Community

Charlie Zhu
Charlie Zhu

Posted on

The Sample Coupon Workshop

A maintainer on a small platform team opened the Monday board and found one red parser test sitting between a release note and a hallway argument. A colleague had already pasted the repository into a chat window. The reply came back long, calm, and wrong about a function renamed in March.

The build stayed red. The useful move was smaller than the argument. Cut a sample coupon from the same stock, mark it, and run one procedure the room can repeat before lunch.

In a metal shop, a coupon is not the bridge. It is a strip taken from the heat being used that day, etched with an identity, and put through a known load. A pass says something narrow: this piece, under this load, on this date, held. A fail says something narrow too.

The workshop treats a model note the same way. Students do not ask a model to bless a repository. They ask it to speak about one failing assert, then a local scorer decides whether the note even names the failure.

The session is ninety minutes, and the clock is part of the method. The first ten minutes stay with the Monday story and a hard constraint: no secret, no customer log, and no whole-tree paste. From minute ten to minute twenty-five the class cuts the coupon. One failing assert is enough, taken from a toy parser or from the fixture shipped with the notes.

The card is a small object with an id, the claim under test, the exact assert text, the tokens a note must name, and the moves a note must not recommend. From minute twenty-five to minute forty-five the class builds the scorer and runs two fixtures, one meant to pass and one meant to fail. From minute forty-five to minute sixty-five a note is produced, first from the checked-in fixture and only afterward, if the bench is actually up, from a live model. From minute sixty-five to minute eighty the room reads the score the way a shop traveler reads a stamp. The last ten minutes are reserved for what the coupon cannot certify, which is most of the repository.

The scorer is dull on purpose. Dull tools survive a classroom and a tired Tuesday. The script below is a worked example for Python 3.11 or newer, and it is meant to be rerun on a laptop with no network. It checks that a note mentions the error the coupon cares about, mentions the assert, mentions None, and does not wander into a rewrite the card forbade.

A hash and a timestamp turn the run into a record instead of a mood. The exit status lets a later exercise hang the same script on a tiny job without inventing a second rubric.

# coupon_check.py
# Worked example. Rerun locally before any network call.
import datetime
import hashlib
import json
import pathlib
import sys

COUPON = {
    "id": "coupon-parser-017",
    "claim": "empty input should raise ParseError, not return None",
    "failing_assert": "assert parse('') is not None",
    "must_name": ["parseerror", "assert"],
    "forbidden": ["rewrite the module", "change the public type"],
}

def score_note(note: str, coupon: dict) -> dict:
    text = " ".join(note.lower().split())
    names = {token: (token in text) for token in coupon["must_name"]}
    names["none"] = "none" in text
    wandered = [phrase for phrase in coupon["forbidden"] if phrase in text]
    passed = all(names.values()) and not wandered
    return {
        "coupon_id": coupon["id"],
        "passed": passed,
        "names": names,
        "wandered": wandered,
        "note_sha256": hashlib.sha256(note.encode("utf-8")).hexdigest(),
        "scored_at": datetime.datetime.now(datetime.timezone.utc).isoformat(),
    }

def explain(result: dict) -> str:
    if result["passed"]:
        return "stamp accepted: names present, fence held"
    parts = [f"missing {key}" for key, ok in result["names"].items() if not ok]
    if result["wandered"]:
        parts.append("left the card: " + ", ".join(result["wandered"]))
    return "; ".join(parts) if parts else "rejected"

def main() -> int:
    note_path = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else "note.txt")
    result = score_note(note_path.read_text(encoding="utf-8"), COUPON)
    result["summary"] = explain(result)
    print(json.dumps(result, ensure_ascii=True))
    return 0 if result["passed"] else 1

if __name__ == "__main__":
    sys.exit(main())
Enter fullscreen mode Exit fullscreen mode

A fixture note is part of the artifact, not a consolation prize. A student who never reaches a model still finishes the hour. That split is the point of a coupon. The network is a second heat, not the stock.

python3 -m venv .venv
. .venv/bin/activate
printf '%s\n' "Empty input raises ParseError. The failing line is assert parse('') is not None. Keep the public type." > note.txt
python coupon_check.py note.txt
echo "pass fixture exit=$?"
printf '%s\n' "Rewrite the module and change the public type so the test goes green." > note-bad.txt
python coupon_check.py note-bad.txt
echo "fail fixture exit=$?"
Enter fullscreen mode Exit fullscreen mode

The first command should exit 0 and set passed to true. The second should exit 1, set passed to false, and list the forbidden phrases under wandered. If either result flips, the class stops and reads the scorer before anyone mentions a model. A press that cannot reject a bad strip is not a press.

Live drafting sits behind that gate. Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode enters as the bench for an optional second heat, not as the thing the coupon is trying to prove. Notes supplied for this workshop say the project offers free model access and a free server option.

Those sentences are availability claims. They are not a named model, not a token quota, not a hardware list, and not a promise that the window stays open next term. An older post that cites a grant size is the wrong instrument for this hour, because grants move and a copied number goes stale. The instructor opens the project documentation on the morning of class and writes the day's limits on the board in plain sentences.

If the board and the page disagree, the page wins. If the page is silent, the class stays on fixtures. No key belongs in the repository. A free server, when that option is actually open, can host the rerun script and the note log for the room. It is a shared bench, not a locker for production credentials, and not evidence that the parser is correct.

# live_note.py
# Unexecuted sketch. Wire it only after the class reads that day's docs.
def draft_note(prompt: str) -> str:
    raise NotImplementedError(
        "Connect free model access using the client documented on class day."
    )
Enter fullscreen mode Exit fullscreen mode

The prompt such a sketch would send is the coupon card in a few lines, plus the assert, plus an instruction to refuse work outside the card. Students save the raw note and run the scorer on it. The model does not score itself. Generation can be cheap enough, on a free-access bench, to throw away. Judgment stays in a function the room can read, diff, and fail on purpose.

Reading the stamp fills the next stretch of the hour. A pass means the note named ParseError, named the assert, mentioned None, and stayed inside the fence. It does not mean the parser is fixed, and it does not mean the model understood the grammar. It means this note, hashed and timed, would not embarrass the card.

A fail is just as useful. Wandered phrases mean the note tried to leave the coupon and redesign the part. Missing names mean the note was fluent and empty. Either result is appended to a log the class can diff on Tuesday.

python coupon_check.py note.txt >> coupon-log.jsonl
python coupon_check.py note-bad.txt >> coupon-log.jsonl
Enter fullscreen mode Exit fullscreen mode

Append-only is a teaching choice, not a storage fashion. Students who overwrite yesterday's stamp learn how to hide a miss. Keeping the miss beside the pass shows whether the procedure is stable or merely lucky. The lowercase fold inside the scorer deserves the same kind of attention.

ParseError and a lowercase spelling collapse to one token, which is friendly to tired typing, and also a hole. A note can say the word and still describe the wrong branch. Closing that hole is a follow-on exercise. Add a fixture that uses the right words in the wrong story, and make the scorer reject it. The press gets stricter only when a bad strip fails in public.

Limits belong on the same card as the claim. Free model access can be rate-limited, queued, region-gated, or closed without a classroom's permission. A free server can be full, slow, or simply not offered that week. The workshop is mis-built if those conditions cancel the hour, so the fixture path is the hour and the live path stays optional.

Keyword scoring can accept a clumsy note and reject a careful one that says empty-string exception instead of ParseError. That is a property of this press. The honest response is another fixture, not a speech about intelligence, and not a longer prompt full of pleading.

Some rooms should skip the live heat entirely. A course whose data rule forbids third-party prompts stays on fixtures. An air-gapped lab stays on fixtures. A team that needs a reviewed vendor, a retention schedule, or an uptime clause should not treat a free option as that contract.

Anyone about to paste a customer payload, an access token, or a production traceback into the prompt should leave the exercise. The coupon is a teaching strip. It is not a side door into someone else's system, and it is not a merge approval with extra steps.

The maintainer in the Monday story did not need a longer chat transcript. The useful object was a marked strip, a dull press, and a log that still made sense on Tuesday. Readers who want the optional heat can look up MonkeyCode's current free model access and free server option, write that day's limits on a card, and only then replace the fixture note. The scorer does not change when the heat changes.

Top comments (0)