QMail Tell — Group 6, Code 71

Notifies a recipient’s beacon RAIDA that mail is waiting. The sender uploads stripes to many RAIDAs but sends one tell per recipient to that recipient’s pre-agreed beacon RAIDA.

Quick reference

Command Group6
Command Code71
Server functioncmd_qmail_tell in cmd_qmail.c
Wire structuresqmail_tell_req_t, qmail_address_entry_t, qmail_file_header_t
Body layoutPreamble (48) + Routing (48) + Addresses (N×32) + Tell record (64 + M×32 + manifest_len) + Terminator (2). Payment tells (tell_type 3) are fixed 194 bytes: one address, no server locations, no manifest.
EncryptionRequired — AES-128 keyed by sender’s coin AN
Side effectOne .tell file written per recipient under QMAIL_MAILBOX_ROOT/{denom}/{sn}/inbox/ (atomic publish via temp+rename)

Purpose

After uploading the stripes, the sender calls tell on each recipient’s beacon RAIDA. The tell is a public delivery envelope: a 64-byte file header, M 32-byte server-location entries, and a file manifest. The server-location entries tell the recipient which RAIDAs hold the stripes; the manifest tells the recipient which stored files exist and the original byte size of each file. The beacon writes the record to the recipient’s inbox directory; when the recipient’s ping or peek arrives, the beacon reads back the record and returns it.

The sender pays a per-recipient inbox fee by attaching a funded locker key to each address entry. The same funded inbox-fee locker is also copied into the routing header's beacon_payment_locker field so the beacon can validate the fee before accepting the delivery and pass the locker code on to the recipient.

Privacy boundary

The Tell envelope is visible to the beacon operator. It MUST NOT contain private display data such as subject, body preview, attachment names, labels, or human-readable filenames. Those fields belong in the private CBDF meta object (file_type=0) that the recipient downloads from the storage RAIDAs after receiving the Tell.

Request body

Preamble (48)                             universal QMail preamble
Routing header (48)                       qmail_tell_req_t
R × Address entry (32 each)             qmail_address_entry_t
File header (64)                          qmail_file_header_t (start of blob)
M × Server location (32 each)           pass-through storage server map
F × File manifest entry (16 each)        pass-through file list (manifest v1)
Terminator (2)                            3E 3E

Server validates: body_size == 48 + 48 + R×32 + 64 + M×32 + manifest_len + 2. Here R is the recipient count, M is the storage-server count, and F is the file count in the manifest. This is the layout for an email tell (tell_type 0); a payment tell (tell_type 3) uses the same first three sections but carries no server locations and no manifest.

The sections below are in wire order, starting from byte 0.

Preamble (48 bytes, offsets 0–47)

The standard QMail preamble — the first 48 bytes of every QMail request. It carries the sender’s address coin (denomination, serial number) and this RAIDA’s 16-byte AN, which authenticates the sender; the whole request is AES-128 encrypted under that AN. See QMail Overview — Universal preamble for the byte-level breakdown.

Routing header (48 bytes, offsets 48–95)

Layout matches qmail_tell_req_t:

email_id (16 bytes, part 1 of 2) 48 55 email_id (part 2 of 2) 56 63 total_file_size (BE) 64 67 reserved_1 (4 bytes, zero) 68 71 client_timestamp (BE) 72 75 TT 76 N 77 M 78 L0 79 beacon_payment_locker (bytes 1-8 of 16) 80 87 beacon_payment_locker (bytes 9-15 of 16) 88 94 R2 95
OffsetSizeFieldDescription
48–6316email_idThe 16-byte GUID for this email. Same value used as File GUID in the upload calls and used by the recipient when they later call download.
64–674total_file_sizeBig-endian total size in bytes. The beacon does not validate this field on the routing header itself — see the matching field on the file header (offset 46–49) for the enforced check.
68–714reserved_1Available for future use. Set to zero.
72–754client_timestampBig-endian Unix timestamp (seconds) at the moment of build. Server rejects with ERROR_INVALID_PARAMETER if it differs from server time by more than 60 seconds. The 60-second tolerance is a tunable security knob — lower values shorten the replay window once volunteer-operator NTP discipline allows it.
761tell_type0 = email tell, 3 = payment tell. Must equal the file header’s tell_type (offset 28 of the blob). All other values (including the reserved 1–2) are rejected.
771address_count (N)Number of recipients in this tell. Must be > 0.
781server_count (M)Number of 32-byte server-location entries that follow the file header. Must equal stripe_count in the file header.
79–9416beacon_payment_lockerFunded inbox-fee locker for the recipients represented by this Tell. ASCII, null-padded. The beacon may peek this locker to verify that it holds at least the recipient's configured inbox fee before accepting delivery, and the value is passed through to the recipient.
951reserved_2Available for future use. Set to zero.

