Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion courses/build-on-andamio/00-course.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ All 32 SLTs are now backed by at least one of the above sources. No SLT requires
All external dependencies have been resolved as of 2026-04-06:

- **`tx-loops.yaml`** — landed 2026-04-06. 16 canonical loops with dotted names, steps, roles, costs. Lives at `reference/tx-loops.yaml`.
- **Cohort-scale cost math** — confirmed linear per student (~1.32 ADA × N). Reflected in `tx-loops.yaml` loop 13 (`course.credential.cohort`).
- **Cohort-scale cost math** — confirmed linear per student (~1.27 ADA × N). Reflected in `tx-loops.yaml` loop 13 (`course.credential.cohort`).
- **Cost-registry key rename** — `single-credential` → `course.credential`, `multi-assignment-credential` → `course.credential.with-updates`. Keys now match tx-loop names.
- **DB API PENDING_TX** — resolved in `andamio-db-api-go#181`. Module status can now be set to PENDING_TX via API.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Before any on-chain transaction, you create the module record in the Andamio API
### Create the module with SLTs

```bash
andamio course create-module "$COURSE_ID" \
andamio course create-module --course-id "$COURSE_ID" \
--code 100 \
--title "Getting Started" \
--slt "I can explain the Andamio transaction state machine" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,35 @@ Modules are on-chain. Content is published. A student is ready to enroll. What h
A course assignment commitment moves through these states:

```
AWAITING_SUBMISSION → SUBMITTED → ACCEPTED → credential claimed
→ REFUSED → AWAITING_SUBMISSION (retry)
assignment_submit → SUBMITTED → ACCEPTED → CREDENTIAL_CLAIMED
→ REFUSED → SUBMITTED (resubmit)
```

Each arrow is a transaction that goes through the five-step state machine from M400.

| State | Set by | What it means |
|-------|--------|--------------|
| `AWAITING_SUBMISSION` | Student creates commitment (off-chain) | Student is enrolled but hasn't submitted evidence yet |
| `SUBMITTED` | Student's `assignment_submit` TX reaches `updated` | Evidence is on-chain, waiting for teacher review |
| `SUBMITTED` | Student's `assignment_submit` TX reaches `updated` | Student is enrolled and their evidence is on-chain, waiting for teacher review |
| `ACCEPTED` | Teacher's `assessment_assess` TX reaches `updated` | Teacher approved the evidence. Student can claim credential. |
| `REFUSED` | Teacher's `assessment_assess` TX reaches `updated` | Teacher rejected the evidence. Student can resubmit. |
| `CREDENTIAL_CLAIMED` | Student's `credential_claim` TX reaches `updated` | The credential NFT is in the student's wallet. Terminal. |

## Two outcomes, not three

Course assignments have two assessment outcomes: **accept** and **refuse**.

- **Accept** means the evidence meets the SLT criteria. The student can claim a credential.
- **Refuse** means "try again." The commitment reverts to `AWAITING_SUBMISSION` and the student can submit new evidence. There's no penalty and no limit on resubmissions.
- **Refuse** means "try again." The commitment moves to `REFUSED`, and the student can submit new evidence, which puts it back in `SUBMITTED`. There's no penalty and no limit on resubmissions.

There is no "deny" for course assignments. A teacher can refuse indefinitely, but can't permanently remove a student from a module. This is deliberate — courses are about learning, and a student who hasn't met the bar yet is a student who needs another attempt, not expulsion.

Projects are different. M600 introduces the third outcome: **deny**, which is terminal. The distinction matters, and it maps to the difference between learning and contribution.

## Off-chain before on-chain
## Enrollment is the first submission

Before the `assignment_submit` transaction, the student creates a commitment record off-chain:
There is no separate step to create a commitment. The student's first `assignment_submit` transaction enrolls them and carries their initial evidence in `assignment_info` (up to 140 characters). When that transaction is confirmed, Andamio creates the commitment record directly in `SUBMITTED`.

```bash
andamio course student commitment create \
--course-id "$COURSE_ID" \
--module-code 100
```

This creates an `AWAITING_SUBMISSION` record in the Andamio API. Without it, the enrollment transaction fails — the API's batch confirm looks for an off-chain record to match the on-chain state, and returns 404 without one.

The module must have assignment content before this command succeeds. If the teacher published the module on-chain (M500.3) but hasn't imported content yet, students can't create commitments.
The module must be on-chain with assignment content first. If the teacher published the module on-chain (M500.3) but hasn't imported the assignment yet, the confirmation fails with a module-not-found error.

## The pending states

Expand All @@ -67,7 +59,7 @@ Between stable states, records pass through `PENDING_TX_*` states while waiting
| Transition | Pending state | On TX expiry |
|-----------|--------------|--------------|
| First enrollment | `PENDING_TX_COMMIT` | **No revert** — no prior state exists |
| Submit evidence | `PENDING_TX_SUBMIT` | Reverts to `AWAITING_SUBMISSION` |
| Resubmit evidence | `PENDING_TX_SUBMIT` | Reverts to `REFUSED` |
| Teacher assesses | `PENDING_TX_ASSESS` | Reverts to `SUBMITTED` |
| Claim credential | `PENDING_TX_CLAIM` | Reverts to `ACCEPTED` |

Expand All @@ -92,18 +84,15 @@ One transaction, multiple students, mixed outcomes. This is how real courses wor
## The full picture

```
Off-chain: student creates commitment
→ AWAITING_SUBMISSION

