Skip to content

Commit 8c303fb

Browse files
committed
feat: checkpoint claim codes, badge contracts, and progress verifier (FP-411/412/415)
- verify.py gains a progress subcommand per course: per-checkpoint status derived from the objective suite (l03 starter-suite, l04 both-suites) plus learner-attested checkpoints (l01/l02/l05), each printing a deterministic 8-char base32 claim code derived from documented per-course constants (FP-411) - COURSE.md/COURSE_cn.md gain the badge contract section (badge id, name, points, honest self-reported-evidence framing), content_version 2, manifest regenerated (FP-412) - verify_courses.py validates the progress contract: double-run determinism, document shape, five checkpoints, claim-code format (FP-415)
1 parent da163ea commit 8c303fb

18 files changed

Lines changed: 557 additions & 33 deletions

File tree

content-manifest.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
{
5151
"id": "course-agent-rules",
5252
"type": "course",
53-
"content_version": 1,
53+
"content_version": 2,
5454
"status": "reviewed",
5555
"reviewed_on": "2026-09-12",
5656
"locales": [
@@ -59,14 +59,14 @@
5959
"path": "courses/agent-rules-single-source/COURSE.md",
6060
"title": "One source of truth for agent rules",
6161
"summary": "Stop maintaining diverging AGENTS.md, CLAUDE.md, and .cursorrules files — build a checker that proves your repository has exactly one rule source, taught hands-on with your coding agent.",
62-
"sha256": "41aaa6f0681ea5a40263dd5372f0d4bf402c947b6727486c4ff5ba7f0a2a9cee"
62+
"sha256": "b09497cd76bea0191c3944dec61cc9bb89f245a21750fcf5013f4c4d4db7d51c"
6363
},
6464
{
6565
"lang": "zh-CN",
6666
"path": "courses/agent-rules-single-source/COURSE_cn.md",
6767
"title": "Agent 规则的单一真源",
6868
"summary": "不再同时维护彼此打架的 AGENTS.md、CLAUDE.md 与 .cursorrules——亲手构建一个能证明仓库只有一处规则真源的检查器,由你的编码 Agent 授课。",
69-
"sha256": "5b90d5556cdff097812ef25ab9134b3939f677f6106c162c28ea15f1986091ee"
69+
"sha256": "245fc0cc40f3103ed5fed99f6f656e9b04ff7093bd0d0782203a0dbafa647864"
7070
}
7171
]
7272
},
@@ -188,7 +188,7 @@
188188
{
189189
"id": "course-claude-code",
190190
"type": "course",
191-
"content_version": 1,
191+
"content_version": 2,
192192
"status": "reviewed",
193193
"reviewed_on": "2026-09-12",
194194
"locales": [
@@ -197,14 +197,14 @@
197197
"path": "courses/hands-on-python-with-claude-code/COURSE.md",
198198
"title": "Hands-on Python with Claude Code",
199199
"summary": "An agent-taught course that takes you from a cloned folder to a tested, verified Python report tool using Claude Code — including the task contract, the bounded change, and the objective pass/fail evidence.",
200-
"sha256": "048b8f210dedc9d60bffb98a8347c89586295e5be3c16abd6be20ea50ef48563"
200+
"sha256": "aec892c18cd7446b9d08c69b116d8c00a0bffc6b6ea6d715dfc969298708d5a3"
201201
},
202202
{
203203
"lang": "zh-CN",
204204
"path": "courses/hands-on-python-with-claude-code/COURSE_cn.md",
205205
"title": "用 Claude Code 实战 Python",
206206
"summary": "一门由 Agent 授课的课程:从下载课程文件夹到交付一个经过测试与验证的 Python 报表工具——包括任务契约、最小变更和客观的通过/失败证据。",
207-
"sha256": "96c3287051153c42678be558538b9be16cc9835296fc8947711e48ea6ee0a145"
207+
"sha256": "185e21a796cac870969f2fff73b3f103eb4a43e215c11be9f0044dc3ec0e7e22"
208208
}
209209
]
210210
},
@@ -326,7 +326,7 @@
326326
{
327327
"id": "course-codex-cli",
328328
"type": "course",
329-
"content_version": 1,
329+
"content_version": 2,
330330
"status": "reviewed",
331331
"reviewed_on": "2026-09-12",
332332
"locales": [
@@ -335,14 +335,14 @@
335335
"path": "courses/hands-on-with-openai-codex-cli/COURSE.md",
336336
"title": "Hands-on with OpenAI Codex CLI",
337337
"summary": "The same verified Python workflow as the Claude Code course — task contract, bounded change, objective verify.py evidence — taught hands-on with the OpenAI Codex CLI instead.",
338-
"sha256": "aa223ff4356ab25c32f55344362a5133fcba0f25851e05c6bd3c6bde9189a8aa"
338+
"sha256": "a0dfd154f544fee2eedfc5a34546286af344afd7e6901abef6dec9ba0967fb76"
339339
},
340340
{
341341
"lang": "zh-CN",
342342
"path": "courses/hands-on-with-openai-codex-cli/COURSE_cn.md",
343343
"title": "OpenAI Codex CLI 实战",
344344
"summary": "与 Claude Code 课程相同的已验证 Python 工作流——任务契约、最小变更、客观 verify.py 证据——改用 OpenAI Codex CLI 完成实战。",
345-
"sha256": "4a31ae97c205ee1e28008f1149aadf1488d4d305176678da1c475475174944d5"
345+
"sha256": "058985bd5e3f274df28de5ab12ba400eb3ea1367be7daee25a3b98424d4656b3"
346346
}
347347
]
348348
},
@@ -464,7 +464,7 @@
464464
{
465465
"id": "course-mcp-tools",
466466
"type": "course",
467-
"content_version": 1,
467+
"content_version": 2,
468468
"status": "reviewed",
469469
"reviewed_on": "2026-09-12",
470470
"locales": [
@@ -473,14 +473,14 @@
473473
"path": "courses/mcp-server-in-python/COURSE.md",
474474
"title": "Give your agent tools with MCP (Python)",
475475
"summary": "Build a stateless Model Context Protocol tool server in pure Python — JSON-RPC 2.0 dispatch, schema validation, error isolation, and the 2026-07-28 input_required round-trip — and learn where a real tool belongs.",
476-
"sha256": "bab5f79922a15ac52c736a549bc69a392718fff274e20cae0ad7c3428e00c4f6"
476+
"sha256": "7cf318f04fd92925789d11cff48afc249fbe4f96b02e68bfa30fe054f0b6da22"
477477
},
478478
{
479479
"lang": "zh-CN",
480480
"path": "courses/mcp-server-in-python/COURSE_cn.md",
481481
"title": "用 MCP 给你的 Agent 装上工具(Python)",
482482
"summary": "用纯 Python 构建一个无状态的 Model Context Protocol 工具服务——JSON-RPC 2.0 分发、schema 校验、错误隔离与 2026-07-28 的 input_required 多轮交互——并理解真正的工具该放在哪里。",
483-
"sha256": "a11236fcd046e9e84e54b22ebcce7e01b925ef71f12014ebb1f1b8bcb536cb63"
483+
"sha256": "74af520640128e8df445f5e7af6f8391eb525af26698871b560fd98a6816961e"
484484
}
485485
]
486486
},
@@ -602,7 +602,7 @@
602602
{
603603
"id": "course-verify-ship",
604604
"type": "course",
605-
"content_version": 1,
605+
"content_version": 2,
606606
"status": "reviewed",
607607
"reviewed_on": "2026-09-12",
608608
"locales": [
@@ -611,14 +611,14 @@
611611
"path": "courses/verifying-ai-generated-code/COURSE.md",
612612
"title": "From \"it runs\" to \"it ships\": verifying AI-generated code",
613613
"summary": "Build the release-evidence machine your AI-written project is missing — a ship check that runs the tests, parses what actually ran, refuses zero-test projects, and writes an honest delivery record.",
614-
"sha256": "7765ea8ad032cc16eb5d34b0f65401c28c8c56cc1f44c496c9cc298f44cb7cd3"
614+
"sha256": "d4f2b0448f3c637acfdff97e76ab72e622833f4904376d0fad4e54dbe189ef23"
615615
},
616616
{
617617
"lang": "zh-CN",
618618
"path": "courses/verifying-ai-generated-code/COURSE_cn.md",
619619
"title": "从「能跑」到「能上线」:验证 AI 写的代码",
620620
"summary": "为你的 AI 项目补上缺失的发布证据机器——一个 ship check:运行测试、解析实际跑了什么、拒绝零测试项目,并写出诚实的交付记录。",
621-
"sha256": "55eda6add807fff2147c7829da190e8c7cdfdbb537d3dcfdb85b461e2c0a21f2"
621+
"sha256": "50b2624cdae9a7597b841ec8f70339d928b431ceff4638e9c3e1e67d90a06188"
622622
}
623623
]
624624
},