Address entries (N × 32 bytes)

Layout per recipient matches qmail_address_entry_t. The server iterates the N entries and writes one .tell file to each recipient’s inbox. Offsets below are relative to the start of each entry.

TY 0 coin_id 1 2 DN 3 serial_number (BE) 4 7 locker_payment_key (16 bytes, part 1 of 2) 8 15 locker_payment_key (part 2 of 2) 16 23 reserved (8 bytes, zero) 24 31
OffsetSizeFieldDescription
01typeRecipient kind: 0=To, 1=CC, 2=BCC, 3=Mass.
1–22coin_idNetwork ID. Fixed 00 06.
31denominationRecipient’s mailbox denomination (signed; valid range −8…+6).
4–74serial_numberRecipient’s mailbox SN (big-endian).
8–2316locker_payment_keyFunded locker covering this recipient’s inbox fee. ASCII, null-padded. Must be non-empty (all-zero fails delivery for this recipient).
24–318reservedAvailable for future use, per-recipient. Set to zero.

Notification blob (64 + M × 32 + manifest_len bytes)

The blob is the pass-through payload — the beacon stores it verbatim and the recipient reads it back through ping/peek. For current manifest v1 records, the first 64 bytes are the file header (qmail_file_header_t), followed by M 32-byte server-location entries and then F 16-byte file manifest entries. There is no trailing recipient footer in manifest v1 records; the manifest entries are the last bytes of the blob.

Two of the manifest-header bytes carry sender-controlled metadata that the beacon also acts on:

  • edit_sequence (file-header offset 57) is a monotonic byte set by the sender. The beacon stores the blob verbatim, but on duplicate-GUID delivery it first reads byte 57 of any existing .tell in the recipient’s inbox and rejects the new tell when incoming < existing. Senders revising a previously-sent email bump edit_sequence; replayed older tells are dropped. 0 = original, 1+ = edits. LEGACY manifest-version-0 senders are treated as 0 by definition.
  • parity_algo (file-header offset 58) names the fault-tolerance algorithm the sender used to stripe the email. 0 = RAID-5 XOR (1 parity stripe). Reserved for future Reed-Solomon / GF(2^8) IDs. The beacon uses this to compute its body-size estimate for total_file_size validation; unknown algorithms skip the size check.

File header (64 bytes)

email_id (16 bytes, part 1 of 2) 0 7 email_id (part 2 of 2) 8 15 coin_id 16 17 DN 18 sender_SN (BE) 19 22 DV 23 client_timestamp (BE) 24 27 TT 28 SC 29 locker[0-1] 30 31 locker_code (bytes 2-9 of 16) 32 39 locker_code (bytes 10-15 of 16) 40 45 tfs[0-1] 46 47 tfs[2-3] 48 49 VR 50 MV 51 FC 52 FES 53 manifest_len 54 55 MFL 56 ES 57 PA 58 reserved (5 bytes, zero) 59 63

The two bytes ES (edit_sequence, offset 57) and PA (parity_algo, offset 58) are the sender-controlled extension fields introduced by PR 2. ES drives the beacon's "newer edit wins" guard on duplicate-GUID delivery; PA selects the fault-tolerance algorithm the sender used and gates the beacon's total_file_size sanity check. See the offset 57 and offset 58 rows in the table below for the semantics. Field-key for the diagram: DN=denomination, DV=sender_device_id, TT=tell_type, SC=stripe_count, VR=version, MV=manifest_version, FC=file_count, FES=file_entry_size, MFL=manifest_flags, tfs=total_file_size.

