Docs: refresh for v0.6.0 (UpdateMessage + mb.* namespace cleanup)

Two related doc passes:

1. UpdateMessage docs.  docs/API.md "Updating & deleting" section
   previously said "Optional operations. Not every backend
   implements them -- default returns False."  Since v0.6.0 that's
   wrong: UpdateMessage has header-metadata-only semantics on
   every backend.  Rewrote the section to describe the semantics,
   typical use cases (flipping attr bits, reply-chain pointers),
   and the boundary (body / CtrlInfo / SubFields / inline kludges
   untouched; need Delete + WriteMessage for body changes).  Added
   a note by the .Native escape-hatch example that most previously-
   native-only operations now have uni-API equivalents.

2. ma.* -> mb.* namespace sweep.  The 0.5.0 rename renamed every
   source unit but the docs kept the old names in code-block
   `uses` clauses and architecture diagrams.  Copy-paste consumers
   hitting those would get compile errors.  Replaced word-boundary
   ma.<api|types|events|lock|paths|kludge|fmt> references in
   README.md, docs/API.md, docs/architecture.md, docs/ftsc-
   compliance.md, and docs/format-notes/dependencies.md with the
   mb.* form.  Left docs/PROPOSAL.md alone -- that is the pre-
   rename design doc and reads as historical record.

All 75 tests pass; full six-target build clean.  Retagging v0.6.0
in place since no downstream has pinned yet.
This commit is contained in:
2026-04-20 08:21:48 -07:00
parent 9317e8213a
commit 97cbc3e0e8
5 changed files with 80 additions and 53 deletions

View File

