# Message Log This document defines the persisted chat-history format used by TNT 1.x. ## Format: `messages.log` v1 Each record is one UTF-8 line: ```text RFC3339_UTC|username|content\n ``` Example: ```text 2026-05-27T12:34:56Z|alice|hello ``` Rules: - Timestamp is strict UTC RFC3339: `YYYY-MM-DDTHH:MM:SSZ`. - The separator is literal `|`. - A valid record has exactly three fields and exactly two separators. - `username` and `content` must be non-empty valid UTF-8. - `username` must fit `MAX_USERNAME_LEN`; `content` must fit `MAX_MESSAGE_LEN`. - Every complete record ends with `\n`. The file has no header. The version is defined by this record contract so existing append-only logs remain readable. ## Write Behavior `message_save()` sanitizes fields before appending: - `|`, `\n`, and `\r` in usernames become `_`. - `|`, `\n`, and `\r` in content become spaces. - Timestamps are written in UTC. Private messages are not written to `messages.log`. `:inbox` stores incoming and sent private-message copies only in each participant's live session memory, so inbox state is lost on disconnect and never appears in `tail`, `dump`, `:last`, or `:search`. ## Replay And Search Replay and search use the same strict parser. TNT skips records that are: - malformed or missing fields - invalid UTF-8 - too long - outside the accepted timestamp window - terminated without a trailing newline - written with extra separators Skipping a bad record is intentional recovery behavior. A truncated final line is treated as a partial append and ignored rather than replayed. ## Export `dump [N]` and `dump -n N` export valid persisted records through the SSH exec interface and `tntctl`. The output format is exactly the v1 record format above. Without `N`, `dump` exports all valid records; with `N`, it exports the last `N` valid records. ## Maintenance `scripts/logrotate.sh` is the manual archive and compaction tool for `messages.log`: ```sh scripts/logrotate.sh [--dry-run] [--keep-archives N] LOG_FILE MAX_SIZE_MB KEEP_LINES ``` When the log exceeds `MAX_SIZE_MB`, the script archives the full file, compacts the active file to the last `KEEP_LINES` records, compresses the archive when `gzip` is available, and removes older archives beyond the retention limit. Run it while TNT is stopped or during a quiet maintenance window if strict log consistency matters. ## Recovery Installed `tnt` binaries provide offline log checking and recovery: ```sh tnt --log-check LOG_FILE tnt --log-recover LOG_FILE > recovered.messages.log ``` `--log-check` prints a summary: ```text path /var/lib/tnt/messages.log records_seen 120 valid_records 119 invalid_records 1 first_invalid_line 120 ``` It exits `0` when every record is valid and `1` when invalid records are found or the log cannot be read. `--log-recover` writes only valid v1 records to stdout, prints the same summary to stderr, and also exits `1` if records were skipped. It never modifies the source log. ## Compatibility The v1 record format is stable for TNT 1.x. Future incompatible storage changes must document downgrade behavior in release notes and provide an operator-visible migration or export path.