Replace the single file-structure.md with a stratified layout designed
for AI/agent skill consumption: tables and concrete identifiers over
prose, files loaded on demand, content separated by churn rate.
Layers:
- architecture/ stable structural reference (overview, source-map,
test-map, data-flow)
- patterns/ memory, commands, autocomplete, events, xmpp,
encryption, ui, plugins
- testing/ unit-tests, stubs, functional-tests, bench
- build/ local, docker, ci
- playbooks/ add-command, add-test, add-autocomplete,
add-event-handler, add-encryption
- gotchas.md append-only dated entries (seven seed entries)
- wip/ branch-specific notes; deleted on merge to master
Stable layers describe cproof on master only. In-flight feature
branches (currently feat/ai) get a single file under wip/.
INDEX.md is the entry map with churn labels; SKILL.md is the
always-loaded skill hint pointing to it.
115 lines
3.5 KiB
Markdown
115 lines
3.5 KiB
Markdown
# Gotchas
|
|
|
|
Append-only log of known pitfalls. One entry per pitfall. Format:
|
|
|
|
```
|
|
## YYYY-MM-DD — <short title>
|
|
|
|
<body — what bites, why, what to do instead>
|
|
```
|
|
|
|
Scan this file before finishing any non-trivial task.
|
|
|
|
---
|
|
|
|
## 2026-04-30 — `g_strsplit` result must use `g_strfreev`
|
|
|
|
`g_strsplit` (and `g_strdupv`) return a `gchar**` whose elements are
|
|
individually GLib-allocated. Free with `g_strfreev`, **not** `g_free`. The
|
|
latter compiles fine and silently leaks the inner strings.
|
|
|
|
The cleanup macro is `auto_gcharv` (declared in `src/common.h`):
|
|
|
|
```c
|
|
auto_gcharv gchar** parts = g_strsplit(line, " ", -1);
|
|
```
|
|
|
|
Mixing `g_free` on a `gchar**` is the most common allocator-mismatch bug in
|
|
this codebase.
|
|
|
|
---
|
|
|
|
## 2026-04-30 — `JABBER_CONNECTED` must be queued in unit tests
|
|
|
|
Most XMPP-touching code paths gate on `connection_get_status()`. The unit-
|
|
test stub returns `mock()`, so every test reaching that gate must:
|
|
|
|
```c
|
|
will_return(connection_get_status, JABBER_CONNECTED);
|
|
// or
|
|
will_return(connection_get_status, JABBER_DISCONNECTED);
|
|
```
|
|
|
|
Forgetting this aborts cmocka with a "missing mock value" error. If you see
|
|
that error, it's almost always `connection_get_status` you forgot.
|
|
|
|
---
|
|
|
|
## 2026-04-30 — Autocomplete callbacks must be stateless
|
|
|
|
Some older callbacks keep "last match" state in a file-static `_last_*_match`
|
|
variable. Do not copy that pattern. A clean canonical example is
|
|
`roster_contact_autocomplete` (`src/xmpp/roster_list.c`) — it delegates
|
|
straight to `autocomplete_complete` against a roster-owned `Autocomplete`
|
|
object and keeps no callback-local state.
|
|
|
|
Stateful callbacks misbehave under shift-tab cycling and break when two
|
|
completers run concurrently in a layered command (e.g. `/foo set bar <tab>`
|
|
followed by `/foo set baz <tab>`).
|
|
|
|
---
|
|
|
|
## 2026-04-30 — CWE-134 format-string discipline
|
|
|
|
Never pass user-controlled or arbitrary strings as the format argument to
|
|
`printf`-family or GLib formatted-print functions. A recent compiler-
|
|
hardening pass (cf. cproof commit `9ec01fa8c`) audited and tightened these
|
|
sites; do not regress.
|
|
|
|
Right:
|
|
|
|
```c
|
|
cons_show("%s", user_text);
|
|
```
|
|
|
|
Wrong:
|
|
|
|
```c
|
|
cons_show(user_text);
|
|
```
|
|
|
|
The compiler does not always warn, especially across helper layers. Enable
|
|
and respect `-Wformat -Wformat-security` warnings in any build you trust.
|
|
|
|
---
|
|
|
|
## 2026-04-30 — Build inside Docker, not on the host
|
|
|
|
Library version drift between a developer host and `Dockerfile.debian`
|
|
(GLib, OpenSSL, libstrophe in particular) can mask or invent failures. CI
|
|
is the source of truth; CI builds inside the Debian image. See
|
|
`build/docker.md`.
|
|
|
|
If you absolutely must build on the host, mirror the package set in
|
|
`Dockerfile.debian` exactly and pin versions — you will spend more time
|
|
chasing version drift than the Docker build would have cost.
|
|
|
|
---
|
|
|
|
## 2026-04-30 — Beware of "Profanity" vs "cproof" naming
|
|
|
|
The fork-rename is incomplete. Many files, symbols, copyright headers, and
|
|
config keys still say `Profanity` / `prof_` / `profanity`. These are
|
|
authoritative as-is; do **not** rename them opportunistically alongside
|
|
unrelated changes. Rename work, when it happens, will be a dedicated PR.
|
|
|
|
---
|
|
|
|
## 2026-04-30 — Encryption disable builds must compile
|
|
|
|
Each encryption stack (`HAVE_OMEMO`, `HAVE_LIBOTR`, `HAVE_LIBGPGME`) can be
|
|
turned off at `configure` time. New code that calls into these modules
|
|
must wrap calls in the matching `#ifdef` and provide a graceful fallback
|
|
in the `#else`. CI does not always test every disable combination — verify
|
|
locally with at least the off-build for each stack you touched.
|