Found while fixing the identical bug in devague lapse, which Qodo caught
on PR #101. lapse was
cloned from deviate, so it inherited the defect — the lapse half is fixed
on that branch; this issue is the pre-existing deviate half, filed
separately so the fix to a released verb stays reviewable on its own.
Reproduction
Against a repo with a current plan (read-only — nothing is written):
$ devague deviate --task t1 --reason "probe: is this silently dropped?"
d1: the split-plan --write path escapes verbatim task text before writing markdown (task t5, approved) [acceptable]
$ echo $?
0
The command listed the existing ledger and exited 0. No deviation was
recorded, and nothing said so.
Cause
cmd_deviate (devague/cli/_commands/deviate.py) dispatches on the presence
of the positional what:
if args.confirm:
return _resolve_status(args, args.confirm, "approved")
if args.reject:
return _resolve_status(args, args.reject, "rejected")
if args.what:
return _record(args)
return _list(args)
_record does validate that --task and --reason are present — but it is
never reached, because a missing what routes to _list first. Every
record-only flag (--task, --reason, --affects, --classification,
--origin) is silently discarded.
Why this is worse for deviate than it was for lapse
The /deviate skill's protocol is: stop the run, get explicit human approval,
record it, then resume. Step 4 producing a silent no-op means the run
resumes believing an approved departure is on the record when it is not — and
/summarize-delivery later reads that same empty ledger as ground truth for
Drift From Plan. A deviation the human approved would simply vanish, and the
delivery summary would look clean.
Suggested fix
The same guard now in lapse.py on the #101 branch: when what is absent,
collect any record-only flags that were given and refuse with a hint naming
them, rather than falling through to _list. Note --origin needs
default=None (resolved back to "user" at record time) for an explicit
--origin to be distinguishable from the default.
Worth auditing the other verbs with an optional positional and a
list/record split for the same shape while in there.
Found while fixing the identical bug in
devague lapse, which Qodo caughton PR #101.
lapsewascloned from
deviate, so it inherited the defect — thelapsehalf is fixedon that branch; this issue is the pre-existing
deviatehalf, filedseparately so the fix to a released verb stays reviewable on its own.
Reproduction
Against a repo with a current plan (read-only — nothing is written):
The command listed the existing ledger and exited
0. No deviation wasrecorded, and nothing said so.
Cause
cmd_deviate(devague/cli/_commands/deviate.py) dispatches on the presenceof the positional
what:_recorddoes validate that--taskand--reasonare present — but it isnever reached, because a missing
whatroutes to_listfirst. Everyrecord-only flag (
--task,--reason,--affects,--classification,--origin) is silently discarded.Why this is worse for
deviatethan it was forlapseThe
/deviateskill's protocol is: stop the run, get explicit human approval,record it, then resume. Step 4 producing a silent no-op means the run
resumes believing an approved departure is on the record when it is not — and
/summarize-deliverylater reads that same empty ledger as ground truth forDrift From Plan. A deviation the human approved would simply vanish, and the
delivery summary would look clean.
Suggested fix
The same guard now in
lapse.pyon the #101 branch: whenwhatis absent,collect any record-only flags that were given and refuse with a hint naming
them, rather than falling through to
_list. Note--originneedsdefault=None(resolved back to"user"at record time) for an explicit--originto be distinguishable from the default.Worth auditing the other verbs with an optional positional and a
list/record split for the same shape while in there.