I study in Halifax, and this case starts the way too many of my README edits start. A sentence looks finished. The sources do not. The feed had been full of finished-looking pages, and mine still looked like a lab book. So why did the line on my clipboard feel like a borrowed drumroll?
It was this line.
Includes free forever token access.
No primary URL. The source date said 2025-01-02. I had already marked the scope as slogan. I was checking it on 2026-10-08, inside a 30-day window I had chosen myself. I did not need a model to smell the theater. I needed a gate that would fail closed when I got tired and pasted it anyway.
Can a standard-library script teach claim freshness, the habit of refusing a sentence whose source date I would not defend out loud? That is the only question in this case study.
What I was willing to say about the tool
Disclosure: This article was prepared as part of MonkeyCode's product outreach. I am using two availability claims and nothing past them: free model access, and a free server option. I will not invent a model name, a quota, a machine, or a duration to make the lab sound bigger. If a number has no primary page I opened, it does not get a sentence.
Free model access is where the risky drafts come from. I let it propose README lines, then I treat every line as a suspect. The free server option is where the checker runs, in a clean directory, so a notebook kernel cannot hide a pass. A remote shell is still just a shell. It does not bless the prose.
Background and goal
I am an AI and CS student, and the notes I publish are meant for other students who are just entering this work. The audience is not a buying committee. The failure I keep meeting is not a missing import. It is fluency. A draft feels current because the verbs are current. Have you ever almost shipped a sentence like that because it sounded like the week you just had?
Claim freshness is the name I am using for the counter-test. A claim is a sentence I might publish. A source date is the day on the primary page, not the day I felt motivated. A window is how many days I allow between those two before the sentence returns to draft. The goal was one small project, end to end, with a visible fail.
Input is a JSON list of claim cards. Output is a JSON report. The process exits 0 only when every card is allowed. This is not a timer for a model endpoint, and it is not an exam for answer quality. It is a door policy for sentences.
Prerequisites are dull on purpose. You want Python 3.11 or newer, and the standard library only. No PyTorch, no Hugging Face, no key in the environment. Hidden setup is how tutorials lie, so check the interpreter before you interpret the failures.
python3 --version
If that prints 3.10 or older, upgrade before you debug the file. The type hints will complain first, and they are not the lesson.
Implementation
I kept the judge boring. Boring is what I want from a gate. Each card carries claim_id, text, source_url, source_date, checked_on, max_age_days, and scope. The URL has to parse as http or https with a host. Both dates have to be real YYYY-MM-DD days. A source date after the checked date is future_source_date, not optimism. An age greater than the window is source_older_than_window. Scope slogan is never citable.
There is one more blunt rule. If the lowercased text contains token, quota, free forever, million, or users, the scope must be docs. Otherwise the card grows quantity_needs_docs_scope. Is that marker list naive? Yes. It will trip on tokenizer one day. I would rather explain a false positive in a lab than publish a grant I never measured.
Think of the script as a coat check, not a courtroom. You do not get the sentence back unless the ticket is filled in. It never opens a socket. That limitation is the point, not a missing feature. A green flag is a coat-check stub, not a notary stamp.
Save this as claim_card.py.
#!/usr/bin/env python3
"""Claim-card gate. Python 3.11+ standard library only."""
from __future__ import annotations
import json
import sys
from dataclasses import dataclass
from datetime import date, datetime
from urllib.parse import urlparse
MARKERS = ("token", "quota", "free forever", "million", "users")
@dataclass(frozen=True)
class ClaimCard:
claim_id: str
text: str
source_url: str
source_date: str
checked_on: str
max_age_days: int
scope: str
def parse_iso(value: str) -> date | None:
try:
return datetime.strptime(value, "%Y-%m-%d").date()
except ValueError:
return None
def host_ok(url: str) -> bool:
parts = urlparse(url)
return parts.scheme in {"http", "https"} and bool(parts.netloc)
def judge(card: ClaimCard) -> dict:
reasons = []
checked = parse_iso(card.checked_on)
sourced = parse_iso(card.source_date) if card.source_date else None
if not card.text.strip():
reasons.append("empty_text")
if not host_ok(card.source_url):
reasons.append("missing_primary_url")
if checked is None:
reasons.append("bad_checked_on")
if card.source_date and sourced is None:
reasons.append("bad_source_date")
if not card.source_date:
reasons.append("missing_source_date")
if checked is not None and sourced is not None:
age = (checked - sourced).days
if age < 0:
reasons.append("future_source_date")
elif age > card.max_age_days:
reasons.append("source_older_than_window")
if card.scope == "slogan":
reasons.append("slogan_scope_not_citable")
lowered = card.text.lower()
if any(marker in lowered for marker in MARKERS) and card.scope != "docs":
reasons.append("quantity_needs_docs_scope")
return {"claim_id": card.claim_id, "allow": not reasons, "reasons": reasons}
def main() -> int:
raw = json.load(sys.stdin)
report = [judge(ClaimCard(**item)) for item in raw]
json.dump(report, sys.stdout, indent=2)
sys.stdout.write("\n")
return 0 if all(row["allow"] for row in report) else 1
if __name__ == "__main__":
raise SystemExit(main())
Save the mixed fixture as fixtures/mixed.json. The first card is the lab note I will keep. The second is the README sentence that should die. Neither URL is a real citation. example.edu is a teaching stand so the file can run offline.
[
{
"claim_id": "lab-wording",
"text": "I drafted the paragraph with free model access, then rewrote it by hand.",
"source_url": "https://example.edu/notes/claim-ledger",
"source_date": "2026-10-08",
"checked_on": "2026-10-08",
"max_age_days": 14,
"scope": "lab-note"
},
{
"claim_id": "readme-slogan",
"text": "Includes free forever token access.",
"source_url": "",
"source_date": "2025-01-02",
"checked_on": "2026-10-08",
"max_age_days": 30,
"scope": "slogan"
}
]
mkdir -p fixtures
python3 claim_card.py < fixtures/mixed.json; echo "exit=$?"
Results I will defend
The report below is traced from judge, rule by rule. It is not a screenshot from a vendor dashboard, and I do not want you to treat it as one. If you run the file and the reasons differ, believe your run, then ask which branch fired.
[
{
"claim_id": "lab-wording",
"allow": true,
"reasons": []
},
{
"claim_id": "readme-slogan",
"allow": false,
"reasons": [
"missing_primary_url",
"source_older_than_window",
"slogan_scope_not_citable",
"quantity_needs_docs_scope"
]
}
]
The exit status is 1. That is the result of the case. The lab card passes the gate. The slogan card does not. Age is not a mood. From 2025-01-02 to 2026-10-08 is 644 days, and 644 is greater than 30, so source_older_than_window is earned. Recompute that subtraction before you trust me. If your calendar disagrees, stop. Do not fix the fixture until you can say where the day count came from.
What does a pass actually prove? Less than a green check wants you to feel. An allowed card can still be a lie in a well-formed URL. The gate checks the ticket. It does not attend the lecture. I would not publish that first card as a citation, even though allow is true. Passing means the fields satisfy my policy, not that the world confirmed the sentence.
The error input
Keep a bad day beside the mixed run. This is the input I care about when someone says the script is too strict. Save it as fixtures/bad_date.json.
[
{
"claim_id": "typo-date",
"text": "The lab note was checked this week.",
"source_url": "https://example.edu/notes/claim-ledger",
"source_date": "2026-13-40",
"checked_on": "2026-10-08",
"max_age_days": 14,
"scope": "lab-note"
}
]
python3 claim_card.py < fixtures/bad_date.json; echo "exit=$?"
Traced output:
[
{
"claim_id": "typo-date",
"allow": false,
"reasons": [
"bad_source_date"
]
}
]
Exit 1 again. Month 13 does not become January. A charitable parser is how stale claims sneak back in, wearing a corrected date you never chose. Would you want the script to guess? I would not. Guessing is a second draft, and second drafts are how the slogan survives.
Where the free options helped, and who should leave
I use the free model access to propose three README variants. The useful moment is watching a fluent line grow a quantity. I delete the quantity. I do not keep a leaderboard, because I was not running a bake-off. I use the free server option when I want that same command in a directory with no leftover bytecode from a local experiment. Clean tree, same file, same stdin. That was the whole server lesson.
This approach is the wrong tool if you are writing a legal citation, a clinical note, or a security advisory. A student lab voice does not belong there, and a date window will not save you. It is also the wrong tool if you need the page fetched, hashed, and archived. There is no network code here on purpose. And if your aim is to wash a marketing number until a checkmark appears, stop. The checkmark is the bug.
Mistakes, then the idea you should keep
I tried to cheat my own gate, which is the fastest way to learn it. I set max_age_days to 3650 and called the slogan fresh. A window that long is a mute button. I pointed source_url at a homepage and pretended a front door was a quote. I let a draft copy checked_on into source_date automatically. That forges the ticket.
I also added an extra JSON key and got TypeError from ClaimCard(**item). Seven fields. No surprise luggage. A string in max_age_days will blow up the comparison too. The gate is strict because I am not.
If a classmate asked what to copy, I would not hand them a prompt. I would hand them the failing fixture and sit there while they predict the reasons. Would the reasons change if the slogan merely sounded humbler? No. Tone is not a source. The code is short because the concept is a door policy, not an architecture.
When your exits match the traced report, this is what you should understand. Claim freshness is a publishing habit with a small automaton beside it. The automaton remembers the rules when you are sleepy. It does not know whether the page is true, whether a free option will exist next term, or whether your paraphrase copied too much. You still open the primary page on the day you write into checked_on. You still delete numbers you did not measure.
Here is the extension, and it is a request for a counterexample rather than a clap. Change the slogan card's scope to docs, give it an https URL dated 2026-10-01, and predict which reasons remain. Then add a host denylist so example.edu and example.com cannot pass. The dangerous card is the one inside the window, carefully worded, and still the wrong document.
A free drafting pass and a clean remote shell were enough for this lab. I would keep the ledger if both went away tomorrow. The sentence does not get truer because the shell did not send an invoice.
Top comments (0)