Step 4 — the attorney gate is a graph invariant

Every workflow must pass through staff_review before anything is signed or filed — not as a policy memo, but as a property checked over the state-machine graph itself with a breadth-first search from BEGIN.

From workflows/src/guardrail.rs:

pub fn staff_review_precedes_signature(spec: &WorkflowSpec) -> Result<(), GateViolation> {
    let begin = StateName::begin();
    if let Some(signature) = reaches_target_without_review(spec, &begin, is_signature_state) {
        return Err(GateViolation {
            fill_state: begin.as_str().to_string(),
            submission_state: signature,
        });
    }
    Ok(())
}