OffsetSizeFieldDescription
0–1516email_idSame GUID as the routing header. Server validates they match.
16–172sender_coin_idNetwork ID. Must be 00 06.
181sender_denominationMust equal preamble denomination.
19–224sender_serial_numberBig-endian. Must equal preamble SN.
231sender_device_idPer-sender device tag. Logged, not enforced.
24–274client_timestampBig-endian. For email tells this file-header timestamp is the one the server enforces (±60 s); payment tells additionally enforce the routing-header timestamp.
281tell_type0 = email tell, 3 = payment tell. Must equal the routing header’s tell_type. Other values rejected.
291stripe_countNumber of server-location entries that follow. For tell_type 0: must be 1…32 and equal the routing-header server_count. For tell_type 3: must be 0.
30–4516locker_codeStandardized 16-byte locker code passed through to the recipient. For tell_type 3 this is the payment locker key itself and must be byte-identical to the address entry’s locker_payment_key.
46–494total_file_sizeBig-endian original size of the primary body object (file_type=1) for legacy convenience. Current recipients should use the manifest entries as the authoritative size list for file_type=0, file_type=1, and attachments. The beacon may sanity-check server-owned fields, but it cannot verify cross-RAIDA storage geometry because it generally does not hold the stored object bytes.
501versionSet to 0x02.
511manifest_version1 for ALL current manifest records, including mail stored through Object Transfer. 0 marks a legacy pre-manifest record and is accepted only for compatibility; new senders must write 1. No other value is valid — object-stored mail needs no richer entry because the object key is derived from the tell itself (object_id = the email GUID in the routing header, generation 1, file_type from the manifest entry).
521file_countFor manifest v1, number of stored files including private meta, body, and attachments. Attachment count is file_count - 2 when both required entries are present. Must be ≥ 2 for new QMail beta records. Legacy v0 records write 0.
531file_entry_sizeFor manifest v1, must be 16. Legacy v0 records write 0.
54–552manifest_lenFor manifest v1, big-endian byte length of the manifest trailing section. Must equal file_count * file_entry_size. Legacy v0 records write 0.
561manifest_flagsFor manifest v1, bit 0 (footer_removed) is set because the 18-byte recipient footer is not part of the current wire format. Bit 1 (crc32_present) is set when the sender filled the per-entry CRC32 field; current object-storing senders always set it — the CRC32 is the receiver’s end-to-end integrity check. Bits 2–7 are reserved (must be 0).
571edit_sequenceSender-controlled monotonic revision byte. 0 = original, 1+ = edits. The beacon reads byte 57 of any existing inbox .tell on duplicate-GUID delivery and rejects when incoming < existing. LEGACY manifest-v0 records are treated as 0.
581parity_algoFault-tolerance algorithm ID. 0 = RAID-5 XOR (1 parity stripe). Reserved for future Reed-Solomon / GF(2^8) algorithms. The beacon uses this to compute the body-size estimate for total_file_size validation.
59–635reservedMust be zero for manifest v1 email tells. For tell_type 3, byte 59 carries the payment_purpose code (see Payment tells) and bytes 60–63 must be zero.

Server location entries (32 bytes each)

The 32-byte format is partially structured (the recipient’s ping parser reads the first three bytes), partially opaque. The rest_core sender writes:

OffsetSizeFieldDescription
01stripe_indexPosition 0…M−1 within the file’s stripe set.
11stripe_typeCurrently encoded as 0=data, 1=parity by the sender. This is not attachment identity; attachment identity belongs in the manifest entry’s file_type.
21server_idRAIDA index (0…24) holding this stripe.
3–1917opaqueCurrently zero-filled by the rest_core sender. Available bytes inside the server-location entry.
20–256IPv4-mapped addressBytes 20–21 are FF FF; bytes 22–25 hold the IPv4 octets of the storage RAIDA.
26–272portBig-endian TCP port of the storage RAIDA.
28–314trailingCurrently zero-filled.

