Encoding the Point Where You Stop
Goal
Before changing production data, decide the place to stop and make the code actually enforce that criterion. You also check that no half-applied state is left behind when the criterion trips.
Request
Please change the PENDING orders in the EAST region to CANCELLED. It is about 120 rows.
Environment
You work under /root/change. You build the site yourself — it is preparation, not
the assignment.
mkdir -p /root/change && cd /root/change
python3 - <<'PY'
import sqlite3, random, datetime
random.seed(23)
con = sqlite3.connect('app.db'); cur = con.cursor()
cur.execute("create table orders(id integer primary key, status text, region text, amount int, created_at text)")
base = datetime.datetime(2026, 8, 1); rows = []; oid = 1
for region, n in (('EAST', 480), ('WEST', 210), ('NORTH', 60), ('SOUTH', 35)):
for _ in range(n):
rows.append((oid, 'PENDING', region, random.randint(1000, 90000),
(base + datetime.timedelta(days=random.randint(0, 30))).isoformat())); oid += 1
for region in ('EAST', 'WEST', 'NORTH', 'SOUTH'):
for _ in range(random.randint(200, 400)):
rows.append((oid, random.choice(['PAID', 'SHIPPED']), region, random.randint(1000, 90000),
(base + datetime.timedelta(days=random.randint(0, 30))).isoformat())); oid += 1
cur.executemany("insert into orders values (?,?,?,?,?)", rows); con.commit(); con.close()
PY
sqlite3 app.db "select region, count(*) from orders where status='PENDING' group by 1"
What to create
scope.txt 요청서 예상과 실제 대상의 차이
abort.md 중단 기준 (지표 · 임계값 · 행동)
restore.sh 스냅숏에서 되돌리는 스크립트
apply.sh 배치로 적용하되 기준에 걸리면 되돌리는 스크립트
split.md 되돌릴 수 없는 변경을 두 단계로 쪼개는 방법
stopped.md 멈췄다는 사실을 알리는 보고
apply.sh takes one request file as an argument.
region=EAST
expected=120
limit=0 0 이면 전부, 숫자면 그만큼만
How it is graded
Each time, after restoring the site to its original state, the grader runs your apply.sh directly with three
requests and compares the DB before and after the run.
region=WEST expected=150 limit=150 통과해야 한다 — 정확히 150건만 바뀐다
The third one matters. If it only blocks and gets no work done, that is a failure too.
Steps
- Count before you change anything. Write the actual target and the request's expectation side by side.
- In
abort.md, write two or more abort criteria. Each must have all three: the indicator to observe, the value that must not be exceeded, and the action to take then. restore.sh— takes a snapshot path and rolls back. The grader deliberately breaks the DB and then checks whether this script recovers it.- The scope criterion of
apply.sh— if the actual target exceeds twice the expectation, change nothing and exit with a non-zero code. - The invariant criterion of
apply.sh— if the PENDING count of any region falls below 20, stop and roll back even what has already been applied. - Under the narrowed condition, exactly that many rows must be applied.
split.md— split an irreversible change into two reversible steps.stopped.md— the fact you stopped, the reason, the scope you rolled back, and the conditions for trying again.
Notes
Step 5 is the hardest place in this lab. Check on every batch, but when it trips, you must not stand there. A half-changed state is in no document, so stopping usually means rolling back. The snapshot you made in step 3 is used here — if you do not build the means to roll back first, you have no means to execute the abort criteria even if you have them.
Count before you change
Count before you change anything. Write the actual target and the request's expectation side by side.
The request said 120 rows. First count how many there actually are, and write the two side by side. If you learn this difference during the run, it is already too late.
Write the place to stop on paper
In abort.md, write two or more abort criteria. Each must have all three: the indicator to observe,
the value that must not be exceeded, and the action to take then.
Each criterion needs all three things — the indicator to observe, the value that must not be exceeded (an inequality and a number), and the action to take then. If even one of the three is missing, room for interpretation appears during the run, and room for interpretation is always used in favor of continuing.
Build the means to roll back first
restore.sh — takes a snapshot path and rolls back. The grader deliberately breaks the DB
and then checks whether this script recovers it.
Take the snapshot path as an argument and roll back. The grader deliberately breaks the DB and then checks whether this script recovers it — if it only prints a message and does not actually roll back, you fail.
The scope criterion blocks the run
The scope criterion of apply.sh — if the actual target exceeds twice the expectation, change nothing
and exit with a non-zero code.
If the actual target exceeds twice the expectation, change nothing and exit with a non-zero code. The grader compares the DB before and after the run, so if even one row changes, you fail.
Roll back if it trips midway
The invariant criterion of apply.sh — if the PENDING count of any region falls below 20,
stop and roll back even what has already been applied.
Check the invariant on every batch, and if it trips, roll back using the snapshot from step 3. You must not stand there — a half-changed state is in no document.
It must pass when narrowed
Under the narrowed condition, exactly that many rows must be applied.
If it only blocks and gets no work done, that is a failure too. Respect limit so that exactly that many rows are applied, and do not go below the lower bound either.
Split what cannot be undone
split.md — split an irreversible change into two reversible steps.
The best abort criterion is not to create an irreversible change at all. If you leave a deletion marker instead of deleting and delete after a grace period, one irreversible step becomes two reversible steps.
The fact that you stopped is also something to report
stopped.md — the fact you stopped, the reason, the scope you rolled back, and the conditions for trying again.
If you pass over it saying nothing happened because you rolled back, the customer will later find the trace in the logs and read it as you hiding it. The fact you stopped, the reason, the scope you rolled back, and the conditions for trying again — these four make one cycle.