On-chain: assignment_submit (student)
On-chain: assignment_submit (student) — enrolls and submits
→ SUBMITTED

On-chain: assessment_assess (teacher)
→ ACCEPTED (student can claim)
→ REFUSED (student retries → AWAITING_SUBMISSION)
→ REFUSED (student resubmits → SUBMITTED)

On-chain: credential_claim (student)
→ credential NFT in wallet
→ CREDENTIAL_CLAIMED, credential NFT in wallet
```

Four roles for three transactions. The teacher never touches the enrollment or claim — those are student-initiated. The student never touches the assessment — that's the teacher's decision. Separation of concerns, enforced by the protocol.
Expand All @@ -117,12 +106,12 @@ Write your answers before checking the rubric.

## Rubric

1. After a refuse, the commitment is back in `AWAITING_SUBMISSION`. The student submits new or revised evidence with another `assignment_submit` transaction. No limit on retries.
1. After a refuse, the commitment is in `REFUSED`. The student submits new or revised evidence in another on-chain submission, which moves it back to `SUBMITTED`. No limit on retries.
2. Two outcomes because courses are about learning — a student who hasn't met the bar needs another attempt, not expulsion. A "deny" would permanently bar the student from earning a credential for that module. Projects use deny because contributions involve treasury funds and teams can't afford indefinite retry loops. The domain difference (learning vs paid work) drives the outcome set.

## What you just did

You understand the arc from enrollment to credential: the four stable states, the two assessment outcomes, the off-chain prerequisite, and batch assessment. You also know why courses have two outcomes where projects will have three — the domain shapes the protocol.
You understand the arc from enrollment to credential: the stable states, the two assessment outcomes, why enrollment is also the first submission, and batch assessment. You also know why courses have two outcomes where projects will have three — the domain shapes the protocol.

## What's next

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,45 @@ evidence_type: tx_hash

## Before we start

You know the structure, the hash, the publishing flow, and the commitment lifecycle. This lesson puts them together: create a course, publish a module, enroll a student, submit evidence, assess it, and claim a credential. Six on-chain transactions, one loop.
You know the structure, the hash, the publishing flow, and the commitment lifecycle. This lesson puts them together: create a course, publish a module, enroll a student, submit evidence, assess it, and claim a credential. Six on-chain transactions, two loops.

The reference for this lesson is `examples/course-lifecycle.sh` — a runnable script that executes every step below. You can read along, run the script, or run each transaction manually.

To run the steps by hand, set these first:

```bash
export SKEY_PATH=/path/to/payment.skey
ALIAS=$(andamio user status --output json | jq -r '.user_alias')
```

## The course.setup loop

Two transactions create the course and publish a module. This is the `course.setup` loop from `reference/tx-loops.yaml`.

### TX 1: Create the course

```bash
andamio tx run /v2/tx/instance/owner/course/create \
COURSE_ID=$(andamio tx run /v2/tx/instance/owner/course/create \
--body '{"alias":"'"$ALIAS"'","teachers":["'"$ALIAS"'"]}' \
--skey "$SKEY_PATH" \
--tx-type course_create
--tx-type course_create \
--output json | jq -r '.build_response.course_id')
```

Creates the course on-chain: mints the LocalStateNFT (whose policy ID becomes the `course_id`), LocalStateToken, and governance token. Cost: ~119.3 ADA (100 ADA service fee + ~18.8 ADA in minUTxO deposits + ~0.56 ADA tx fee). Name every teacher here: a teacher added after creation pays a further 10 ADA service fee.

After this reaches `updated`, discover the `course_id`:

```bash
COURSE_ID=$(andamio course list --output json \
| python3 -c "import json,sys; print(json.load(sys.stdin)['data'][-1]['course_id'])")
```
The builder returns the new `course_id` in its response, so the command above captures it once the transaction reaches `updated`.

### TX 2: Publish a module

Three off-chain steps, then one transaction (covered in detail in M500.3):

```bash
# Off-chain: create module, approve, advance to PENDING_TX
andamio course create-module "$COURSE_ID" \
SLT_HASH=$(andamio course create-module --course-id "$COURSE_ID" \
--code 100 --title "Getting Started" \
--slt "Learner can explain the Andamio transaction state machine" \
--approve
--approve --output json | jq -r '.slt_hash')