File manifest entries (N × 16 bytes)

The manifest is the authoritative public object list for this email. New QMail beta senders list the private CBDF meta object first with file_type=0x00, the body/content object second with file_type=0x01, and attachments afterward using sequential file types 0x0A, 0x0B, and so on. The receiver downloads file_type=0 first, parses private subject/filename/display metadata locally, and then downloads the body and attachments described by that private meta. The server validates manifest structure but does not read or interpret private CBDF keys.

Object-stored mail uses this same manifest. Senders that store files through Object Transfer (commands 76–84) upload every file under object_id = the email GUID at generation 1, so the receiver derives the full object key from the tell itself: object_id from the routing header, file_type and original_size from the manifest entry. The receiver fetches via object-info/get-range (cmd 81/82), falls back to the legacy striped pages when the object does not exist, and verifies the reconstructed file against the entry’s sender-authored CRC32. No richer manifest entry is needed or permitted on the wire.

Entry offsetSizeFieldDescription
01file_type0x00 private CBDF meta, 0x01 body/content, 0x0A attachment 1, 0x0B attachment 2, etc.
11file_flagsBit 0 = body/content; bit 1 = attachment; bit 2 = private meta; other bits reserved.
2–32reservedMust be zero.
4–118original_sizeBig-endian uint64 size before striping/padding.
12–154crc32Big-endian CRC32 over the original file bytes. Optional: written when manifest_flags.crc32_present (bit 1) is set; zero otherwise. Receivers must only verify the CRC when the flag is set.

Payment tells (tell_type 3)

A payment tell transfers CloudCoins instead of announcing mail. The sender funds a locker with the payment, then sends a tell whose locker_code is the locker key. The recipient’s client recognizes tell_type 3, skips the download flow, and automatically claims the locker into its wallet, recording the sender, timestamp, and purpose code in its transaction log. Nothing is displayed as a message.

There is deliberately no memo field. The only sender-chosen content is one payment_purpose byte. This is what keeps the tell system from becoming a free messaging channel: anyone who wants to say something sends an email tell and pays the inbox fee; a payment tell can only say “here is money, for this standard reason.”

Body layout (exactly 194 bytes)

Preamble (48)                 unchanged — AES-128 + AN authentication as always
Routing header (48)           tell_type=3, address_count=1, server_count=0,
                              beacon_payment_locker = zero
Address entry (32, one only)  recipient mailbox; locker_payment_key = payment locker key
File header (64)              tell_type=3, stripe_count=0, locker_code = payment locker key,
                              total_file_size=0, version=0x02, bytes 51-58 zero,
                              byte 59 = payment_purpose, bytes 60-63 zero
Terminator (2)                3E 3E

Server validates: body_size == 48 + 48 + 32 + 64 + 2 == 194. Exactly one recipient per payment tell — paying N people means funding N lockers and sending N tells. Every fixed byte of the layout is enforced: the routing header’s beacon_payment_locker and reserved bytes must be zero, the address entry must be type To with coin ID 00 06 and zero reserved bytes, the file-header version must be 0x02, and the routing and file-header email_id GUIDs must match (the GUID is the payment ID and drives the same duplicate-delivery protection). Sender authentication applies exactly as for email tells, and both the routing-header and file-header timestamps must be within ±60 seconds.

The two locker fields must match

The address entry’s locker_payment_key (which the beacon’s payment gate verifies) and the file header’s locker_code (which is passed through to the recipient) must be byte-identical. If they could differ, a sender could fund the checked locker while delivering an empty key. The server rejects a mismatch with ERROR_INVALID_PARAMETER.

payment_purpose codes (file header byte 59)

CodeMeaning
0x00Subscription payment
0x01Invoice payment
0x02Gift / tip
0x03Refund
0x04Payroll
0x05Purchase
0xFFUnspecified

The beacon passes the byte through without validating it; recipients display unknown codes as “Other”. New codes are allocated on this page.

Payment gate

