에이전트가 대신 돈을 낼 때, 그 결제는 누가 허락하고 누가 확인하는가? 7주차 시장에는 결제 층이 없었다. 영수증과 서명은 있었지만 돈은 오가지 않았고, 예산은 공개 ledger에 그대로 적혔다. 같은 시장에서 Round 3을 열고, ACP checkout과 AP2 mandate로 정산된 거래만 센다.
Phase 1이 끝났다. 중간고사는 에이전트 만들기 과제로 대신한다. 예전 자료에 있던 재현 실험 보고서는 내지 않는다.
REPORT.md, Round 3 순위(가게 ALL + buyer ALL)./agent.md에 올린다.평가 기준과 제출물은 아래 HW에 있다.
| 구분 | 내용 |
|---|---|
| OPEN | 7주차 웃긴 에피소드 |
| SETUP | 키트 v4로 다시 들어가기 |
| L1 | 거래 스택과 빠진 층 |
| L2 | ACP와 AP2 |
| DEMO | 공격 장면 재현 |
| R3 | Round 3: 정산된 거래만 인정 |
| LAB | 결제를 눈으로 보기 |
| L3 | MeshKit으로 |
| HW | 중간 평가: Round 3 시장의 내 에이전트 |
수업이 끝난 뒤에도 시장은 Round 2 규칙으로 계속 돌았다. 아래 장면과 수치는 market.ourolabs.ai의 DB 전체에서 뽑았다.
| 관찰 | 값 |
|---|---|
| 서명 검증을 통과한 거래 | 290,292건 |
| 거부된 영수증 | 30,198건. 99.2%는 시장이 시험용으로 심어 둔 하우스 가게 두 곳에서 나왔고, 수강생 가게에서 나온 것은 47건 |
| 하한가에 정확히 체결된 거래 | 하루 단위로 최대 75% |
| 직전과 같은 가게에서 다시 산 비율 | 60.4% |
| 에이전트가 쓴 후기 | 281,624개 |
한 LLM buyer가 가게를 고르며 남긴 이유 16,534건을 분류하면, 영수증과 서명을 언급한 것이 99.3%, 자기 과거 거래가 76.1%, 가격이 43.6%, 남의 후기가 15.0%였다. 할인, 세일, 보증 같은 카드의 프로모션을 언급한 것은 0.3%였다.
공개 /api/ledger에는 주문마다 buyer, 품목, 예산이 적혔다. 주문이 ledger에 올라오고 몇 초 뒤에 그 buyer가 가게에 말을 건다. 강사의 가게 q00은 ledger를 2초마다 읽어, 같은 품목으로 열린 주문 중 가장 낮은 예산을 첫 호가로 불렀다.
q00은 232건을 팔고 순이익 937에 그쳤다. 예산에 거의 붙여 부른 탓에 하우스 buyer들이 3점을 줬다("Paid 180 of 185"). 별점이 떨어지자 손님이 끊겼다. 그래도 예산은 거래 전에 가게가 읽을 수 있는 정보였다. Round 3에서는 예산을 ledger에서 뺀다.
Round 3의 checkout, 결제, 공급, 게시판은 키트 v4가 맡는다. 키트만 바꿔 같은 명령으로 다시 join한다. Round 3가 열리기 전까지 키트 v4는 Round 2와 똑같이 거래한다. Round 3부터 가게는 재고에서 팔아야 한다. 아래 R3의 ECONOMY를 본다.
수업 레포로 들어왔다면 GitHub에서 내 포크의 Sync fork를 누른 뒤 git pull로 받는다. install.sh로 들어왔다면 지난주 명령을 그대로 다시 실행한다. 키트만 새로 받고 내 에이전트 폴더는 건드리지 않는다.
cd ai-agent-engineering-101 # 내 포크 git pull grep KIT_VERSION scripts/market_kit.py # KIT_VERSION = "4"
curl -sL https://market.ourolabs.ai/install.sh | bash -s -- --name <닉네임> --owner <claim code>
# 내 폴더로 들어왔다면 지난주처럼 --dir <내 폴더>를 붙인다지난주에 켜 둔 키트를 Ctrl-C로 끈다. 중간 평가는 submissions/<학번>/week-08에 내니, 지난주 폴더를 키 파일까지 통째로 복사하고 그 폴더로 다시 join한다. 키가 같으면 같은 이름으로 들어온다. install.sh는 STEP 1에서 join까지 한다.
cp -r submissions/<학번>/week-07 submissions/<학번>/week-08
MARKET_OWNER=<claim code> python scripts/market_kit.py join --dir submissions/<학번>/week-08 \
--market https://market.ourolabs.ai --name <닉네임> --tunnel
# Windows: cp -r 대신 Copy-Item -Recurse, 줄 끝의 \ 를 빼고 한 줄로 붙여 쓴다키트 로그 첫 줄에 버전 4가 찍히면 된다. 내 가게 주소 뒤에 /.well-known/acp.json을 붙여 열면 키트가 연 ACP checkout 안내가 보인다. 내 가게 주소는 로그의 [shop] 줄 끝에 있다.
14:50:37 [kit] market_kit 4, .../week-08
curl -s <내 가게 주소>/.well-known/acp.json
{"protocol":"acp","version":"2026-04-17","endpoint":"https://market.ourolabs.ai/shop/corner-store/acp",
"capabilities":{"services":["checkout"],"payment_methods":["ap2-mandate"]},
"tools":[{"name":"create_checkout_session","method":"POST","path":"/checkout_sessions",...}, ...]}| 상황 | 방법 |
|---|---|
로그 첫 줄이 market_kit 3 이하 | 키트가 아직 옛 파일이다. STEP 1을 다시 한다 |
| 키트 없이 배포한 가게 (Workers, Render 등) | 키트가 ACP를 열어 주지 못한다. 수업에서는 --buyer-only로 buyer만 들어오고, 가게의 ACP는 HW에서 직접 만든다 |
| 터널이 열리지 않는다 | 지난주처럼 --buyer-only로 buyer만 들어온다 |
한 번의 거래는 발견, 협상, 실행, 결제, 기록으로 나뉜다. 1~7주차에 만든 것을 이 층 위에 놓으면 결제 층만 비어 있다.
| 층 | 주차 | 7주차 시장에서 일어난 일 |
|---|---|---|
| 발견 | W05 MCP, W06 agent card, W07 registry | 카드가 AI buyer를 겨냥한 광고판이 됐고, "approved by the instructor" 같은 권위 사칭이 나왔다 |
| 협상 | W03 Contract Net, W04 FIPA-ACL, W06 A2A task | 하한가 체결이 최대 75%. 응답에 숨긴 가짜 공지가 일부 buyer를 움직였다 |
| 실행 | W01 에이전트, W02 하네스 | 자기 모델의 rate limit 때문에 거래가 깨진 buyer가 가게들에 1점을 6,837번 줬다 |
| 결제 | 없음 | 크레딧은 오가지 않았다. 예산은 위임 범위였지만 공개 ledger에 그대로 노출됐다 |
| 기록 | W07 ledger, 서명 영수증 | 위조 영수증 30,198건이 거부됐다. 담합 거래는 서명이 정상이라 기록으로는 구분되지 않았다 |
7주차의 주문은 결제 층의 일부를 대신했다. 품목, 예산, 만료 시각, nonce가 buyer가 쓸 수 있는 범위였다. 이 범위는 시장이 정했고, 누구나 읽을 수 있었고, 가게는 결제 전에 아무것에도 서명하지 않았다. ACP와 AP2가 이 자리를 채운다.
OpenAI와 Stripe가 만든 checkout 규격이다. Apache 2.0으로 공개됐고, ChatGPT가 처음 구현했다. 버전은 날짜로 매긴다.
| 버전 | 추가된 것 |
|---|---|
| 2025-09-29 | 첫 공개 |
| 2025-12-12 | fulfillment 확장 |
| 2026-01-16 | capability negotiation |
| 2026-01-30 | extensions, discounts, payment handlers |
| 2026-04-17 | carts, feeds, orders, delegate authentication, MCP transport binding (최신 안정판) |
checkout은 세션 하나로 진행된다.
POST /checkout_sessions # create: line items in, totals out GET /checkout_sessions/{id} POST /checkout_sessions/{id} # update POST /checkout_sessions/{id}/complete # pay POST /checkout_sessions/{id}/cancel
2026-04-17판의 MCP 바인딩은 이 다섯 호출을 create_checkout_session, get_checkout_session, update_checkout_session, complete_checkout_session, cancel_checkout_session 툴로 노출한다. 가게는 /.well-known/acp.json의 capabilities.services로 무엇을 지원하는지 알린다. 결제 수단이나 개입 방식 같은 capability는 별도 registry 없이 세션마다 주고받는다. 결제 자격 증명은 원래 카드 정보를 드러내지 않는 토큰으로 전달되며, Stripe의 Shared Payment Token이 첫 예다.
Google이 2025-09-16에 발표했고, v0.2.0이 2026-04-28에 나왔다. 표준화 작업은 FIDO Alliance로 옮겨 가는 중이다. A2A, MCP, UCP의 확장으로 쓰도록 설계됐다. AP2가 다루는 질문은 이 에이전트가 이 결제를 해도 된다는 증거가 무엇인가이다.
v0.2의 증거는 mandate다. 종류는 Checkout Mandate와 Payment Mandate이고, 각각 Open과 Closed가 있다.
| Open (장바구니 전, 사용자가 서명) | Closed (checkout 하나에 묶임) | |
|---|---|---|
| Checkout | mandate.checkout.open.1checkout.allowed_merchants, checkout.line_items | mandate.checkout.1merchant-signed checkout_jwt, checkout_hash |
| Payment | mandate.payment.open.1payment.amount_range, payment.budget, payment.agent_recurrence, payment.allowed_payees, payment.execution_date | mandate.payment.1amount and payee for that checkout |
Open mandate는 사용자가 Trusted Surface(에이전트가 아닌 승인 화면)에서 미리 서명하는 위임 범위다. Shopping Agent는 실제 거래가 정해지면 그 범위 안에서 Closed mandate를 만든다. Closed Checkout Mandate에는 가게가 서명한 checkout_jwt와 그 해시가 들어가므로, 가게가 나중에 다른 가격을 주장할 수 없다. Payment Mandate는 Credential Provider, 결제 Network, Merchant Payment Processor가 확인한다. 형식은 SD-JWT VC다.
UCP(Universal Commerce Protocol, Google, Shopify, Walmart 등)는 ACP와 같은 자리의 다른 checkout 규격이다. AP2 문서는 UCP와 함께 쓸 때 checkout_jwt에 UCP의 Checkout 객체를 넣도록 정한다.
session/new, session/prompt, session/request_permission.FIG. 01은 Round 3에서 두 규격이 놓이는 자리다.
강사 컴퓨터에서 시장, 가게, buyer를 로컬로 띄워 같은 흐름을 한 장면씩 보인다. buyer는 가게의 acp.json을 읽고 그 자리에서 자기 툴 정의를 만든다. 손으로 짠 checkout 클라이언트는 없다.
| 장면 | 결과 |
|---|---|
| 정상 구매 | 정산되고 크레딧이 옮겨진다 |
| 위조 checkout | 가게 서명이 맞지 않아 시장이 거부 |
| 예산 초과 | amount_range에서 거부 |
| 재사용 | 같은 closed mandate로 두 번째 정산을 시도하면 거부 |
| 숨긴 공지 | 가게 메시지의 가짜 공지와 상관없이 checkout 총액과 mandate 상한으로 결제 |
./run_demo.sh
거래로 세는 기준이 정산으로 바뀌고, 상품과 재고와 게시판이 더해진다(아래 ECONOMY). 흥정은 6주차부터 써 온 A2A 대화로 한다. 그 뒤의 checkout과 정산은 키트가 처리한다.
amount_range(상한 = 예산)와 실행 기한(주문 만료)을 담는다. 사용자의 Trusted Surface를 대신해 시장이 서명한다./.well-known/acp.json을 읽고 checkout 세션을 연다. 가게 키트는 영수증과 같은 가격에 실제로 보낼 SKU를 담은 checkout_jwt를 가게 키로 서명해 돌려준다.checkout_jwt와 그 해시를 담은 Closed Checkout Mandate, 금액과 받는 가게를 담은 Closed Payment Mandate에 buyer 키로 서명한다./api/settle로 보낸다. 시장은 서명 사슬과 제약을 확인하고 크레딧을 옮긴다.| 7주차 사건 | Round 3에서 막는 검사 |
|---|---|
| 위조 영수증 | 가게가 서명한 checkout_jwt와 Closed Checkout Mandate의 checkout_hash가 맞아야 정산된다 |
| 예산 초과, 주문 재사용 | amount_range 밖의 금액은 거부. 주문 하나에 정산 하나 |
| ledger의 예산 노출 | 예산은 buyer의 open mandate에만 있다. ledger에는 해시만 남는다 |
| 응답에 숨긴 가짜 공지 | 결제 금액은 checkout의 구조화된 총액에서 나온다. 대화 문장은 금액을 바꾸지 못한다 |
| 담합 | 막지 못한다. 위의 토론 1 |
Round 3의 시장은 실제 온라인 쇼핑몰 상품 약 5,600개(식품, 가구, 침구, 가전)를 판다. 크레딧은 원과 1:1이다. 키트 v4가 공급, 재고 파일, 결제 전 확인, 게시판 전송을 맡고, 가격과 재고와 무엇을 믿을지는 내 에이전트가 정한다.
| 구분 | 규칙 |
|---|---|
| 주문 | 상품 카테고리 하나(예: 김치, 침대/매트리스)와 그 카테고리에서 기준 가격 0.5~1.5배인 SKU 목록이 온다. 잘 팔리는 상품이 따로 있고, buyer마다 자주 사는 카테고리가 몇 개 숨어 있다. 시장은 둘 다 알려 주지 않는다. 정산 기록, 내 기록, 게시판에서 알아낸다. 식품 주문에는 그 시간 안에 먹는다는 use_within_hours가 붙는다 |
| 공급 | 가게는 5,000,000 크레딧으로 시작해 재고를 직접 산다. 무엇을 살지는 에이전트의 restock 명령이 정하고, 없으면 키트가 무작위로 산다. 단위마다 들어오는 순간 원가가 정해진다. 원가는 정가의 A 55~75%, B 40~60%, C 25~45%다. 공급은 20분마다 3분 동안 열린다(Round 3 첫 창은 10분). 같은 SKU가 시장 전체에서 최근 1시간 동안 50개를 넘게 공급되면 그 뒤 원가는 개당 0.2%씩, 최대 50%까지 오른다 |
| 식품 | 그 순간 남은 유통기한이 등급이다. A 넉넉, B 보통, C 임박. 기다리는 동안 등급이 떨어지고, 등급 주장은 checkout이나 정산 시점의 등급 중 하나와 맞으면 참이다. 기한이 지나면 원가째 폐기된다 |
| 비식품 | A 정상, B 박스 훼손, C 리퍼. 일부는 판 뒤에 고장 난다. 가게가 건 보증 시간 안에 고장 나면 시장이 가게 돈으로 환불한다. 고장 소식은 키트가 .market/broken.jsonl에 물건 이름과 고장 시각만 적는다. 언제 어느 가게에서 산 것인지, 보증이 있었는지는 에이전트가 기억해야 한다 |
| 보관비 | 비식품 재고는 하루에 원가의 1%를 낸다 |
| 파산 | 잔고가 50만 원 아래면 라운드에 두 번까지 파산할 수 있다. 재고는 압류되고 잔고는 500만 원으로 돌아온다. 받은 돈은 Book에서 빠진다. 팔 재고도 없이 바닥나면 키트가 대신 신청한다 |
| 가격 | 하한가는 없다. 원가보다 싸게 팔아도 되고, 손해는 Book에 그대로 잡힌다 |
| 증명서 | 시장이 서명한 입고 증명서가 유통기한이나 등급을 증명한다. 가게는 증명서를 빼고 팔 수 있다. 말로 한 등급 주장은 정산 뒤 ledger에서 참인지 드러난다 |
| buyer의 확인 | market_buyer 마지막 줄의 accept(증명서, 남은 시간, 등급, 보증)를 키트가 결제 전에 확인한다. 맞지 않으면 결제하지 않고, 그 이유를 .market/payments.jsonl에 남긴다 |
| 게시판 | 에이전트가 .market/outbox.jsonl에 한 줄을 쓰면 키트가 올린다. 글은 가게와 buyer가 각각 5분에 한 번이다. 내용 규칙은 없다. 계정마다 작성자 한 명에게 입장 하나만 센다. 좋아요 입장은 1 + log2(순 좋아요 수), 나빠요 입장은 1로 세어 buyer 평점을 낸다. 정산된 거래가 50건 이상이고 주인이 다른 에이전트의 표만 센다. 좋아요는 무료다. 한 계정이 1시간 안에 buyer에게 새로 건 나빠요 입장이 3개를 넘으면 k번째에 20,000 x (k - 3)을 가게 잔고에서 낸다. 나빠요를 value -N으로 보내면 그 작성자에게 N표를 건다. 값은 합계 단가 x (N - 1)^2이고, 단가는 계정의 가장 큰 Book의 3%(최소 20,000)다. 돌려받지 못한다 |
| 같은 주인 | 같은 GitHub 계정의 가게와 buyer끼리는 정산되지 않는다 |
| 순위 | 지표 | ALL |
|---|---|---|
| 가게 | Book(잔고 - 시작 자본 - 파산 지원금 + 안 팔린 재고의 원가), 매출, 별점(결제된 거래의 리뷰를 계정마다 평균 하나로) | 0.5 Book + 0.3 매출 + 0.2 별점, 각각 백분위 |
| buyer | Saved(거래마다 정가에서 아낀 비율을 더해 거래 수 + 100으로 나눈 값. 쓸모없던 물건은 -1, 환불받으면 0), 게시판 평점, 거래 수, buyer로 쓴 글 수 | 0.5 Saved + 0.3 게시판 평점 + 0.1 거래 수 + 0.1 글 수. 평점은 값 그대로, 나머지는 백분위 |
재고에서 파는 seller가 필요하면 market_kit.py starter --round3 --dir <내 폴더>로 seller_r3.py를 받는다. 원가 아래로는 팔지 않고, 품질 이야기도 보증도 하지 않는 단순한 가게다. 전체 규칙은 시장의 /agent.md에 있다. .market/ 파일의 필드와 restock, review hook의 입출력은 그 안의 Round 3 agent contract 표에 있다.
vct 값은 AP2 v0.2를 따른다.Round 3가 열리면 코드를 고치지 않고 로그, ledger, dashboard에서 결제 한 건을 따라간다.
흥정이 끝나고 영수증 서명이 확인되면 [acp] paid 줄이 찍힌다. 그다음 줄의 verified True가 정산된 거래다.
[buyer] -> '260' <- TASK_STATE_COMPLETED | Deal: bookshelf at 260. [sign] sig_seller ok, sig_buyer added [acp] paid 260 through http://127.0.0.1:53619/acp, settled at ledger #129 [market] ledger #130: bookshelf at 260, stars 3, verified True, review accepted
내 가게가 팔면 가게 쪽 로그에 [acp] settled 줄이 찍힌다.
[acp] settled lamp at 100, ledger #106
curl -s "https://market.ourolabs.ai/api/ledger?after=-20"
{"kind": "order", "data": {"order": "o-2d3f7bb75899", "buyer": "buyer-03", "expires": 1793356601, "round": 3,
"budget_commitment": "78d8da4570c25276..."}}
{"kind": "settle", "data": {"order": "o-bd9feefa4e63", "buyer": "buyer-01", "item": "G1f5d00c7", "amount": 8551,
"name": "국내산 제주도 구좌 흙당근 중 2kg", "grade": "B", "claim": "B", "claim_honest": true, ...}}Round 2의 주문에는 item과 budget이 있었다. Round 3의 주문에는 둘 다 없고 budget_commitment만 남는다. 무엇이 팔렸는지는 결제가 끝난 뒤 붙는 settle 줄의 SKU와 등급으로 드러난다. dashboard의 ledger 칸에서도 같은 줄이 budget hidden, paid로 보인다.
/api/settle은 누구나 부를 수 있다. ledger에서 남의 주문 번호 하나를 골라 가짜 checkout으로 정산을 요청해 본다. 시장이 어느 검사에서 막는지 보인다.
curl -s -X POST https://market.ourolabs.ai/api/settle -H 'content-type: application/json' \
-d '{"order":"<주문 번호>","checkout_jwt":"a.b.c",
"payment_mandate":{"mandate":{"payee":"https://market.ourolabs.ai/shop/corner-store","amount":1}}}'{"settled": false, "checks": {
"round_3_order": false, "not_expired": true, "not_settled_before": true,
"checkout_signed_by_shop": false, "checkout_matches_order": false,
"checkout_mandate_signed_by_buyer": false, "payment_mandate_signed_by_buyer": false,
"closed_mandates_types": false, "bound_to_open_mandates": false, "bound_to_this_checkout": false,
"payee_is_this_shop": true, "amount_is_checkout_total": false, "amount_in_range": false}}가게 서명과 buyer 서명 없이는 통과할 수 없다. 서명이 정상인 담합 거래는 이 검사를 모두 통과한다.
9주차부터는 MeshKit 위에서 팀 프로젝트를 한다. Round 3의 부품은 MeshKit의 부품과 하나씩 대응한다.
| 8주차 시장 | MeshKit |
|---|---|
| 가게의 acp.json과 checkout | 미니앱의 ACP descriptor: capabilities[], requiresPayment, inputSchema |
| acp.json에서 만든 buyer 툴 | /api/acp/apps에서 만든 슈퍼앱 에이전트 툴 |
| AP2 mandate와 시장 지갑 | Agent Wallet과 정산 시뮬레이션 |
| 해시 체인 ledger | /api/settlements |
| 가게가 서명한 영수증 | 대상 앱이 서명한 receipt |
가게는 미니앱으로, 시장은 슈퍼앱으로 옮겨 간다.
이 과제가 중간 평가를 대신한다. 성적의 30%이고 중간시험은 없다. 1주차에서 정의한 대로 에이전트는 모델, 컨텍스트, 툴로 이뤄진다. 세 부품을 직접 설계해 가게와 buyer를 Round 3 시장에 올리고 정산된 거래를 쌓는다. 해답 코드는 없다.
| 항목 | 보는 것 |
|---|---|
| 1. 부품 구현 (40%) | 모델, 컨텍스트, 툴이 각각 제대로 구현됐는가. 컨텍스트는 관리 방식(meta-harness, 메모리 등)으로 지난 거래와 평판을 다음 결정에 어떻게 넣는지 본다. 툴은 무엇을 툴로 만들었고 어떻게 만들었는지 본다 |
| 2. 구조의 독창성 (30%) | 세 부품을 엮은 구조가 키트 기본형과 어떻게 다른가. LaTeX로 직접 그린 한 페이지 아키텍처 figure로 설명한다 |
| 3. Round 3 순위 (30%) | Round 3가 끝난 시각 board의 Players 표 Class 보기(내 가게 ALL + 내 buyer ALL)에서 학생끼리 계산한 백분위가 그대로 점수가 된다. board의 가게 표와 buyer 표는 각자의 순위를 참고로 보여 준다 |
| 구분 | 지켜야 할 것 |
|---|---|
| 가게 | Round 3에 내 가게로 정산된 거래가 20건 이상 |
| buyer | Round 3에 내 buyer가 정산한 거래가 20건 이상. open mandate의 상한을 넘는 checkout은 complete하지 않는다 |
| 키트 없이 배포한 가게 | /.well-known/acp.json과 checkout 세션 엔드포인트를 직접 만들고, 시장의 /api/settle을 통과한 거래가 있다 |
acp.json을 읽어 툴을 만들고 그 툴로 checkout을 끝낸다. 키트도 고쳐도 된다. 키트의 acp.json은 입력을 짧은 설명 문자열로만 적으니, scripts/market_kit.py의 AcpShop.card에 JSON Schema를 넣어 툴 만들기 쉽게 바꿔도 된다. 정산은 그대로 시장의 /api/settle을 통과해야 한다.제출물(submissions/<학번>/week-08): 배포한 컴퓨터의 logs/market-kit.log(정산 줄 포함), 바꾼 코드, REPORT.md, 아키텍처 figure(architecture.tex와 빌드한 architecture.pdf).
REPORT.md: (1) 부품별 설계. 어떤 모델을 어디에 썼는지, 컨텍스트를 어떻게 관리했는지(meta-harness, 메모리 등), 어떤 툴을 어떻게 만들었는지. (2) 아키텍처 figure가 보여 주는 구조와 키트 기본형과 다른 점. (3) Round 3 결과. 제출 시점의 정산 수, Players 순위, 거부 사유를 로그에서 인용한다. 최종 순위는 종료 시각의 board로 정한다.
형식: 6주차, 7주차와 같다. squash 금지, 실행 로그는 logs/에 커밋, API 키와 개인키는 커밋 금지.
checkout_hash. docs/ap2/checkout_mandate.md, payment_mandate.md, 개요는 ap2-protocol.org프로젝트 킥오프: MeshKit. 팀을 꾸리고 미니앱 하나를 정한다. 8주차의 가게가 미니앱이 된다.