@@ -29,8 +29,8 @@ program hello;
{$mode objfpc}{$H+}
uses
SysUtils,
ma.types, ma.events, ma.api,
ma.fmt.jam, ma.fmt.jam.uni;
mb.types, mb.events, mb.api,
mb.fmt.jam, mb.fmt.jam.uni;
var
base: TMessageBase;
@@ -58,15 +58,15 @@ end.
| Format | Units to add to `uses` |
|-----------|---------------------------------------------|
| Hudson | `ma.fmt.hudson, ma.fmt.hudson.uni` |
| JAM | `ma.fmt.jam, ma.fmt.jam.uni` |
| Squish | `ma.fmt.squish, ma.fmt.squish.uni` |
| FTS-1 MSG | `ma.fmt.msg, ma.fmt.msg.uni` |
| Hudson | `mb.fmt.hudson, mb.fmt.hudson.uni` |
| JAM | `mb.fmt.jam, mb.fmt.jam.uni` |
| Squish | `mb.fmt.squish, mb.fmt.squish.uni` |
| FTS-1 MSG | `mb.fmt.msg, mb.fmt.msg.uni` |
| FTN PKT | (moved to `fpc-ftn-transport`; `uses tt.pkt.reader, tt.pkt.writer`) |
| PCBoard | `ma.fmt.pcboard, ma.fmt.pcboard.uni` |
| EzyCom | `ma.fmt.ezycom, ma.fmt.ezycom.uni` |
| GoldBase | `ma.fmt.goldbase, ma.fmt.goldbase.uni` |
| Wildcat | `ma.fmt.wildcat, ma.fmt.wildcat.uni` |
| PCBoard | `mb.fmt.pcboard, mb.fmt.pcboard.uni` |
| EzyCom | `mb.fmt.ezycom, mb.fmt.ezycom.uni` |
| GoldBase | `mb.fmt.goldbase, mb.fmt.goldbase.uni` |
| Wildcat | `mb.fmt.wildcat, mb.fmt.wildcat.uni` |
The `.uni` unit's `initialization` section registers the factory;
without it, `MessageBaseOpen(<format>, ...)` raises `EMessageBase`.
@@ -76,7 +76,7 @@ Threads on Unix need `cthreads` first in the program's `uses`:
```pascal
uses
{$IFDEF UNIX}cthreads,{$ENDIF}
ma.api, ...;
mb.api, ...;
```
---
@@ -256,7 +256,7 @@ if base.SupportsAttribute('attr.returnreceipt') then
RenderReceiptCheckbox;
```
### Canonical attribute bits (`ma.types`)
### Canonical attribute bits (`mb.types`)
The MSG_ATTR_* cardinal constants stay as the internal pivot
between native flag words and the individual `attr.*` boolean
@@ -284,7 +284,7 @@ Bits 0..15 match FTS-0001 exactly; 16+ are for storage-layer flags
(deleted/read/echo/etc.) that aren't part of the FTN wire format.
Use `UniAttrBitsToAttributes` / `UniAttrBitsFromAttributes`
helpers in `ma.types` to bridge the bitset to/from individual
helpers in `mb.types` to bridge the bitset to/from individual
`attr.*` boolean attributes.
### FTN addressing
@@ -395,10 +395,28 @@ function UpdateMessage(Index: longint; var Msg: TUniMessage): boolean;
function DeleteMessage(Index: longint): boolean;
```
Optional operations. Not every backend implements them — the
default returns False. Attribute-only changes can also be made
through the native API (`.Native`) by flipping the MSG_ATTR_DELETED
bit and calling `Pack`; that pattern works on every backend.
**`UpdateMessage` — header-metadata-only, every backend (since v0.6.0).**
Reads the existing message, applies header-shaped attrs from
`Msg`, rewrites the fixed-size header / ISAM record in place.
Body, CtrlInfo (Squish), inline kludges (`*.MSG`), and SubFields
(JAM) are NOT touched. Typical use cases: flipping an attribute
bit (deleted / received / sent), updating reply-chain pointers
(`jam.reply1st` / `jam.replynext`, `squish.reply1st` /
`squish.replynext` list, `hudson.prevreply` / `hudson.nextreply`,
etc.), rewriting `cost` or `msg.timesread`. Callers that need
body-level changes should `DeleteMessage` + `WriteMessage`.
Per-backend header-slot coverage — the attrs each backend honours
on Update are the same slots its `ClassSupportedAttributes`
publishes as "header-shaped." See
[`attributes-registry.md`](attributes-registry.md) for the full
matrix.
`DeleteMessage` is currently optional — not every backend
implements it; the default returns False. Attribute-only
deletion also works via the native API (`.Native`) by flipping
the `attr.deleted` bit on `UpdateMessage` and calling `Pack`;
that pattern works on every backend.
---
@@ -487,7 +505,7 @@ base.Events.MinLevel := metWarning; { drop info + debug }
## Locking
Three layers, all in `ma.lock`:
Three layers, all in `mb.lock`:
1. **TRTLCriticalSection** per `TMessageBase` instance — serialises
concurrent Read/Write/Update/Delete calls on the same instance.
@@ -540,8 +558,8 @@ Use it from there:
```pascal
uses
{$IFDEF UNIX}cthreads,{$ENDIF}
ma.api, { TMessageBase + factory }
ma.fmt.jam, ma.fmt.jam.uni, { destination msgbase }
mb.api, { TMessageBase + factory }
mb.fmt.jam, mb.fmt.jam.uni, { destination msgbase }
tt.pkt.format, { wire-format types }
tt.pkt.reader, { registers mbfPkt }
tt.pkt.batch; { TPacketBatch + Run loop }
@@ -556,7 +574,16 @@ See `fpc-ftn-transport/docs/` for the worker-pool details.
Every `.uni` adapter exposes `Native` for callers who need format-
specific features the unified API doesn't abstract (JAM subfields,
Squish UMsgId, EzyCom dual-byte attributes, Wildcat NextMsg
walking, etc.):
walking, etc.).
Note that many previously-native-only operations have uni-API
equivalents now — e.g. header rewrites go through
`base.UpdateMessage` since v0.6.0 and don't need the `Native`
dance below. Drop to `Native` only when the unified API really
can't express what you need.
Native header-rewrite example (pre-v0.6.0 pattern, still
supported):
```pascal
var
@@ -618,7 +645,7 @@ Native class names:
- `tests/` — test_read, test_roundtrip, test_roundtrip_attrs,
test_lock, test_batch, test_wildcat, test_write_existing,
test_pack, test_hwm, test_consumer_round1
- `ma.kludge` — shared FTSC kludge parsing/emission helpers
- `mb.kludge` — shared FTSC kludge parsing/emission helpers
(`ParseKludgeLine`, `SplitKludgeBlob`, `BuildKludgePrefix`,
`BuildKludgeSuffix`) for callers that need to handle raw FTSC
body blobs outside an adapter