doctor's kill-switch finding tells the operator to run a command that cannot clear the kill switch.
Finding(
"rail.kill_switch",
HALTED,
"kill switch engaged",
"every entry is vetoed; this is a correct state, not a fault",
"keel autonomy on", # <- does not do this
)
autonomy_on calls repo.set_autonomous(True, ...) and nothing else. Its own docstring says so in terms:
It does NOT let the agent clear a safety halt: releasing the kill-switch or a drawdown breaker always needs a human, whatever this is set to.
The command that clears it is keel resume (trading.disengage_kill_switch → repo.set_state("kill_switch", False)).
How it plays out
Observed while bootstrapping the equities profile on 2026-09-02. A fresh database defaults the kill switch to engaged, so the first cycle prints skipped: kill_switch. Following doctor's advice:
$ keel ... autonomy on
About to turn autonomy ON. Type "yes" to confirm: yes
autonomy ON, with NO expiry
$ keel ... agent
[1788361666] skipped: kill_switch <- unchanged
The operator has now typed a confirmation for a dangerous capability — unattended order placement — and is still halted, with no indication that the two are different gates. Arming autonomy while still halted is strictly worse than either state alone: it grants the risky half and withholds the harmless one.
Why the wording matters more than usual here
These are deliberately separate controls and the separation is load-bearing: who gets asked versus whether the agent runs at all. A fix line that conflates them teaches the operator they are one thing, which is the opposite of what the design says. keel kill / keel resume and keel autonomy on / off are two pairs on purpose.
Acceptance
doctor's kill-switch finding tells the operator to run a command that cannot clear the kill switch.autonomy_oncallsrepo.set_autonomous(True, ...)and nothing else. Its own docstring says so in terms:The command that clears it is
keel resume(trading.disengage_kill_switch→repo.set_state("kill_switch", False)).How it plays out
Observed while bootstrapping the equities profile on 2026-09-02. A fresh database defaults the kill switch to engaged, so the first cycle prints
skipped: kill_switch. Followingdoctor's advice:The operator has now typed a confirmation for a dangerous capability — unattended order placement — and is still halted, with no indication that the two are different gates. Arming autonomy while still halted is strictly worse than either state alone: it grants the risky half and withholds the harmless one.
Why the wording matters more than usual here
These are deliberately separate controls and the separation is load-bearing: who gets asked versus whether the agent runs at all. A fix line that conflates them teaches the operator they are one thing, which is the opposite of what the design says.
keel kill/keel resumeandkeel autonomy on/offare two pairs on purpose.Acceptance
rail.kill_switch's fix line nameskeel resume.doctorfix line names a command that can actually produce the state it describes — pinned by a test, because this is the second doc/behaviour drift found by running the documented path (see the rail-count drift, fix(docs): the rail count drifted to five different answers in one commit #687).Finding.fix, check it exists in the CLI, and where a finding names a state, check the named command touches it. A finding whose fix is prose (-, "see the runbook") is out of scope.