v1.6.0 — Ignition Lock
Ignition Lock
A transition can be fully legal — evidence fresh, gate green, everything the FPF logic computes says fire — and still not be cleared to fire without a human turning the key. That's the new mechanism this release adds, named off vocabulary the library already had (can_fire) rather than borrowed HITL jargon.
TransitionPrimitive.requires_human_authorization — a transition can opt into needing authorized=True to fire, enforced at ActiveState.transition_to() itself so there's no lower-level bypass. The model still sees everything (step()/slice() report evidence, gate status, all of it) — it just can't pull the trigger alone.
ActiveState.pending_authorizations (set[str]) — every currently-unresolved escalated ask, plural on purpose: an earlier single-value design silently lost track of one ask the moment a second, different transition also escalated. Found and fixed via adversarial live testing against two concurrent destructive requests, not by code review.
Abort to Orbit — TransitionPrimitive.safe_alternatives names a transition's non-destructive twins (archive instead of hard delete), surfaced before the model ever attempts the destructive move. ActiveState.deny_pending_authorization(transition_id, reason) records an explicit "no" as a fact, not a void — and doesn't lock the door permanently, a later authorized=True still fires.
Two new integrator advisories (ADV-10, ADV-11, both auto-detected by dev_mcp): a keyword-heuristic lint for destructive-sounding transitions with no gate set, and a soundness check for safe_alternatives declarations (dangling references, an alternative that's itself gated, an alternative already denied). Both explicitly heuristic, explicitly not enforcement — same honesty as the existing advisories.
Fixes: ESCALATE now surfaces missing evidence alongside the auth requirement instead of hiding it; dev_mcp's compliance wrapper forwards authorized= (and future kwargs generally) instead of silently dropping them.
23/23 core verify, 38/38 dev_mcp self-test. All changes purely additive over v1.5.0 — nothing published ever had a field renamed out from under it.