courses/agent-rules-single-source/COURSE.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type: course
44
title: One source of truth for agent rules
55
summary: Stop maintaining diverging AGENTS.md, CLAUDE.md, and .cursorrules files — build a checker that proves your repository has exactly one rule source, taught hands-on with your coding agent.
66
lang: en-US
7-
content_version: 1
7+
content_version: 2
88
status: reviewed
99
reviewed_on: 2026-09-12
1010
---
@@ -58,8 +58,17 @@ and the AGENTS.md guide on flypython.com), multi-repo setups, or
5858
machine-policy enforcement. The checker is deliberately narrow: one
5959
directory, three file names, one truth.
6060

61+
62+
## Badge contract
63+
64+
- Badge: **Measure the drift Badge** (badge id `course-agent-rules`) - earned by claiming all five checkpoints.
65+
- Challenges: L01-L05 checkpoints, 10 points each; +50 course-badge bonus when all five are claimed on flypython.com.
66+
- Evidence: `python verify.py progress` - L03 (bounded change) and L04 (verify & review) are objectively gated by the suite; L01/L02/L05 are learner-attested.
67+
- Submission: each passed checkpoint prints a deterministic claim code; record it on flypython.com against your account. Self-reported evidence, never a certificate.
68+
6169
## Folder map
6270