Instead of the email inbox-fee gate, a payment tell passes this per-recipient gate:

  1. Blacklist — applies exactly as for email tells (ERROR_SENDER_BLACKLISTED).
  2. Class rejection — skipped. A funded payment supersedes the sender-class filter.
  3. Locker verification — mandatory, even for whitelisted senders. Payment tells are exempt from the recipient’s inbox fee — they carry no message, so there is nothing to charge attention for. Instead the beacon peeks the supplied locker and requires its value to meet the flat minimum payment of 5000 CC. A zero locker key → ERROR_PAYMENT_REQUIRED; a locker below 5000 CC (including empty or nonexistent) → ERROR_PAYMENT_INSUFFICIENT; a temporary verification-backend failure → ERROR_PAYMENT_PROCESSING (sender keeps the tell queued and retries). The client also rejects below-minimum amounts locally before funding a locker.

The 5000 CC floor is the anti-abuse economics: with no memo field, the only nuisance a payment tell could create is dust-value notifications cluttering the transaction log — the minimum makes every unwanted payment tell deliver a substantial amount to its “victim.” The primary use case is subscription payouts: a webserver holding subscriber mailbox addresses sends each member their coins monthly with purpose 0x00, and each member’s client claims automatically. Unlike the email-tell fee path, locker verification for payment tells is not stubbed and not waivable.

Delivery and claim

Accepted payment tells are written to the recipient’s inbox and served by ping/peek exactly like email tells — the pass-through record is just the 64-byte file header. The recipient’s beacon loop then claims the locker (13-of-25 consensus download), deposits the coins into the wallet, and records the transaction. The sender can confirm pickup at any time by peeking the locker: an empty locker means the payment was claimed. No receipt protocol is needed.

Local REST test calls

These calls are for a two-client local test setup where client1 is the sender on port 8081 and client2 is the receiver on port 8082.

# Confirm both local identities
GET http://127.0.0.1:8081/api/qmail/local/identity/whoami
GET http://127.0.0.1:8082/api/qmail/local/identity/whoami

# Optional: stop receiver background beacon so manual peek/ping can consume the Tell deterministically
GET http://127.0.0.1:8082/api/qmail/local/beacon/control?action=stop

# Sender uploads body + one attachment and sends Tell to the receiver
GET http://127.0.0.1:8081/api/qmail/net/messages/upload_and_tell?to=<CLIENT2_QMAIL_ADDRESS>&subject=ManifestTest&body=Hello%20from%20client1&attachment_file_path=C%3A%5Ctmp%5Catt1.txt

# Poll the async task returned by upload_and_tell
GET http://127.0.0.1:8081/api/system/tasks?task_id=<TASK_ID>

# Inspect sender receipt after the task returns file_guid
GET http://127.0.0.1:8081/api/qmail/receipts?guid=<FILE_GUID>

# Receiver consumes the Tell and sees manifest_version/file_count/files[] in JSON
GET http://127.0.0.1:8082/api/qmail/net/beacon/peek?since=0

# Receiver downloads the body and all manifest-listed attachments
GET http://127.0.0.1:8082/api/qmail/net/messages/download?file_guid=<FILE_GUID>

# Confirm downloaded attachment rows and file_type values
GET http://127.0.0.1:8082/api/qmail/db/attachments/list?email_id=<FILE_GUID>
GET http://127.0.0.1:8082/api/qmail/db/attachments/get?email_id=<FILE_GUID>&attachment_id=<ATTACHMENT_ID>&info=1

Response

No body. Status only.

DRD white/black list & inbox-fee gate

