Summary
write_checkpoint()'s existing "GATE VIOLATION" check only guards the stage being written right now — it never checks whether earlier stages in the pipeline sequence were actually approved before allowing a write to a later stage.
_stage_requires_approval() only resolves the gate policy for the one stage passed in. get_pipeline_stages() is used only to validate that the stage name is legal, never to check ordering. Sequence-aware helpers (get_completed_stages(), get_next_stage()) exist but write_checkpoint() never calls them — they're advisory, described in skills/meta/checkpoint-protocol.md as something the agent should check, not something the writer enforces.
Real-world impact
Hit this in production: a scene_plan checkpoint sat status="awaiting_human", human_approved=false continuously for several days — three rewrites, never once approved — while checkpoint_assets.json/checkpoint_edit.json/checkpoint_compose.json were all written afterward with no error. A bridge script explicitly relied on this gap, using status="in_progress" specifically to avoid triggering the existing same-stage check. tests/backlot/test_gate_scenarios.py only covers same-stage violations — no test exercised predecessor-stage validation.
Proposed fix
Add a helper that walks get_pipeline_stages(pipeline_type) up to the stage being written, and for each gated predecessor reads its checkpoint via read_checkpoint(); if any predecessor isn't completed+human_approved, raise a new SEQUENCE GATE VIOLATION CheckpointValidationError. Should only fire when status != "in_progress", so existing resume/liveness heartbeats keep working.
A PR implementing this (with new + updated tests, full suite passing) will follow.
Summary
write_checkpoint()'s existing "GATE VIOLATION" check only guards the stage being written right now — it never checks whether earlier stages in the pipeline sequence were actually approved before allowing a write to a later stage._stage_requires_approval()only resolves the gate policy for the one stage passed in.get_pipeline_stages()is used only to validate that the stage name is legal, never to check ordering. Sequence-aware helpers (get_completed_stages(),get_next_stage()) exist butwrite_checkpoint()never calls them — they're advisory, described inskills/meta/checkpoint-protocol.mdas something the agent should check, not something the writer enforces.Real-world impact
Hit this in production: a
scene_plancheckpoint satstatus="awaiting_human",human_approved=falsecontinuously for several days — three rewrites, never once approved — whilecheckpoint_assets.json/checkpoint_edit.json/checkpoint_compose.jsonwere all written afterward with no error. A bridge script explicitly relied on this gap, usingstatus="in_progress"specifically to avoid triggering the existing same-stage check.tests/backlot/test_gate_scenarios.pyonly covers same-stage violations — no test exercised predecessor-stage validation.Proposed fix
Add a helper that walks
get_pipeline_stages(pipeline_type)up to the stage being written, and for each gated predecessor reads its checkpoint viaread_checkpoint(); if any predecessor isn'tcompleted+human_approved, raise a newSEQUENCE GATE VIOLATIONCheckpointValidationError. Should only fire whenstatus != "in_progress", so existing resume/liveness heartbeats keep working.A PR implementing this (with new + updated tests, full suite passing) will follow.