71+
6372
`COURSE.md`/`COURSE_cn.md`, bilingual `lessons/`, `scenario/` repositories,
6473
`TASK.md`/`TASK_cn.md` (the code contract), `starter/`, `solution/`, `tests/`
6574
(11 tests), `verify.py`, `REVIEW.md`.

courses/agent-rules-single-source/COURSE_cn.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type: course
44
title: Agent 规则的单一真源
55
summary: 不再同时维护彼此打架的 AGENTS.md、CLAUDE.md 与 .cursorrules——亲手构建一个能证明仓库只有一处规则真源的检查器,由你的编码 Agent 授课。
66
lang: zh-CN
7-
content_version: 1
7+
content_version: 2
88
status: reviewed
99
reviewed_on: 2026-09-12
1010
---
@@ -53,8 +53,17 @@ reviewed_on: 2026-09-12
5353
flypython.com 上的 AGENTS.md 指南)、多仓库配置、机器策略强制。检查器
5454
刻意收窄:一个目录、三个文件名、一个真源。
5555

56+
57+
## 徽章契约
58+
59+
- 徽章:**量化漂移徽章**(徽章 id `course-agent-rules`)——认领全部五个检查点后获得。
60+
- 挑战:L01–L05 检查点各 10 分;五项全部在 flypython.com 认领后另加 50 分课程徽章奖励。
61+
- 证据:`python verify.py progress` —— L03(边界修改)与 L04(验证与审查)由测试套件客观判定;L01/L02/L05 为学习者自报。
62+
- 提交:每个通过的检查点会打印确定性认领码,在 flypython.com 上记入你的账号。这是自我报告的证据,绝不是证书。
63+
5664
## 文件夹结构
5765

