Skip to content

Refusals and findings

This reference is generated by anb skill. Command descriptions come from the CLI definitions; examples run against a scratch notebook. CI checks the committed copy for drift.

Refusals carry an error code, a message explaining the condition and a try array of recovery commands. Fill placeholders before running a suggested command. JSON and TOON contain the same values.

The scratch notebook the refusals below run against:

$ anb add task "Ship the parser" --tag epic
ok: add
id: task.ship-the-parser
path: tasks/task.ship-the-parser.md
$ anb add task "Grammar parser accepts fences" --from task.ship-the-parser
ok: add
id: task.grammar-parser-accepts-fences
path: tasks/task.grammar-parser-accepts-fences.md
$ anb add decision "Fences never nest" --kind rule
ok: add
id: decision.fences-never-nest
path: decisions/decision.fences-never-nest.md
$ anb add note Fence --kind term
ok: add
id: note.fence
path: notes/note.fence.md

No record carries the id.

$ anb start task.parser
error: unknown-id
message: no record `task.parser`
try[1]: anb list

The record’s state does not allow the move; the valid moves are listed, each with its command.

$ anb close task.ship-the-parser --body "The parser is verified."
error: invalid-transition
message: "`task.ship-the-parser` is open; valid: start, close --reason"
try[2]: anb start task.ship-the-parser,"anb close task.ship-the-parser --reason \"<why>\""

Another person holds the Task, having started it or been handed it. start takes work nobody holds, so a held Task changes hands through edit --taken-by first, on purpose.

$ anb edit task.grammar-parser-accepts-fences --taken-by Grace
ok: edit
id: task.grammar-parser-accepts-fences
changed[1]: taken-by
already: false
$ anb start task.grammar-parser-accepts-fences
error: taken
message: `task.grammar-parser-accepts-fences` is taken by Grace
try[2]: "anb edit task.grammar-parser-accepts-fences --taken-by \"<name>\"",anb show task.grammar-parser-accepts-fences

A flag or value is invalid for this command or record type. The reply suggests a valid form.

$ anb add decision Tabs --priority 2
error: invalid-argument
message: "priority: applies only to a task"
try[1]: "anb add decision \"<title>\""
$ anb close task.ship-the-parser
error: invalid-argument
message: "close: pass one of --body \"<outcome>\", --body-file <path>, --reason \"<why>\", or --resolved-by <id>"
try[2]: "anb close task.ship-the-parser --body \"<outcome>\"","anb close task.ship-the-parser --reason \"<why>\""

An envelope reference names a record that does not exist.

$ anb add task "A child" --from task.ghost
error: dangling-ref
message: "from: `task.ghost` names no record"
try[2]: "anb add task \"<title>\" --id task.ghost",anb list

The proposed dependency would create a cycle. The reply prints the cycle.

$ anb block task.ship-the-parser task.grammar-parser-accepts-fences
ok: block
id: task.ship-the-parser
on: task.grammar-parser-accepts-fences
already: false
$ anb block task.grammar-parser-accepts-fences task.ship-the-parser
error: would-cycle
message: "the edge would close a dependency cycle: task.grammar-parser-accepts-fences → task.ship-the-parser → task.grammar-parser-accepts-fences"
try[1]: anb unblock task.ship-the-parser task.grammar-parser-accepts-fences

A Task can be started to coordinate its parts, but successful completion requires its prerequisites to be closed. Inspect the listed blockers; do not remove them merely to make closing succeed.

$ anb start task.ship-the-parser
ok: start
id: task.ship-the-parser
from: open
to: active
already: false
record:
id: task.ship-the-parser
path: tasks/task.ship-the-parser.md
more: anb show task.ship-the-parser --all
archived: false
fields:
count: 10
omitted: 0
rows[10]:
- [2]: id,task.ship-the-parser
- [2]: type,task
- [2]: state,active
- [2]: title,Ship the parser
- [2]: by,Ada
- [2]: taken-by,Ada
- [2]: tags,epic
- [2]: blocked-by,task.grammar-parser-accepts-fences
- [2]: created,2026-01-15
- [2]: updated,2026-01-15
body:
lines: 0
characters: 0
head: ""
omitted: 0
from: []
born[1]: task.grammar-parser-accepts-fences
task: []
bound: []
"blocked-by"[1]: task.grammar-parser-accepts-fences
blocks: []
links: []
"linked-by": []
mentions: []
"mentioned-by": []
$ anb close task.ship-the-parser --body "The parser is verified."
error: unfinished-dependencies
message: cannot complete `task.ship-the-parser` while dependencies remain unfinished
findings[1]: task.grammar-parser-accepts-fences
try[1]: anb show task.grammar-parser-accepts-fences
count: 1
omitted: 0
id: task.ship-the-parser