Before writing to each recipient’s inbox, the beacon consults its DRD (Group 16) data. The sender’s identity is the AN-authenticated preamble coin, so it cannot be spoofed. Per recipient, in order:

  1. Blacklist — if the recipient’s list has the sender as black (list_type 0x01), the recipient is skipped. If nothing delivers, the Tell returns ERROR_SENDER_BLACKLISTED (236).
  2. Whitelist — a whitelisted sender (list_type 0x00) delivers free: no locker code, no fee, and no class-rejection check.
  3. Class rejection — if the recipient’s DRD record sets a nonzero class-rejection byte, senders whose address denomination is below it are refused with ERROR_SENDER_CLASS_REJECTED (237) — paying more does not help; only a higher-denomination address or a whitelist entry does. The byte is signed denomination encoding (0xFF = −1 = 0.1 CC, which ranks below 0x00 = 1 CC).
  4. Inbox fee — for everyone else, the fee is the recipient’s DRD record fee. A recipient with no DRD record is charged the beacon’s default Tell fee (10 CC, configurable per server in config.toml [drd] and toggleable off) so that spammers cannot sweep guessed serial numbers with free Tells. A DRD record with an explicit fee of 0 means a deliberately free inbox.
  5. Locker — when a fee is due the sender must supply a locker code (the per-recipient locker_payment_key, falling back to the routing header’s beacon_payment_locker). Missing locker → ERROR_PAYMENT_REQUIRED (169). The locker-value comparison against the fee is currently stubbed to accept any supplied locker; when Phase 2 lands, an underfunded locker returns ERROR_PAYMENT_INSUFFICIENT (168).

With multiple recipients, allowed recipients still deliver and the Tell returns 250. Only when zero recipients deliver does the most specific failure win: blacklisted > class rejected > insufficient > payment required > ERROR_WRONG_RAIDA.

Payment tells use a different gate. For tell_type 3 only the blacklist step above applies; the class-rejection and inbox-fee steps are replaced by mandatory locker verification — see Payment tells — Payment gate.

Status codes

DecimalHexSymbolMeaning
2500xFASTATUS_SUCCESSAt least one recipient inbox received the .tell file.
80x08ERROR_COIN_NOT_FOUNDSender’s (denom, SN) is not loaded on this RAIDA.
160x10ERROR_INVALID_PACKET_LENGTHBody too short, missing terminator, address_count or server_count = 0, or actual size doesn’t match the calculated size.
180x12ERROR_WRONG_RAIDAZero deliveries succeeded — every recipient was rejected (bad denom, fee unpaid, filesystem error, empty locker key).
400x28ERROR_INVALID_SN_OR_DENOMINATIONSender denomination outside −8…+6.
1670xA7ERROR_PAYMENT_PROCESSINGTemporary inbox-fee lookup or locker-validation dependency failure. Sender must keep the Tell queued and retry; this is not a permanent recipient failure.
1680xA8ERROR_PAYMENT_INSUFFICIENTDRD gate: a locker code was supplied but its value is below the recipient’s inbox fee. Permanent for this locker; fund a new locker and re-send. (For email tells the locker-value check is currently stubbed to accept any supplied locker; for payment tells the check is mandatory and live — the locker must hold at least the 5000 CC minimum payment. Payment tells are exempt from the recipient’s inbox fee.)
1690xA9ERROR_PAYMENT_REQUIREDDRD gate: the recipient charges an inbox fee (their DRD record’s fee, or the beacon’s default fee when they have no record) and the sender supplied no locker code. Permanent: acquire an inbox-fee locker or get whitelisted, then re-send.
2360xECERROR_SENDER_BLACKLISTEDDRD gate: every undelivered recipient has the sender on their blacklist. Permanent: the sender should not retry.
2370xEDERROR_SENDER_CLASS_REJECTEDDRD gate: the sender’s address denomination is below the recipient’s class-rejection minimum. Permanent for this address; use a higher-denomination address or get whitelisted.
1980xC6ERROR_INVALID_PARAMETERValidation failed on the blob: bad sender_coin_id, denomination/SN mismatch with preamble, timestamp out of range, tell_type not 0 or 3, routing/file-header tell_type mismatch, stripe_count out of 1..32 (email tells) or nonzero (payment tells), payment-tell locker fields not identical, nonzero payment-tell reserved bytes, stripe_count != server_count, unsupported manifest version, invalid manifest length, nonzero manifest reserved bytes, missing required private-meta/body manifest entries, or malformed file flags.
2000xC8ERROR_INVALID_ANPreamble AN does not match server’s stored AN.

Server-side delivery