66+
5867
`COURSE.md`/`COURSE_cn.md`、双语 `lessons/``scenario/` 仓库、
5968
`TASK.md`/`TASK_cn.md`(代码契约)、`starter/``solution/``tests/`
6069
(11 个测试)、`verify.py``REVIEW.md`

courses/agent-rules-single-source/verify.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
from __future__ import annotations
88

99
import argparse
10+
import base64
11+
import hashlib
12+
import json
1013
import os
1114
import subprocess
1215
import sys
@@ -24,12 +27,85 @@
2427
)
2528

2629

30+
31+
COURSE_ID = 'course-agent-rules'
32+
# Documented constant: claim codes derive deterministically from
33+
# (COURSE_ID, checkpoint_id, COURSE_SALT). They are spot-checkable
34+
# self-reported evidence, not tamper-proof secrets — see
35+
# docs/repo-plan-0.0.4.md FP-411.
36+
COURSE_SALT = '3af23393e1911a4a'
37+
38+
CHECKPOINTS = [
39+
{"id": "l01", "gate": "attest", "title": '量化漂移 / Measure the drift'},
40+
{"id": "l02", "gate": "attest", "title": '确定唯一真源 / Decide the source of truth'},
41+
{"id": "l03", "gate": "starter-suite", "title": '有边界的变更 / Bounded change'},
42+
{"id": "l04", "gate": "both-suites", "title": '验证并接入流程 / Verify and wire it in'},
43+
{"id": "l05", "gate": "attest", "title": '应用到你的仓库 / Apply to your repository'},
44+
]
45+
46+
def _claim_code(checkpoint_id):
47+
digest = hashlib.sha256(
48+
(COURSE_ID + ":" + checkpoint_id + ":" + COURSE_SALT).encode("utf-8")
49+
).digest()
50+
return base64.b32encode(digest).decode("ascii")[:8]
51+
52+
def _run_suite(implementation):
53+
environment = os.environ.copy()
54+
environment["PYTHONPATH"] = str(ROOT / implementation)
55+
return subprocess.run(
56+
[sys.executable, "-m", "unittest", "discover", "-s", str(ROOT / "tests")],
57+
env=environment, check=False, capture_output=True, text=True,
58+
)
59+
60+
def run_progress(as_json):
61+
starter = _run_suite("starter")
62+
solution = _run_suite("solution")
63+
starter_ok = starter.returncode == 0
64+
solution_ok = solution.returncode == 0
65+
rows = []
66+
for checkpoint in CHECKPOINTS:
67+
gate = checkpoint["gate"]
68+
if gate == "attest":
69+
status, kind = "attest", "attested"
70+
elif gate == "starter-suite":
71+
status = "passed" if starter_ok else "open"
72+
kind = "objective"
73+
else:
74+
status = "passed" if (starter_ok and solution_ok) else "open"
75+
kind = "objective"
76+
code = _claim_code(checkpoint["id"]) if status in ("passed", "attest") else None
77+
row = dict(checkpoint)
78+
row["status"] = status
79+
row["kind"] = kind
80+
row["claim_code"] = code
81+
rows.append(row)
82+
if as_json:
83+
print(json.dumps({"course": COURSE_ID,
84+
"starter_suite_passed": starter_ok,
85+
"solution_suite_passed": solution_ok,
86+
"checkpoints": rows}, ensure_ascii=False, indent=2))
87+
else:
88+
starter_state = "通过" if starter_ok else "未通过"
89+
solution_state = "通过" if solution_ok else "未通过"
90+
print("课程 " + COURSE_ID)
91+
print("实现状态: starter " + starter_state + " / solution " + solution_state)
92+
for row in rows:
93+
state = row["status"] + ("(自报)" if row["kind"] == "attested" else "")
94+
code = "认领码 " + row["claim_code"] if row["claim_code"] else "—"
95+
print(" " + row["id"] + " " + row["title"] + " [" + state + "] " + code)
96+
print("认领码是自我报告的证据,在 flypython.com 记录;绝非证书。")
97+
return 0
98+
2799
def main() -> int:
28100
parser = argparse.ArgumentParser(description=__doc__)
29-
parser.add_argument("implementation", choices=("starter", "solution"))
101+
parser.add_argument("implementation", choices=("progress", "starter", "solution"))
102+
parser.add_argument("--json", action="store_true")
30103
parser.add_argument("--expect-failure", action="store_true")
31104
args = parser.parse_args()
32105

