@got3nks there is no hurry in making this, is jut to have a clean API before we publish v1. take your time to review field by field.
Review of all 119 fields returned by GET /api/v0/preferences, compared
against the labels the Web UI preferences form renders for the same field
(src/webapi/static/js/views/preferences.js + src/webapi/static/i18n/en.json)
and against the underlying core preference each field maps to
(src/ECSpecialMuleTags.cpp, src/Preferences.h, src/muuli_wdr.cpp).
Goal: are the API field names self-explanatory, or at least sensible? This is
an analysis only — no code was changed.
Naming rules used in this review
Every suggested name in this document follows three rules:
- Positive terms only. The name states an affirmative fact, and
true
means that fact holds. No non_*, no_*, not_*, *_disable, and no
double negatives such as create_files_non_sparse or block_non_friends.
Where the underlying behaviour is a denial, the name uses an affirmative
verb for the action itself (filter_all_messages,
accept_from_friends_only) rather than negating a noun.
- Polarity is called out. A handful of positive names can only be reached
by flipping the boolean's current meaning. Every such case is marked
⚠ INVERTS CURRENT SENSE at the point it is proposed, and all of them are
collected in Section G
so none can be missed during implementation.
- Units in the name for every numeric field, matching the convention the
payload already uses (max_upload_kbps, min_free_space_mb, kad_reask_ms).
Method
For every field the three names were lined up:
| Layer |
Source |
| API field |
GET /api/v0/preferences (src/webapi/Api.cpp, src/webapi/State.h) |
| Web UI label |
prefs_field_<category>_<key> in i18n/en.json |
| Desktop label / core setter |
src/muuli_wdr.cpp, thePrefs::* |
The API↔UI mapping is 1:1: every one of the 119 GET fields is rendered by the
Web UI form, and the UI adds only 6 extra controls that are not GET fields
(4 write-only passwords, the ip2country.update_now trigger, and the derived
read-only udp_server_port).
Verdict at a glance
| Category |
Fields |
Good |
Needs a look |
general |
4 |
3 |
1 |
connection |
23 |
21 |
2 |
directories |
8 |
7 |
1 |
files |
19 |
9 |
10 |
servers |
11 |
5 |
6 |
security |
13 |
8 |
5 |
message_filter |
9 |
6 |
3 |
remote_controls |
9 |
7 |
2 |
online_signature |
3 |
2 |
1 |
core_tweaks |
8 |
2 |
6 |
kademlia |
1 |
1 |
0 |
ip2country |
11 |
9 |
2 |
| Total |
119 |
80 |
39 |
The overall shape is good: nested categories mirror the desktop preference
pages, names are snake_case throughout, and most fields read correctly
without documentation. Problems cluster in four places: files, servers,
core_tweaks, and unit-less numeric fields. Only two fields in the whole
payload would need a polarity flip to get a positive name (Section G) — the API
is already largely free of inverted booleans, which is worth preserving.
A. Actively misleading names
The name suggests something different from what the field does, so a client
author can get it wrong without ever seeing a warning.
A1. message_filter.friends — the name reads as the opposite of the behaviour
|
|
| API |
message_filter.friends: false |
| UI label |
"Filter messages from people not on your friend list" |
| Core |
thePrefs::SetMsgOnlyFriends() |
Inside a category called message_filter, the field friends reads as "filter
friends". It means the opposite: accept only from friends. Same problem, one
step milder, for message_filter.secure → thePrefs::SetMsgOnlySecure()
(UI label: "Filter messages from unknown clients").
Suggested (positive, sense unchanged):
| Current |
Suggested |
Polarity |
friends |
accept_from_friends_only |
unchanged |
secure |
accept_from_known_clients_only |
unchanged |
Both keep true = "restrict to this group", exactly as today. The affirmative
verb accept avoids the block_non_friends / filter_non_friends double
negative, and matches the core accessor names (MsgOnlyFriends,
MsgOnlySecure) rather than fighting them.
A2. message_filter.all — bare quantifier, no verb
all: false inside message_filter carries no verb at all.
UI label: "Filter all messages".
Suggested: filter_all_messages — polarity unchanged. filter is the
category's own affirmative verb, so this needs no negation.
A3. files.create_normal — name says nothing, and core stores the inverse
|
|
| API |
files.create_normal: false |
| UI label |
"Create new files non-sparse (allocate real disk blocks)" |
| Core |
thePrefs::CreateFilesNormal(val) → s_createFilesSparse = !val |
"Normal" is meaningless to an API consumer. The setting is about sparse vs
non-sparse file creation, and the core stores the opposite boolean — the API
name inherits a double negative from a legacy wxWidgets accessor.
There is no positive name for the current polarity: today true means
"not sparse", and any faithful name has to say so (create_files_non_sparse,
avoid_sparse_files) — all negations. The only positive term available is the
sparse one:
Suggested: create_sparse_files — ⚠ INVERTS CURRENT SENSE.
create_sparse_files: true == create_normal: false.
This also makes the backend simpler, because it matches how the core already
stores the value (s_createFilesSparse), removing the ! in
CreateFilesNormal(). The Web UI label would become "Create new files as sparse
files (allocate disk blocks on demand)" with the checkbox default flipped.
A4. security.obfuscation_supported — collides with the capability-flag convention
This payload uses _supported / _available for read-only build
capabilities the daemon advertises:
connection.upnp_available — read-only
files.mmap_supported — read-only
ip2country.supported — read-only
But security.obfuscation_supported is a writable user preference —
thePrefs::SetClientCryptLayerSupported(), desktop label "Support Protocol
Obfuscation". It's the master toggle for the obfuscation group, and it gates
obfuscation_requested / obfuscation_required in the UI.
A client that treats every *_supported field as read-only capability metadata
will silently drop this preference.
Suggested: obfuscation_enabled — polarity unchanged. Keeps _supported /
_available reserved for capabilities, and aligns with the other master
toggles in the payload (ich_enabled, proxy_enabled, upnp_enabled).
A5. files.preview_prio — not a priority
|
|
| UI label |
"Try to download first and last chunks first" |
Nothing here is a priority value; it's a chunk-ordering strategy for
previewable files.
Suggested: prioritize_first_last_chunks — polarity unchanged.
A6. files.save_sources — under-specifies badly
|
|
| UI label |
"Save 10 sources on rare files (< 20 sources)" |
| Core |
thePrefs::SetSrcSeedsOn() |
save_sources reads as a general "persist my source lists to disk" toggle. It
is specifically about writing source seeds for rare files.
Suggested: save_source_seeds_for_rare_files — polarity unchanged.
(save_source_seeds if the longer form is too much.)
A7. directories.exclude_regex — describes the wrong thing
|
|
| API |
directories.exclude_regex: false |
| UI label |
"Patterns are regular expressions" |
| Core |
thePrefs::ExcludeSharePatternsUseRegex() |
The name reads as "exclude regexes" — a second exclusion list alongside
exclude_patterns. It is actually a modifier on exclude_patterns: are those
patterns globs or regexes?
Suggested: exclude_patterns_use_regex — polarity unchanged. Matches the
core accessor name exactly and makes the dependency on exclude_patterns
visible in the name.
A8. security.ipfilter_level — a threshold, not a level of anything
|
|
| UI label |
"Filtering level (0-255)" |
| Core |
IPFilter.cpp:139: an entry is loaded when it->AccessLevel < accessLevel |
The value is a threshold: IP ranges whose access level is below it get
blocked, so a higher number blocks more. "Level" alone tells a client neither
the direction nor what it applies to.
Suggested: ipfilter_block_below_access_level — polarity unchanged
(numeric). Reads affirmatively and encodes the comparison direction.
A9. core_tweaks.max_conn_per_five — "five" of what?
|
|
| UI label |
"Max new connections / 5 secs" |
The unit is missing from the field name entirely.
Suggested: max_new_connections_per_5s — polarity unchanged.
B. Missing units on numeric fields
The payload is inconsistent about encoding units in the name. Some fields do it
right — max_upload_kbps, max_download_kbps, min_free_space_mb,
kad_reask_ms, source_reask_ms — and then several don't, including one that
sits in the same object as the two _ms fields. None of these involves a
polarity change.
B1. core_tweaks.srv_keepalive_timeout — milliseconds, un-suffixed
|
|
| API |
srv_keepalive_timeout: 0 |
| Core |
GetServerKeepAliveTimeout() returns s_dwServerKeepAliveTimeoutMins * 60000 |
The value on the wire is milliseconds. Its two siblings in the same object,
kad_reask_ms and source_reask_ms, are also milliseconds and do say so.
This one doesn't.
Suggested: server_keepalive_timeout_ms (also spells out the srv
abbreviation, see Section D).
Related UI note (outside the API-naming scope, but caused by the same gap): the
Web UI applies scale: 60000 to kad_reask_ms and source_reask_ms and shows
them in minutes, but renders srv_keepalive_timeout raw with the label "Server
connection refresh interval (0 = disable)" — so the form shows an unlabelled
millisecond figure where the desktop shows minutes (slider 0–30).
B2. connection.slot_allocation — kB/s per upload slot
|
|
| UI label |
"Slot Allocation" (copied verbatim from the desktop) |
| Core |
UploadQueue.cpp:306: float kBpsUpPerClient = thePrefs::GetSlotAllocation(); |
The value is kB/s allocated per upload slot. Neither the field name nor the UI
label says so.
Suggested: upload_slot_kbps. The UI label is equally opaque and would
benefit from "Upload speed per slot (KB/s)".
B3. core_tweaks.filebuffer — bytes
Desktop shows "File Buffer Size: 240000 bytes". Also the only field in the whole
payload that runs two words together without an underscore.
Suggested: file_buffer_bytes.
B4. core_tweaks.ul_queue — a count of clients
Desktop shows "Upload Queue Size: 5000 clients".
Suggested: max_upload_queue_clients (or upload_queue_size).
B5. online_signature.update_frequency — seconds
Desktop: "Update Frequency (Secs)".
Suggested: update_frequency_seconds.
B6. remote_controls.webserver_refresh — seconds
UI label already says "Page refresh time (seconds)".
Suggested: webserver_refresh_seconds.
C. Inconsistent conventions inside one payload
None of these is wrong on its own; together they make the API harder to
predict. No polarity changes in this section.
C1. Enums: two different encodings
| Field |
Encoding |
connection.proxy_type |
int 0..3 (SOCKS5 / SOCKS4 / HTTP / SOCKS4a) |
security.can_see_shares |
int 0..2 (everybody / friends / nobody) |
ip2country.source |
string ("dbip" / "maxmind" / "custom") |
ip2country.source is self-describing on the wire; the other two require the
client to hardcode a magic-number table (the Web UI does exactly that, in
PROXY_TYPES and SEE_SHARES). Consistent string enums would remove that.
can_see_shares additionally reads as a yes/no question but holds a 3-state
integer.
Suggested: shared_files_visibility with values "everybody" /
"friends" / "nobody", and proxy_type with "socks5" / "socks4" /
"http" / "socks4a". Value order preserved, so no semantic change.
C2. files.resume_same_cat breaks its own family
Three fields describe the same "what to start when a download finishes"
behaviour, and one is named differently:
| API |
UI label |
start_next_paused |
"Start next paused file when a file completes" |
start_next_alphabetical |
"In alphabetic order" |
resume_same_cat |
"From the same category" |
Suggested: start_next_same_category — matches the prefix of the parent it
is gated by, drops the cat abbreviation, and drops "resume", which wrongly
suggests the pause/resume action.
C3. auto_update means three different things
servers.auto_update — refresh the server list at startup
security.ipfilter_auto_update — refresh the IP filter at startup
ip2country.auto_update — refresh the GeoIP database at startup
Two are bare, one is prefixed with its subsystem even though the category
already scopes it. Similarly security.ipfilter_update_url repeats ipfilter
inside security, while servers.update_url and kademlia.update_url rely on
the category. Pick one rule — dropping the redundant prefixes (security.auto_update,
security.update_url) is the smaller and more consistent option, given that
security has no second updatable resource.
C4. Boolean naming: *_enabled vs bare verbs/adjectives
*_enabled form: ich_enabled, proxy_enabled, upnp_enabled,
extended_udp_port_enabled, media_metadata_enabled, mmap_enabled,
webserver_enabled, amuleapi_enabled, message_filter.enabled,
online_signature.enabled, ip2country.enabled.
Bare form: autoconnect, reconnect, remove_dead, share_hidden,
auto_rescan, follow_symlinks, new_paused, endgame, verbose,
check_free_space, use_secident, use_score_system, smart_id_check,
safe_server_connect, paranoid_filtering, use_system_ipfilter.
Most bare ones read fine as English, so this is largely cosmetic. Two read as
truncations rather than sentences and are worth spelling out:
| Current |
Suggested |
core_tweaks.verbose |
verbose_logging |
files.endgame |
endgame_enabled |
Two more describe the check but not the effect:
| Current |
UI label |
Suggested |
files.check_free_space |
"Stop downloads on low free disk space" |
stop_on_low_disk_space |
files.alloc_full_size |
"Preallocate disk space for new files" |
preallocate_full_file_size |
All four keep their current polarity.
C5. security.ipfilter_filter_lan — stutter
The word "filter" appears twice in one field name. UI label: "Always filter LAN
IPs".
Suggested: ipfilter_include_lan_ips — polarity unchanged.
C6. remote_controls: prefixes doing the work of nesting
All nine fields are prefixed webserver_ or amuleapi_ because two unrelated
subsystems share one flat object:
remote_controls.webserver_enabled, webserver_port, webserver_use_gzip,
webserver_refresh, webserver_template, webserver_guest_enabled,
amuleapi_enabled, amuleapi_port, amuleapi_bind
Nesting (remote_controls.webserver.{...}, remote_controls.amuleapi.{...})
would drop the prefixes and match how the rest of the payload uses categories.
This is a breaking structural change, so it is worth noting rather than doing.
C7. amuleapi_bind vs bind_address
connection.bind_address and connection.bind_interface spell out what is
being bound. remote_controls.amuleapi_bind is a bare verb holding an IP
(UI label: "Listening IP").
Suggested: amuleapi_bind_address.
D. Abbreviations that don't need to be abbreviations
All polarity-unchanged.
| Current |
Meaning |
Suggested |
files.new_auto_dl_prio |
new downloads get auto priority |
new_downloads_auto_priority |
files.new_auto_ul_prio |
new shared files get auto priority — not uploads of your downloads (UI: "Add new shared files with auto priority") |
new_shared_files_auto_priority |
files.aich_trust |
"Advanced I.C.H. trusts every hash" |
aich_trust_every_hash |
files.new_paused |
"Add files to download in pause mode" |
add_new_downloads_paused |
files.resume_same_cat |
see C2 |
start_next_same_category |
servers.autoconn_static_only |
"Autoconnect to servers in static list only" |
autoconnect_static_servers_only |
servers.manual_high_prio |
manually added servers → High priority |
manual_servers_high_priority |
servers.dead_server_retries |
retries before a server counts as dead |
fine as-is |
core_tweaks.kad_max_searches |
GetKadMaxSourceSearches(), UI: "Concurrent Kad source lookups" |
kad_max_source_searches |
core_tweaks.srv_keepalive_timeout |
see B1 |
server_keepalive_timeout_ms |
core_tweaks.ul_queue |
see B4 |
max_upload_queue_clients |
prio / dl / ul / cat / srv / autoconn are the only abbreviations in
the payload; everything else spells words out, so they stand out.
E. Legacy core names leaking through, where the UI already says something better
Defensible (they match thePrefs:: / EC tag names 1:1, which makes the backend
easy to audit) but they contradict the label the same field is shown with. All
polarity-unchanged.
| Current |
UI label / desktop label |
Suggested |
servers.use_score_system |
"Use priority system" |
Core is s_scorsystem / SetScoreSystem. The desktop dropped the word "score" years ago; the API kept it. → use_priority_system |
servers.add_from_server |
"Update server list when connecting to a server" |
"Add" what, from where? → update_list_from_server |
servers.add_from_client |
"Update server list when a client connects" |
→ update_list_from_client |
servers.safe_server_connect |
"Safe connect" |
→ safe_connect (drops the redundant server inside servers) |
general.host_name |
"Host name" |
thePrefs::GetYourHostname() — the local hostname this client advertises, read-only. Ambiguous next to proxy_host and amuleapi_bind. → local_host_name or advertised_host_name |
files.create_normal |
see A3 |
see A3 — the one case that needs a polarity flip |
files.save_sources |
see A6 |
save_source_seeds_for_rare_files |
security.paranoid_filtering |
"Paranoid handling of non-matching IPs" |
Jargon, but the desktop uses the same word and the tooltip explains it. Leave as-is, or reject_spoofed_source_ips to say what it does. |
F. Names that are already good
Worth recording so a future rename pass doesn't churn them:
- Units in the name:
max_upload_kbps, max_download_kbps,
min_free_space_mb, kad_reask_ms, source_reask_ms.
- Ports:
tcp_port, udp_port, proxy_port, upnp_tcp_port,
webserver_port, amuleapi_port — consistent and unambiguous.
directories paths: incoming, temp, shared, share_hidden,
auto_rescan, follow_symlinks, exclude_patterns. Clean, and
category-scoped without redundant prefixes.
- Capability flags (read-only, daemon-advertised):
upnp_available,
files.mmap_supported, ip2country.supported. Consistent — which is exactly
why A4 is a problem.
ip2country status block: source / loaded_source (requested vs
actually loaded) is a genuinely good pair, and db_path / db_loaded read
correctly. Minor nits only: downloading → download_in_progress,
last_result → last_update_result.
- Obfuscation triple:
obfuscation_requested / obfuscation_required is a
precise distinction (prefer vs mandate), stated positively. Only the third
member, obfuscation_supported, is misnamed.
- Already-positive inversion of an EC negative:
connection.extended_udp_port_enabled deliberately inverts
EC_TAG_CONN_UDP_DISABLE so the API has no double negative. This is precisely
the pattern the rest of this document asks for, it is already documented in
State.h, and it is the precedent for the create_sparse_files flip in A3.
- Write-only passwords (
proxy_password, webserver_password,
webserver_guest_password, amuleapi_password) are accepted on PATCH and
correctly absent from GET.
G. Polarity changes: fields whose sense would flip
Out of 39 flagged fields, exactly one boolean cannot be given a positive
name without inverting its current meaning. Everything else in this document is
a pure rename.
| Current field |
Current true means |
Suggested field |
New true means |
Equivalence |
files.create_normal |
files are created non-sparse (real blocks allocated up front) |
create_sparse_files |
files are created sparse (blocks allocated on demand) |
create_sparse_files == !create_normal |
Implementation consequences of that single flip:
- Wire:
create_normal: false (today's default) becomes
create_sparse_files: true. A client that blindly renames the key without
flipping the value gets the opposite behaviour — this is the one place where a
mechanical find-and-replace is wrong.
- Backend: it removes a negation rather than adding one. The core already
stores s_createFilesSparse, and thePrefs::CreateFilesNormal(val) does
s_createFilesSparse = !val. Emitting create_sparse_files lets the webapi
read and write the stored value directly.
- Web UI:
prefs_field_files_create_normal ("Create new files non-sparse
(allocate real disk blocks)") becomes "Create new files as sparse files
(allocate disk blocks on demand)", and the checkbox's meaning flips. Because
the Web UI reads the same key it writes, no extra inversion logic is needed
there — only the label and its Spanish translation change.
- Transition: if both keys are emitted during a deprecation window, they
must carry opposite values. That is the one asymmetry versus every other
rename in this document, and a reason to do this field on its own commit
rather than inside a bulk rename.
Two near-misses that are not polarity changes, recorded so they don't get
mistaken for one:
security.obfuscation_supported → obfuscation_enabled (A4). Same value,
same meaning; only the misleading _supported suffix goes.
message_filter.friends → accept_from_friends_only (A1). true still means
"restrict to friends". The name stops reading as an inversion — the value
never was one.
Recommended priority, if a rename pass ever happens
Renaming API fields is breaking, so this is ordered by "how likely is this to
cause a wrong integration", not by how ugly the name is.
Tier 1 — semantic hazards (a client can get these wrong silently):
security.obfuscation_supported → obfuscation_enabled (A4)
message_filter.friends / .secure / .all → accept_from_friends_only / accept_from_known_clients_only / filter_all_messages (A1, A2)
core_tweaks.srv_keepalive_timeout → server_keepalive_timeout_ms (B1)
directories.exclude_regex → exclude_patterns_use_regex (A7)
files.create_normal → create_sparse_files — own commit, polarity flip (A3, G)
Tier 2 — missing units and under-specified names:
6. connection.slot_allocation → upload_slot_kbps (B2)
7. core_tweaks.max_conn_per_five → max_new_connections_per_5s (A9)
8. core_tweaks.filebuffer / ul_queue → file_buffer_bytes / max_upload_queue_clients (B3, B4)
9. files.save_sources, files.preview_prio → save_source_seeds_for_rare_files, prioritize_first_last_chunks (A6, A5)
10. security.ipfilter_level → ipfilter_block_below_access_level (A8)
11. online_signature.update_frequency, remote_controls.webserver_refresh → *_seconds (B5, B6)
Tier 3 — consistency and abbreviations (cosmetic, batch them):
12. Enum encodings: proxy_type, can_see_shares → string enums (C1)
13. files.resume_same_cat → start_next_same_category (C2)
14. The dl / ul / prio / cat / srv / autoconn abbreviations (D)
15. servers.use_score_system, add_from_server, add_from_client (E)
16. security.ipfilter_filter_lan, core_tweaks.verbose, files.endgame,
files.check_free_space, files.alloc_full_size (C4, C5)
Not recommended: the remote_controls re-nesting (C6) — real improvement,
but a much larger break than the rest for a purely structural gain.
If backwards compatibility matters, the usual escape hatch applies: emit both
the old and the new key on GET for one release, accept both on PATCH, and
drop the old one after. That is cheap here because every field already goes
through a single emit site in src/webapi/Api.cpp and a single PrefTake* call
on the write path. The one exception is files.create_normal — during its
window the two keys must carry opposite values (Section G).
Web UI labels worth revisiting at the same time
Two labels are as opaque as the API fields behind them, since they were copied
verbatim from the desktop dialog:
prefs_field_connection_slot_allocation = "Slot Allocation" → "Upload speed
per slot (KB/s)"
prefs_field_core_tweaks_srv_keepalive_timeout = "Server connection refresh
interval (0 = disable)" → needs a unit, and the field needs scale: 60000 to
show minutes like the desktop does (see B1)
And one label changes as a consequence of the polarity flip:
prefs_field_files_create_normal = "Create new files non-sparse (allocate
real disk blocks)" → "Create new files as sparse files (allocate disk blocks
on demand)", with the checkbox default inverted (see G)
@got3nks there is no hurry in making this, is jut to have a clean API before we publish v1. take your time to review field by field.
Review of all 119 fields returned by
GET /api/v0/preferences, comparedagainst the labels the Web UI preferences form renders for the same field
(
src/webapi/static/js/views/preferences.js+src/webapi/static/i18n/en.json)and against the underlying core preference each field maps to
(
src/ECSpecialMuleTags.cpp,src/Preferences.h,src/muuli_wdr.cpp).Goal: are the API field names self-explanatory, or at least sensible? This is
an analysis only — no code was changed.
Naming rules used in this review
Every suggested name in this document follows three rules:
truemeans that fact holds. No
non_*,no_*,not_*,*_disable, and nodouble negatives such as
create_files_non_sparseorblock_non_friends.Where the underlying behaviour is a denial, the name uses an affirmative
verb for the action itself (
filter_all_messages,accept_from_friends_only) rather than negating a noun.by flipping the boolean's current meaning. Every such case is marked
⚠ INVERTS CURRENT SENSE at the point it is proposed, and all of them are
collected in Section G
so none can be missed during implementation.
payload already uses (
max_upload_kbps,min_free_space_mb,kad_reask_ms).Method
For every field the three names were lined up:
GET /api/v0/preferences(src/webapi/Api.cpp,src/webapi/State.h)prefs_field_<category>_<key>ini18n/en.jsonsrc/muuli_wdr.cpp,thePrefs::*The API↔UI mapping is 1:1: every one of the 119 GET fields is rendered by the
Web UI form, and the UI adds only 6 extra controls that are not GET fields
(4 write-only passwords, the
ip2country.update_nowtrigger, and the derivedread-only
udp_server_port).Verdict at a glance
generalconnectiondirectoriesfilesserverssecuritymessage_filterremote_controlsonline_signaturecore_tweakskademliaip2countryThe overall shape is good: nested categories mirror the desktop preference
pages, names are
snake_casethroughout, and most fields read correctlywithout documentation. Problems cluster in four places:
files,servers,core_tweaks, and unit-less numeric fields. Only two fields in the wholepayload would need a polarity flip to get a positive name (Section G) — the API
is already largely free of inverted booleans, which is worth preserving.
A. Actively misleading names
The name suggests something different from what the field does, so a client
author can get it wrong without ever seeing a warning.
A1.
message_filter.friends— the name reads as the opposite of the behaviourmessage_filter.friends: falsethePrefs::SetMsgOnlyFriends()Inside a category called
message_filter, the fieldfriendsreads as "filterfriends". It means the opposite: accept only from friends. Same problem, one
step milder, for
message_filter.secure→thePrefs::SetMsgOnlySecure()(UI label: "Filter messages from unknown clients").
Suggested (positive, sense unchanged):
friendsaccept_from_friends_onlysecureaccept_from_known_clients_onlyBoth keep
true= "restrict to this group", exactly as today. The affirmativeverb
acceptavoids theblock_non_friends/filter_non_friendsdoublenegative, and matches the core accessor names (
MsgOnlyFriends,MsgOnlySecure) rather than fighting them.A2.
message_filter.all— bare quantifier, no verball: falseinsidemessage_filtercarries no verb at all.UI label: "Filter all messages".
Suggested:
filter_all_messages— polarity unchanged.filteris thecategory's own affirmative verb, so this needs no negation.
A3.
files.create_normal— name says nothing, and core stores the inversefiles.create_normal: falsethePrefs::CreateFilesNormal(val)→s_createFilesSparse = !val"Normal" is meaningless to an API consumer. The setting is about sparse vs
non-sparse file creation, and the core stores the opposite boolean — the API
name inherits a double negative from a legacy wxWidgets accessor.
There is no positive name for the current polarity: today
truemeans"not sparse", and any faithful name has to say so (
create_files_non_sparse,avoid_sparse_files) — all negations. The only positive term available is thesparse one:
Suggested:
create_sparse_files— ⚠ INVERTS CURRENT SENSE.create_sparse_files: true==create_normal: false.This also makes the backend simpler, because it matches how the core already
stores the value (
s_createFilesSparse), removing the!inCreateFilesNormal(). The Web UI label would become "Create new files as sparsefiles (allocate disk blocks on demand)" with the checkbox default flipped.
A4.
security.obfuscation_supported— collides with the capability-flag conventionThis payload uses
_supported/_availablefor read-only buildcapabilities the daemon advertises:
connection.upnp_available— read-onlyfiles.mmap_supported— read-onlyip2country.supported— read-onlyBut
security.obfuscation_supportedis a writable user preference —thePrefs::SetClientCryptLayerSupported(), desktop label "Support ProtocolObfuscation". It's the master toggle for the obfuscation group, and it gates
obfuscation_requested/obfuscation_requiredin the UI.A client that treats every
*_supportedfield as read-only capability metadatawill silently drop this preference.
Suggested:
obfuscation_enabled— polarity unchanged. Keeps_supported/_availablereserved for capabilities, and aligns with the other mastertoggles in the payload (
ich_enabled,proxy_enabled,upnp_enabled).A5.
files.preview_prio— not a priorityNothing here is a priority value; it's a chunk-ordering strategy for
previewable files.
Suggested:
prioritize_first_last_chunks— polarity unchanged.A6.
files.save_sources— under-specifies badlythePrefs::SetSrcSeedsOn()save_sourcesreads as a general "persist my source lists to disk" toggle. Itis specifically about writing source seeds for rare files.
Suggested:
save_source_seeds_for_rare_files— polarity unchanged.(
save_source_seedsif the longer form is too much.)A7.
directories.exclude_regex— describes the wrong thingdirectories.exclude_regex: falsethePrefs::ExcludeSharePatternsUseRegex()The name reads as "exclude regexes" — a second exclusion list alongside
exclude_patterns. It is actually a modifier onexclude_patterns: are thosepatterns globs or regexes?
Suggested:
exclude_patterns_use_regex— polarity unchanged. Matches thecore accessor name exactly and makes the dependency on
exclude_patternsvisible in the name.
A8.
security.ipfilter_level— a threshold, not a level of anythingIPFilter.cpp:139: an entry is loaded whenit->AccessLevel < accessLevelThe value is a threshold: IP ranges whose access level is below it get
blocked, so a higher number blocks more. "Level" alone tells a client neither
the direction nor what it applies to.
Suggested:
ipfilter_block_below_access_level— polarity unchanged(numeric). Reads affirmatively and encodes the comparison direction.
A9.
core_tweaks.max_conn_per_five— "five" of what?The unit is missing from the field name entirely.
Suggested:
max_new_connections_per_5s— polarity unchanged.B. Missing units on numeric fields
The payload is inconsistent about encoding units in the name. Some fields do it
right —
max_upload_kbps,max_download_kbps,min_free_space_mb,kad_reask_ms,source_reask_ms— and then several don't, including one thatsits in the same object as the two
_msfields. None of these involves apolarity change.
B1.
core_tweaks.srv_keepalive_timeout— milliseconds, un-suffixedsrv_keepalive_timeout: 0GetServerKeepAliveTimeout()returnss_dwServerKeepAliveTimeoutMins * 60000The value on the wire is milliseconds. Its two siblings in the same object,
kad_reask_msandsource_reask_ms, are also milliseconds and do say so.This one doesn't.
Suggested:
server_keepalive_timeout_ms(also spells out thesrvabbreviation, see Section D).
Related UI note (outside the API-naming scope, but caused by the same gap): the
Web UI applies
scale: 60000tokad_reask_msandsource_reask_msand showsthem in minutes, but renders
srv_keepalive_timeoutraw with the label "Serverconnection refresh interval (0 = disable)" — so the form shows an unlabelled
millisecond figure where the desktop shows minutes (slider 0–30).
B2.
connection.slot_allocation— kB/s per upload slotUploadQueue.cpp:306:float kBpsUpPerClient = thePrefs::GetSlotAllocation();The value is kB/s allocated per upload slot. Neither the field name nor the UI
label says so.
Suggested:
upload_slot_kbps. The UI label is equally opaque and wouldbenefit from "Upload speed per slot (KB/s)".
B3.
core_tweaks.filebuffer— bytesDesktop shows "File Buffer Size: 240000 bytes". Also the only field in the whole
payload that runs two words together without an underscore.
Suggested:
file_buffer_bytes.B4.
core_tweaks.ul_queue— a count of clientsDesktop shows "Upload Queue Size: 5000 clients".
Suggested:
max_upload_queue_clients(orupload_queue_size).B5.
online_signature.update_frequency— secondsDesktop: "Update Frequency (Secs)".
Suggested:
update_frequency_seconds.B6.
remote_controls.webserver_refresh— secondsUI label already says "Page refresh time (seconds)".
Suggested:
webserver_refresh_seconds.C. Inconsistent conventions inside one payload
None of these is wrong on its own; together they make the API harder to
predict. No polarity changes in this section.
C1. Enums: two different encodings
connection.proxy_type0..3(SOCKS5 / SOCKS4 / HTTP / SOCKS4a)security.can_see_shares0..2(everybody / friends / nobody)ip2country.source"dbip"/"maxmind"/"custom")ip2country.sourceis self-describing on the wire; the other two require theclient to hardcode a magic-number table (the Web UI does exactly that, in
PROXY_TYPESandSEE_SHARES). Consistent string enums would remove that.can_see_sharesadditionally reads as a yes/no question but holds a 3-stateinteger.
Suggested:
shared_files_visibilitywith values"everybody"/"friends"/"nobody", andproxy_typewith"socks5"/"socks4"/"http"/"socks4a". Value order preserved, so no semantic change.C2.
files.resume_same_catbreaks its own familyThree fields describe the same "what to start when a download finishes"
behaviour, and one is named differently:
start_next_pausedstart_next_alphabeticalresume_same_catSuggested:
start_next_same_category— matches the prefix of the parent itis gated by, drops the
catabbreviation, and drops "resume", which wronglysuggests the pause/resume action.
C3.
auto_updatemeans three different thingsservers.auto_update— refresh the server list at startupsecurity.ipfilter_auto_update— refresh the IP filter at startupip2country.auto_update— refresh the GeoIP database at startupTwo are bare, one is prefixed with its subsystem even though the category
already scopes it. Similarly
security.ipfilter_update_urlrepeatsipfilterinside
security, whileservers.update_urlandkademlia.update_urlrely onthe category. Pick one rule — dropping the redundant prefixes (
security.auto_update,security.update_url) is the smaller and more consistent option, given thatsecurityhas no second updatable resource.C4. Boolean naming:
*_enabledvs bare verbs/adjectives*_enabledform:ich_enabled,proxy_enabled,upnp_enabled,extended_udp_port_enabled,media_metadata_enabled,mmap_enabled,webserver_enabled,amuleapi_enabled,message_filter.enabled,online_signature.enabled,ip2country.enabled.Bare form:
autoconnect,reconnect,remove_dead,share_hidden,auto_rescan,follow_symlinks,new_paused,endgame,verbose,check_free_space,use_secident,use_score_system,smart_id_check,safe_server_connect,paranoid_filtering,use_system_ipfilter.Most bare ones read fine as English, so this is largely cosmetic. Two read as
truncations rather than sentences and are worth spelling out:
core_tweaks.verboseverbose_loggingfiles.endgameendgame_enabledTwo more describe the check but not the effect:
files.check_free_spacestop_on_low_disk_spacefiles.alloc_full_sizepreallocate_full_file_sizeAll four keep their current polarity.
C5.
security.ipfilter_filter_lan— stutterThe word "filter" appears twice in one field name. UI label: "Always filter LAN
IPs".
Suggested:
ipfilter_include_lan_ips— polarity unchanged.C6.
remote_controls: prefixes doing the work of nestingAll nine fields are prefixed
webserver_oramuleapi_because two unrelatedsubsystems share one flat object:
Nesting (
remote_controls.webserver.{...},remote_controls.amuleapi.{...})would drop the prefixes and match how the rest of the payload uses categories.
This is a breaking structural change, so it is worth noting rather than doing.
C7.
amuleapi_bindvsbind_addressconnection.bind_addressandconnection.bind_interfacespell out what isbeing bound.
remote_controls.amuleapi_bindis a bare verb holding an IP(UI label: "Listening IP").
Suggested:
amuleapi_bind_address.D. Abbreviations that don't need to be abbreviations
All polarity-unchanged.
files.new_auto_dl_prionew_downloads_auto_priorityfiles.new_auto_ul_prionew_shared_files_auto_priorityfiles.aich_trustaich_trust_every_hashfiles.new_pausedadd_new_downloads_pausedfiles.resume_same_catstart_next_same_categoryservers.autoconn_static_onlyautoconnect_static_servers_onlyservers.manual_high_priomanual_servers_high_priorityservers.dead_server_retriescore_tweaks.kad_max_searchesGetKadMaxSourceSearches(), UI: "Concurrent Kad source lookups"kad_max_source_searchescore_tweaks.srv_keepalive_timeoutserver_keepalive_timeout_mscore_tweaks.ul_queuemax_upload_queue_clientsprio/dl/ul/cat/srv/autoconnare the only abbreviations inthe payload; everything else spells words out, so they stand out.
E. Legacy core names leaking through, where the UI already says something better
Defensible (they match
thePrefs::/ EC tag names 1:1, which makes the backendeasy to audit) but they contradict the label the same field is shown with. All
polarity-unchanged.
servers.use_score_systems_scorsystem/SetScoreSystem. The desktop dropped the word "score" years ago; the API kept it. →use_priority_systemservers.add_from_serverupdate_list_from_serverservers.add_from_clientupdate_list_from_clientservers.safe_server_connectsafe_connect(drops the redundantserverinsideservers)general.host_namethePrefs::GetYourHostname()— the local hostname this client advertises, read-only. Ambiguous next toproxy_hostandamuleapi_bind. →local_host_nameoradvertised_host_namefiles.create_normalfiles.save_sourcessave_source_seeds_for_rare_filessecurity.paranoid_filteringreject_spoofed_source_ipsto say what it does.F. Names that are already good
Worth recording so a future rename pass doesn't churn them:
max_upload_kbps,max_download_kbps,min_free_space_mb,kad_reask_ms,source_reask_ms.tcp_port,udp_port,proxy_port,upnp_tcp_port,webserver_port,amuleapi_port— consistent and unambiguous.directoriespaths:incoming,temp,shared,share_hidden,auto_rescan,follow_symlinks,exclude_patterns. Clean, andcategory-scoped without redundant prefixes.
upnp_available,files.mmap_supported,ip2country.supported. Consistent — which is exactlywhy A4 is a problem.
ip2countrystatus block:source/loaded_source(requested vsactually loaded) is a genuinely good pair, and
db_path/db_loadedreadcorrectly. Minor nits only:
downloading→download_in_progress,last_result→last_update_result.obfuscation_requested/obfuscation_requiredis aprecise distinction (prefer vs mandate), stated positively. Only the third
member,
obfuscation_supported, is misnamed.connection.extended_udp_port_enableddeliberately invertsEC_TAG_CONN_UDP_DISABLEso the API has no double negative. This is preciselythe pattern the rest of this document asks for, it is already documented in
State.h, and it is the precedent for thecreate_sparse_filesflip in A3.proxy_password,webserver_password,webserver_guest_password,amuleapi_password) are accepted onPATCHandcorrectly absent from
GET.G. Polarity changes: fields whose sense would flip
Out of 39 flagged fields, exactly one boolean cannot be given a positive
name without inverting its current meaning. Everything else in this document is
a pure rename.
truemeanstruemeansfiles.create_normalcreate_sparse_filescreate_sparse_files == !create_normalImplementation consequences of that single flip:
create_normal: false(today's default) becomescreate_sparse_files: true. A client that blindly renames the key withoutflipping the value gets the opposite behaviour — this is the one place where a
mechanical find-and-replace is wrong.
stores
s_createFilesSparse, andthePrefs::CreateFilesNormal(val)doess_createFilesSparse = !val. Emittingcreate_sparse_fileslets the webapiread and write the stored value directly.
prefs_field_files_create_normal("Create new files non-sparse(allocate real disk blocks)") becomes "Create new files as sparse files
(allocate disk blocks on demand)", and the checkbox's meaning flips. Because
the Web UI reads the same key it writes, no extra inversion logic is needed
there — only the label and its Spanish translation change.
must carry opposite values. That is the one asymmetry versus every other
rename in this document, and a reason to do this field on its own commit
rather than inside a bulk rename.
Two near-misses that are not polarity changes, recorded so they don't get
mistaken for one:
security.obfuscation_supported→obfuscation_enabled(A4). Same value,same meaning; only the misleading
_supportedsuffix goes.message_filter.friends→accept_from_friends_only(A1).truestill means"restrict to friends". The name stops reading as an inversion — the value
never was one.
Recommended priority, if a rename pass ever happens
Renaming API fields is breaking, so this is ordered by "how likely is this to
cause a wrong integration", not by how ugly the name is.
Tier 1 — semantic hazards (a client can get these wrong silently):
security.obfuscation_supported→obfuscation_enabled(A4)message_filter.friends/.secure/.all→accept_from_friends_only/accept_from_known_clients_only/filter_all_messages(A1, A2)core_tweaks.srv_keepalive_timeout→server_keepalive_timeout_ms(B1)directories.exclude_regex→exclude_patterns_use_regex(A7)files.create_normal→create_sparse_files— own commit, polarity flip (A3, G)Tier 2 — missing units and under-specified names:
6.
connection.slot_allocation→upload_slot_kbps(B2)7.
core_tweaks.max_conn_per_five→max_new_connections_per_5s(A9)8.
core_tweaks.filebuffer/ul_queue→file_buffer_bytes/max_upload_queue_clients(B3, B4)9.
files.save_sources,files.preview_prio→save_source_seeds_for_rare_files,prioritize_first_last_chunks(A6, A5)10.
security.ipfilter_level→ipfilter_block_below_access_level(A8)11.
online_signature.update_frequency,remote_controls.webserver_refresh→*_seconds(B5, B6)Tier 3 — consistency and abbreviations (cosmetic, batch them):
12. Enum encodings:
proxy_type,can_see_shares→ string enums (C1)13.
files.resume_same_cat→start_next_same_category(C2)14. The
dl/ul/prio/cat/srv/autoconnabbreviations (D)15.
servers.use_score_system,add_from_server,add_from_client(E)16.
security.ipfilter_filter_lan,core_tweaks.verbose,files.endgame,files.check_free_space,files.alloc_full_size(C4, C5)Not recommended: the
remote_controlsre-nesting (C6) — real improvement,but a much larger break than the rest for a purely structural gain.
If backwards compatibility matters, the usual escape hatch applies: emit both
the old and the new key on
GETfor one release, accept both onPATCH, anddrop the old one after. That is cheap here because every field already goes
through a single emit site in
src/webapi/Api.cppand a singlePrefTake*callon the write path. The one exception is
files.create_normal— during itswindow the two keys must carry opposite values (Section G).
Web UI labels worth revisiting at the same time
Two labels are as opaque as the API fields behind them, since they were copied
verbatim from the desktop dialog:
prefs_field_connection_slot_allocation= "Slot Allocation" → "Upload speedper slot (KB/s)"
prefs_field_core_tweaks_srv_keepalive_timeout= "Server connection refreshinterval (0 = disable)" → needs a unit, and the field needs
scale: 60000toshow minutes like the desktop does (see B1)
And one label changes as a consequence of the polarity flip:
prefs_field_files_create_normal= "Create new files non-sparse (allocatereal disk blocks)" → "Create new files as sparse files (allocate disk blocks
on demand)", with the checkbox default inverted (see G)