andamio course teacher update-module-status \
--course-id "$COURSE_ID" --module-code 100 --status PENDING_TX
Expand All @@ -76,18 +79,14 @@ Four transactions take a student from enrollment to credential. This is the `cou
### TX 3: Student enrolls

```bash
# Off-chain: create commitment record
andamio course student commitment create \
--course-id "$COURSE_ID" --module-code 100

# On-chain: enrollment + initial evidence
# On-chain: enrollment + initial evidence (this also creates the commitment)
andamio tx run /v2/tx/course/student/assignment/commit \
--body '{"alias":"'"$ALIAS"'","course_id":"'"$COURSE_ID"'","slt_hash":"'"$SLT_HASH"'","assignment_info":"Enrolling in module 100"}' \
--skey "$SKEY_PATH" \
--tx-type assignment_submit
```

Cost: ~2.14 ADA (includes ~1.45 ADA enrollment deposit, refunded at credential claim). The `assignment_info` field is the student's initial evidence — it can be updated before the teacher assesses.
Cost: ~2.64 ADA (includes ~2.3 ADA locked in the course-state UTxO, mostly returned at credential claim). When it reaches `updated`, the commitment exists and is already `SUBMITTED` — there is no separate create step. The `assignment_info` field is the student's initial evidence — it can be updated before the teacher assesses.

### TX 4: Student updates evidence (optional)

Expand All @@ -109,7 +108,7 @@ andamio tx run /v2/tx/course/teacher/assignments/assess \
--tx-type assessment_assess
```

Cost: ~0.21 ADA (teacher actually gets a small refund because the datum shrinks after grading). The `assignment_decisions` array can include multiple students in one transaction (batch assessment from M500.4).
Cost: ~0.27 ADA, the network fee. The `assignment_decisions` array can include multiple students in one transaction (batch assessment from M500.4).

### TX 6: Student claims credential

