Checkpoint
One last thing before we move on. Same surface as a write step — but the lesson doesn't complete until this passes.
Checkpoint: the full calendar gate, the one that runs before anything touches the scheduling tool.
Write gate(rows) returning a dict with three lists, each preserving
row order:
"schedule"— rows withstatus == "approved"AND a non-emptyapproved_by. These may enter the scheduler."blocked"— rows withstatus == "approved"but NO approver. These go back for a named sign-off, not into the scheduler."rejected"— rows withstatus == "rejected". These stay in the file as the record of what the team said no to.
The harness prints each list and a summary. The rows are the full relaunch calendar so far — including the teaser-story that's been sitting nameless since the gate first caught it. Expected output:
SCHEDULE 09-02 email launch-email (dana)
SCHEDULE 09-04 ads ad-set-a (sam)
SCHEDULE 09-05 email winback (sam)
BLOCKED 09-02 social teaser-story (no approver)
KEPT 09-03 social meme-post (rejected, stays in the file)
3 scheduled, 1 blocked, 1 rejected-and-kept