106+
if args.implementation == "progress":
107+
return run_progress(args.json)
108+
33109
command = [sys.executable, "-m", "unittest", "discover", "-s", str(ROOT / "tests")]
34110
environment = os.environ.copy()
35111
environment["PYTHONPATH"] = str(ROOT / args.implementation)

courses/hands-on-python-with-claude-code/COURSE.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type: course
44
title: Hands-on Python with Claude Code
55
summary: An agent-taught course that takes you from a cloned folder to a tested, verified Python report tool using Claude Code — including the task contract, the bounded change, and the objective pass/fail evidence.
66
lang: en-US
7-
content_version: 1
7+
content_version: 2
88
status: reviewed
99
reviewed_on: 2026-09-12
1010
---
@@ -70,8 +70,17 @@ Installing Claude Code, prompt tricks, multi-file architecture, pandas or
7070
real Excel (`.xlsx`) files, deployment, or selling anything. For those, the
7171
companion repository has guides and playbooks — link, don't improvise.
7272

73+
74+
## Badge contract
75+
76+
- Badge: **Reproduce the failure Badge** (badge id `course-claude-code`) - earned by claiming all five checkpoints.
77+
- Challenges: L01-L05 checkpoints, 10 points each; +50 course-badge bonus when all five are claimed on flypython.com.
78+
- Evidence: `python verify.py progress` - L03 (bounded change) and L04 (verify & review) are objectively gated by the suite; L01/L02/L05 are learner-attested.
79+
- Submission: each passed checkpoint prints a deterministic claim code; record it on flypython.com against your account. Self-reported evidence, never a certificate.
80+
7381
## Folder map
7482

83+
7584
```
7685
COURSE.md / COURSE_cn.md this file (EN / 中文)
7786
lessons/L01.md … L05.md lessons (each has an _cn.md pair)

courses/hands-on-python-with-claude-code/COURSE_cn.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type: course
44
title: 用 Claude Code 实战 Python
55
summary: 一门由 Agent 授课的课程:从下载课程文件夹到交付一个经过测试与验证的 Python 报表工具——包括任务契约、最小变更和客观的通过/失败证据。
66
lang: zh-CN
7-
content_version: 1
7+
content_version: 2
88
status: reviewed
99
reviewed_on: 2026-09-12
1010
---
@@ -62,8 +62,17 @@ Claude Code 安装、提示词技巧、多文件架构、pandas 或真正的 Exc
6262
`.xlsx`)文件、部署、任何销售内容。这些主题在配套仓库里有指南和
6363
手册——链接过去,不要现场发挥。
6464

65+
66+
## 徽章契约
67+
68+
- 徽章:**复现故障徽章**(徽章 id `course-claude-code`)——认领全部五个检查点后获得。
69+
- 挑战:L01–L05 检查点各 10 分;五项全部在 flypython.com 认领后另加 50 分课程徽章奖励。
70+
- 证据:`python verify.py progress` —— L03(边界修改)与 L04(验证与审查)由测试套件客观判定;L01/L02/L05 为学习者自报。
71+
- 提交:每个通过的检查点会打印确定性认领码,在 flypython.com 上记入你的账号。这是自我报告的证据,绝不是证书。
72+
6573
## 文件夹结构
6674

75+
6776
```
6877
COURSE.md / COURSE_cn.md 本文件(英文 / 中文)
6978
lessons/L01.md … L05.md 课程(每课都有 _cn.md 中文版)

0 commit comments

Comments
 (0)