diff --git a/README.md b/README.md index 8779303..7d5f5d4 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,9 @@ motd.txt - Message of the Day (optional, shown to users on connect) tnt.service - systemd service unit ``` +The persisted chat-history format is documented in +[docs/MESSAGE_LOG.md](docs/MESSAGE_LOG.md). + ### MOTD (Message of the Day) Place a `motd.txt` file in the state directory to show a welcome message to every user on connect. Users see the MOTD before entering the chat and press any key to continue. diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1b0c4cc..da8e83b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,8 @@ ### Added - Documented the stable SSH exec interface contract, including exit statuses and JSON field shapes for package tests, scripts, and future `tntctl` work. +- Documented `messages.log` v1 as the stable TNT 1.x persisted history format, + including parser, sanitization, and partial-record recovery rules. - Added a public security policy, supported-version guidance, and GitHub issue templates for bug reports and feature requests. - Added `tntctl`, a thin local wrapper around the documented SSH exec diff --git a/docs/Development-Guide.md b/docs/Development-Guide.md index 362c6ce..a52eceb 100644 --- a/docs/Development-Guide.md +++ b/docs/Development-Guide.md @@ -291,6 +291,9 @@ void room_broadcast(chat_room_t *room, const message_t *msg) { ### 3. Message Persistence (message.c) +See [MESSAGE_LOG.md](MESSAGE_LOG.md) for the stable TNT 1.x on-disk record +contract. + **Log format:** ``` 2024-01-13T10:30:45Z|username|message content diff --git a/docs/INTERFACE.md b/docs/INTERFACE.md index ffe13af..de9b65a 100644 --- a/docs/INTERFACE.md +++ b/docs/INTERFACE.md @@ -23,12 +23,14 @@ Stable: - SSH exec command names and argument shapes listed below - SSH exec exit statuses - JSON field names and value types for documented `--json` commands +- `messages.log` v1 record format documented in + [MESSAGE_LOG.md](MESSAGE_LOG.md) Not yet stable: - exact human-readable diagnostic wording - interactive TUI layout -- on-disk message log format +- future storage migration tooling - internal module names and helper functions ## Exit Status diff --git a/docs/MESSAGE_LOG.md b/docs/MESSAGE_LOG.md new file mode 100644 index 0000000..4b7517f --- /dev/null +++ b/docs/MESSAGE_LOG.md @@ -0,0 +1,60 @@ +# 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`. + +## 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. + +## 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. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 7b70a1e..2b03a25 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -54,12 +54,12 @@ Goal: make long-running operation boring and reliable. Goal: make stored history durable, inspectable, and recoverable. -- formalize the message log format and version it -- keep timestamps in a timezone-safe format throughout write and replay +- ✅ formalize the message log v1 format +- ✅ keep persisted timestamps in UTC throughout write and replay - ✅ validate persisted UTF-8 and record structure before replay/search - add log rotation and compaction tooling - provide an offline inspection/export command -- define broader recovery behavior for truncated or partially corrupted logs +- define broader recovery tooling for truncated or partially corrupted logs ## Stage 4: Interactive UX diff --git a/tnt.1 b/tnt.1 index c0d9496..85f879d 100644 --- a/tnt.1 +++ b/tnt.1 @@ -302,9 +302,13 @@ libssh log verbosity from 0 to 4 (default: 1). .SH FILES .TP .I messages.log -Chat history in RFC\ 3339 pipe\-delimited format +Chat history in the TNT message log v1 format: +RFC\ 3339 UTC pipe\-delimited records .RI ( timestamp | username | content ). Stored in the state directory. +See +.I docs/MESSAGE_LOG.md +in the source distribution for parser and recovery rules. .TP .I host_key RSA 4096\-bit host key, auto\-generated on first run.