Expand All @@ -120,24 +119,24 @@ andamio tx run /v2/tx/course/student/credential/claim \
--tx-type credential_claim
```

Cost: **net negative**. The student gains ~1.03 ADA because the enrollment deposit is refunded and the CourseState token is burned. A credential claim is the only transaction where the initiator ends with more ADA than they started.
Cost: **net negative**. The student gains ~1.65 ADA because the enrollment deposit is refunded and the CourseState token is burned. A credential claim is the only transaction where the initiator ends with more ADA than they started.

The credential NFT is now in the student's wallet — permanent, portable, tied to the `slt_hash`.

## Cost summary

The `course.credential` loop costs ~1.32 ADA total (student: ~1.11 ADA net; teacher: ~0.21 ADA). For a cohort of N students, the cost scales linearly: ~1.32 ADA × N.
The `course.credential` loop costs ~1.27 ADA total (student: ~0.99 ADA net; teacher: ~0.27 ADA). For a cohort of N students, the cost scales linearly: ~1.27 ADA × N.

The `course.setup` loop costs ~121 ADA for a one-module course. Setup is a one-time cost; the credential loop runs per student per module.

| Transaction | Paid by | Cost |
|-------------|---------|------|
| `course_create` | Owner | ~119.3 ADA |
| `modules_manage` | Teacher | ~1.86 ADA |
| `assignment_submit` | Student | ~2.14 ADA |
| `assignment_submit` | Student | ~2.64 ADA |
| `assignment_update` | Student | ~0.33 ADA (optional, per update) |
| `assessment_assess` | Teacher | ~0.21 ADA |
| `credential_claim` | Student | -1.03 ADA (refund) |
| `assessment_assess` | Teacher | ~0.27 ADA |
| `credential_claim` | Student | -1.65 ADA (refund) |

## Running the example script

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ Courses and projects share the transaction state machine from M400 and the same
| **Participant role** | Student | Contributor |
| **Treasury** | None — no on-chain funds | Real ADA locked in an on-chain treasury |
| **Escrow** | None | Task reward locked in escrow until assessment |
| **Deposit** | ~1.45 ADA (enrollment) | ~14.5 ADA (contributor state) |
| **Deposit** | ~2.3 ADA (enrollment) | ~2.3 ADA (contributor state) |
| **Assessment outcomes** | Accept, Refuse | Accept, Refuse, **Deny** |
| **Credential claim** | Net positive (~1.03 ADA refund) | Net positive (deposit refund + task reward - 5% commission) |
| **Credential claim** | Net positive (~1.65 ADA back) | Net positive (deposit refund + task reward − commission, 5% with a 1 ADA minimum) |
| **Prerequisite** | None by default | Requires a course credential |

## The treasury
Expand All @@ -49,7 +49,7 @@ When a manager publishes a task (via `tasks_manage`), the task's reward moves fr
- **Refuse** → reward stays in escrow, contributor resubmits.
- **Deny** → reward returns to treasury, contributor is removed.

The escrow is what makes projects trustless. The contributor knows the reward exists before committing. The manager knows the contributor has skin in the game (~14.5 ADA deposit). Neither party has to trust the other — the protocol enforces the deal.
The escrow is what makes projects trustless. The contributor knows the reward exists before committing. The manager knows the contributor has skin in the game (~2.3 ADA locked at commit). Neither party has to trust the other — the protocol enforces the deal.

## Three outcomes, not two

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ The difference from courses is the third outcome and what each outcome does to t
### Accept

The contributor's work meets the bar. On credential claim:
- The ~14.5 ADA state deposit returns to the contributor.
- The task reward transfers from escrow to the contributor, minus a 5% commission.
- The ADA locked in the contributor state at `project_join` (~2.3 ADA) returns to the contributor.
- The task reward transfers from escrow to the contributor, minus the commission: 5% of the reward, with a 1 ADA minimum.
- A credential NFT is minted to the contributor's wallet.

Net: contributor gains ADA. Credential claims are the only transaction where the initiator ends richer.
Expand All @@ -53,22 +53,22 @@ Refuse is not punitive — it's iterative. A contributor who gets refused three

### Deny

Terminal. The contributor is permanently removed from the project. The task reward returns from escrow to the treasury. The contributor's ~14.5 ADA state deposit is refunded (deny removes the contributor, it doesn't confiscate their deposit). No credential is issued.
Terminal. The contributor is permanently removed from the project. The task reward returns from escrow to the treasury. The ~2.3 ADA the contributor locked is refunded (deny removes the contributor, it doesn't confiscate their deposit). No credential is issued.

Deny exists because projects involve real money. A contributor acting in bad faith — plagiarizing, spamming, or submitting malicious code — needs to be removable, and the treasury needs to recover the reward for reassignment.

There is no un-deny. A denied contributor cannot rejoin the project.

## The deposit mechanics

The contributor's ~14.5 ADA deposit at `project_join` serves two purposes:
The ~2.3 ADA the contributor locks at `project_join` serves two purposes:

1. **Spam prevention.** Committing to a task costs real ADA. A contributor who commits to a task and never submits evidence has ADA locked in a pending state. The deposit creates a cost for occupying task slots.
2. **State UTxO funding.** The deposit pays for the on-chain UTxO that holds the contributor's state. When the credential is claimed, the UTxO is burned and the ADA returns.

The deposit is always refunded — on accept (via credential claim) and on deny. The contributor doesn't lose their deposit; they lose the opportunity cost of having it locked.

Compare with courses: the enrollment deposit is ~1.45 ADA, ten times smaller. The difference reflects the economic stakes. Courses are about learning (low stakes). Projects are about funded work (higher stakes, higher deposit).
Compare with courses: enrollment locks about the same amount (~2.3 ADA). The deposit is not where courses and projects differ. The economic stakes of a project live in its treasury and escrow — real rewards that a bad-faith contributor could tie up — which is why projects add the `deny` outcome.

## The escrow flow

Expand All @@ -77,9 +77,9 @@ Follow the ADA through the project lifecycle:
```
Treasury (owner funds it)
→ tasks_manage: reward moves to escrow
→ project_join: contributor deposits ~14.5 ADA
→ project_join: contributor locks ~2.3 ADA
→ task_assess (accept): reward stays in escrow, waiting for claim
→ credential_claim: reward (minus 5%) → contributor, deposit → contributor
→ credential_claim: reward (minus commission) → contributor, deposit → contributor
→ task_assess (refuse): reward stays in escrow, contributor retries
→ task_assess (deny): reward returns to treasury, deposit → contributor
```
Expand Down Expand Up @@ -126,7 +126,7 @@ Write your answers before checking the rubric.
## Rubric

1. The reward stays in escrow — refuse doesn't move money. The contributor submits a new `project_join` transaction with revised evidence. No limit on retries.
2. The reward returns from escrow to the treasury. The contributor's ~14.5 ADA deposit is refunded. The contributor is permanently removed — they can't rejoin this project.
2. The reward returns from escrow to the treasury. The ~2.3 ADA the contributor locked is refunded. The contributor is permanently removed — they can't rejoin this project.
3. Projects involve real money (treasury, escrow, rewards). A bad-faith contributor occupying a funded task slot needs to be removable, and the treasury needs to recover the reward. Courses don't have this problem because there's no treasury and no financial incentive to game the system.

## What you just did
Expand Down
Loading
Loading