An existing record reserves its id, including in the archive. Only deleting a record frees its id.

$ anb add task "Ship the parser again" --id task.ship-the-parser
error: duplicate-id
message: `task.ship-the-parser` already exists at tasks/task.ship-the-parser.md
try[2]: anb show task.ship-the-parser,"anb add task \"<title>\""

The id names a type the command does not act on.

$ anb start note.fence
error: wrong-type
message: `note.fence` is not a task
try[1]: anb show note.fence

Other records reference this id. The reply identifies the references that prevent deletion.

$ anb delete task.ship-the-parser
error: still-referenced
message: `task.ship-the-parser` is still referenced by 1 record
findings[1]: task.grammar-parser-accepts-fences — from
try[1]: anb show task.grammar-parser-accepts-fences
count: 1
omitted: 0

The target is not eligible for supersession. Only an active Decision or Note can be replaced.

$ anb retire decision.fences-never-nest
ok: retire
id: decision.fences-never-nest
from: active
to: retired
already: false
$ anb add decision "Fences nest once" --kind rule --supersedes decision.fences-never-nest
error: cannot-supersede
message: "cannot supersede `decision.fences-never-nest`: its state is `retired`, not active"
try: []

An archived record is read, never mutated in place; restore brings it back.

$ anb archive decision.fences-never-nest
ok: archive
id: decision.fences-never-nest
from: decisions/decision.fences-never-nest.md
to: archive/decisions/decision.fences-never-nest.md
already: false
$ anb edit decision.fences-never-nest --title Fences
error: archived
message: `decision.fences-never-nest` is archived
try[2]: anb show decision.fences-never-nest,anb restore decision.fences-never-nest

A Task leaves for the archive with the records bound to it, so an open Question bound to it holds the move back. Close the Question, or clear its task so that it outlives the Task.

$ anb add question "Do fences nest" --task task.ship-the-parser
ok: add
id: question.do-fences-nest
path: questions/question.do-fences-nest.md
$ anb close task.ship-the-parser --reason "replaced by a smaller plan"
ok: close
id: task.ship-the-parser
from: active
to: closed
already: false
unblocked:
count: 0
omitted: 0
rows: []
"open-questions":
count: 1
omitted: 0
rows[1]: question.do-fences-nest
$ anb archive task.ship-the-parser
error: open-questions
message: `task.ship-the-parser` has 1 open question bound to it; close each or clear its task first
findings[1]: question.do-fences-nest
try[2]: anb close question.do-fences-nest --resolved-by <id>,anb edit question.do-fences-nest --clear task
count: 1
omitted: 0

The operation requires a valid record. Read the findings with check and follow the suggested repair before retrying.

$ anb start task.broken
error: invalid-record
message: tasks/task.broken.md is invalid (1 finding)
findings[1]: "line 4: bad-value state: `bogus` is not one of open, active, review, closed for a task"
try[1]: anb show task.broken
count: 1
omitted: 0

Other refusal codes describe command or storage failures: unknown-command (a verb anb does not have; the reply offers anb --help), storage (the file system failed the read or write, in the message) and not-utf8 (a record file is not UTF-8; anb check names it).

anb check prints findings[N]{file,line,severity,code,repair,message}; an error fails the command, a warning does not. The repair column carries the command that erases the finding when the tool has one.

Severity Codes
error no-envelope, unclosed-envelope, bad-envelope-line, duplicate-field, missing-field, bad-value, bad-date, bad-id, id-filename-mismatch, type-dir-mismatch, archived-live-record, dangling-ref, block-cycle, origin-cycle, duplicate-id, broken-supersession, broken-binding, not-utf8
warning unknown-field, unarchived-settled-record, orphan-field, unreadable-reference, crlf, bom, no-final-newline