For each accepted recipient the server writes:

Path: /opt/raidax/QMail_Data/mailboxes/{denom_hex}/{sn}/inbox/00000000{GUID_hex}.tell

Body: pass-through Tell record
      64-byte file header
      M×32 server entries
      N×16 file manifest entries

Migration note: pre-manifest .tell files on disk include an 18-byte recipient
footer (tag=0x50, length=16, recipient_locker). Implementations may strip that
footer when migrating older files. Current manifest v1 records have no footer.

Writes use atomic publish: open a hidden tempfile (.tmp.PID.TIME.SEQ.GUID.tell; payment tells use the disjoint prefix .tmpp.) with O_CREAT|O_EXCL, write, fsync, and rename() into the final .tell path. The recipient’s long-poll inotify watch fires on IN_MOVED_TO only after the rename, guaranteeing the watcher never sees a partial file. Any .tmp.* orphan from a crashed sender is ignored by the directory scanner because the dotfile prefix.

Before each per-recipient write, the beacon checks for an existing .tell at the target path. If one exists and its edit_sequence (byte 57) is greater than the incoming blob’s, the recipient is skipped (the older revision is not allowed to clobber the newer one). Equal-or-greater edit_sequence values overwrite, matching the documented idempotent re-send / edit semantics.

After delivery, when the recipient’s ping or peek reads the file into the response, the server remove()s the file. Tells are one-shot; once read they are gone.

Common mistakes

Skew between client clock and server clock

The 60-second timestamp tolerance is checked twice (routing header + file header). If the sending machine’s clock is wrong by more than 60 seconds, every tell returns ERROR_INVALID_PARAMETER. NTP-sync the sender.

stripe_count vs server_count

The file header’s stripe_count and the routing header’s server_count describe the same M number from different angles. They must be equal — the server compares them and rejects on mismatch. For email tells stripe_count is bounded by 1–32; sending 0 or 33+ is rejected. Payment tells are the opposite: both counts must be exactly 0.

Sender identity lives in two places

The preamble has (denom, SN), and the file header has (denom, SN). Both are validated and must match. If you change the preamble for any reason (per-RAIDA AN swapping during parallel send), make sure the blob still uses the original sender identity, not whatever you just wrote into the preamble.

One tell per beacon, not per recipient’s storage

tell is sent to the recipient’s beacon RAIDA only — not to the storage RAIDAs that hold the stripes. Sending tell to a storage RAIDA wastes a packet; it’ll be accepted but no recipient will ever poll that RAIDA for the notification.

Points of confusion

  1. The server doesn’t verify file existence. tell just writes the notification blob to the recipient’s inbox; it does not contact the storage RAIDAs to confirm the stripes are actually there. If you call tell before upload finishes, the recipient will be told about a file they cannot download.
  2. Inbox-fee lookup failure is retryable, not free. A definite no-fee result means an authoritative zero-fee response (for example success:true with inbox_fee:0) or an explicitly documented server-side mapping such as contact-not-found to fee=0. Do not treat success:false, an error envelope, a missing success field, bad JSON, or no response as free. If the beacon cannot determine the recipient’s inbox fee because rest_core or another payment dependency failed, the beacon returns ERROR_PAYMENT_PROCESSING (167) so the client keeps the Tell queued for retry.
  3. stripe_type is not attachment identity. It remains 0=data or 1=parity. Attachment identity belongs in the file manifest’s file_type field.
  4. Atomic-publish is recent. Older raidax builds wrote the .tell file in place. The current build uses temp+rename so the inotify watcher never sees a partial file. Senders see no behavior change; recipients see a smaller race window.
  5. Multiple reserved regions. Three structures in this command have reserved bytes: reserved_1[4] + reserved_2[1] in the routing header (beacon-local), reserved[8] per recipient address entry (beacon-local), and reserved[5] at offsets 59–63 of the file header (pass-through). Per-file reserved[2] in each manifest entry is also pass-through but only 2 bytes wide. Bytes 57 (edit_sequence) and 58 (parity_algo) of the file header used to be reserved; they now carry defined meanings.