Skip to content

fix(types): an omitted TYPE_* key degrades as documented instead of crashing under set -u (DIVE-2076, reported in #196) - #206

Merged
lodar merged 2 commits into
mainfrom
dive-2076-typechannels-absent
Jul 26, 2026
Merged

fix(types): an omitted TYPE_* key degrades as documented instead of crashing under set -u (DIVE-2076, reported in #196)#206
lodar merged 2 commits into
mainfrom
dive-2076-typechannels-absent

Conversation

@lodar

@lodar lodar commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Second of the two defects @A-MO7SEN reported in #196 while registering a new agent type. Does not close #196 — that issue asks for the devin type itself, which is his own #197.

A bare \${TYPE_CHANNELS[\$type]} read under set -u made a type registered without that key hard-crash agent types with an unbound-variable error naming the array — an error pointing at our internals rather than the missing key. Seven readers fixed (the ticket named five); a :-0 default routes an omitted key into the existing "type X does not support channels" path.

The sweep found a live instance, not a future-type hypothetical. cmd_auth.sh read TYPE_API_VAR/TYPE_API_FILE bare one line above a graceful fail written for exactly the absent case — which even names hermes and openclaw. Both maps are sparse by design and their comments claimed cmd_auth_set "already fails gracefully when a type isn't in this map". Under set -u execution never reached that line, so 4 of 8 types (hermes, openclaw, antigravity, pi) crashed on auth set-key instead of getting the message. The comment described behaviour the code did not have.

Author: dev3, who reproduced the reporter's symptom end-to-end on the built bundle (inject [devin] into TYPE_BIN only: pre-fix dies TYPE_CHANNELS[\$type]: unbound variable rc=1; fixed prints devin … channels=no rc=0) and graded the harness rather than just running it — 14 graded failures pre-fix. Notably their first harness version hardcoded :-0 and passed against a still-bare tree, i.e. proved the default works rather than that the code uses it; the shipped version lifts the expressions from source.

Stated weakest link: no genuinely new type was provisioned end-to-end (agent create --type=devin against a real binary), so this proves the maps degrade, not that a full create/auth/channel lifecycle works. That belongs to #197's review.

Release: 0.16.13 assigned at merge with the CHANGELOG entry, per CONTRIBUTING.

🤖 Generated with Claude Code

lodar and others added 2 commits July 26, 2026 13:31
…ng under set -u (DIVE-2076)

Reported from outside by A-MO7SEN (github #196) while adding a new agent type:
`${TYPE_CHANNELS[$type]}` was read bare under `set -uo pipefail`, so a type
registered without a TYPE_CHANNELS entry did not degrade to "no channels" — it
hard-crashed `agent types` with an unbound-variable error naming the ARRAY
rather than the missing type.

Readers now supply the documented default. TYPE_CHANNELS defaults to 0, which
routes an omitted key into the existing validation error that names the type
("type 'x' does not support channels") — the behaviour the reporter arranged by
hand with an explicit [devin]=0.

The sweep half found the same defect one map over, and live rather than
hypothetical: cmd_auth_set read TYPE_API_VAR/TYPE_API_FILE bare at cmd_auth.sh
one line above a graceful `fail` written for exactly the absent case, which even
names hermes/openclaw. Those two maps are SPARSE BY DESIGN and their own
comments claim "cmd_auth_set already fails gracefully when a type isn't in this
map" — under set -u it never reached that line. 4 of 8 types (hermes, openclaw,
antigravity, pi) crashed instead of getting the message. The comment described
behaviour the code did not have; it does now.

cmd_agent_create's error also hardcoded the supported-type list, one more place
a new type must be registered and silently would not be; it derives the list.
cmd_account's read is safe by construction (it iterates that map's own keys) but
takes the default anyway: the contract is deliberately exemption-free, because a
rule with no carve-outs is one a contributor can follow.

The ticket's second half was the documentation, so it is the larger half of the
diff: header.sh now states the absent-vs-zero contract above TYPE_BIN, splitting
the maps into REQUIRED (TYPE_BIN — it IS the registry, is_known_type tests it, so
bare reads are correct by construction) and OPTIONAL (everything else, where
omission is a meaningful signal with a documented default every reader must
supply). TYPE_CHANNELS states its own default at its declaration.

tests/type_map_registration_contract_unit.sh enforces both halves in two
dimensions, because either alone is defeatable. The static pass rejects any bare
variable-keyed read of an optional map, so a bare read added tomorrow reds. The
behavioural pass registers a synthetic type in TYPE_BIN only and runs the real
reader expressions under set -u — lifted FROM the source, not written in the
test, since a probe hardcoding `:-0` proves the default works while passing
happily against a tree whose readers are still bare. A control probe asserts a
bare read of a missing key still crashes, so a `set -u` that quietly stopped
applying cannot read as green. Against origin/main the harness reds with 14
graded failures; post-fix it passes.
Resolves the 5dive.sha256 conflict by rebuilding from source rather than picking a side.
Assigns the release number and CHANGELOG entry at merge time per CONTRIBUTING; the branch
was correctly left unversioned by its author.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lodar
lodar merged commit 863b6e4 into main Jul 26, 2026
12 checks passed
@lodar
lodar deleted the dive-2076-typechannels-absent branch July 26, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Agent type request: devin (Cognition's Devin CLI)

1 participant