FTN Transport¶
Immortal Barons can carry its league packets over an FTN mail system by itself. The game reads and writes its own private packet directories; the transport wraps those packets for FTN, chooses the next hop, and unwraps them after a mailer session. Neither side has to pretend that a BBS inbound or a BinkP outbox is an ordinary game directory.
The transport has no program of its own. It runs inside the game's inter-BBS
commands, the way the original's BRE PLANETARY writes its own netmail, and it
is configured with lines in bbs.cfg. A board whose packets travel some other
way sets none of those lines and the transport never runs.
This guide covers the operational details. For league concepts, roster HOST
lines, and packet authentication, begin with Inter-BBS Leagues.
The exact ZIP manifest and game-packet fields are in the
developer packet-format reference.
The layers and their directories¶
There are three independent formats:
- A game packet is one signed JSON
.brpdocument. Its contents name its author, final destination, sequence, league, and operations. - A transport bundle is a ZIP file containing one or more unchanged game
packets and transport-only routing metadata. Its temporary FTN name has the
form
NNNNCCCC.BRP. - A stored-message envelope is an optional
.msgfile telling a tosser to send one transport bundle as a file attach. Obox and direct BSO links do not create this envelope.
The same .BRP extension on the first two is intentional, but every file the
transport publishes onto FTN is a ZIP transport bundle unless the link is
raw. Its 8.3 physical
name is only an alias. Packet ZIP members use the canonical IB filename derived
from their contents, and the unwrap step derives that name again rather than
trusting any external filename. A raw JSON packet arriving in the mailer's
inbound is recognized too.
Keep each owner in its own directory. Every setting below is a bbs.cfg line:
| Directory | Owner | Healthy contents |
|---|---|---|
GameInbound |
Immortal Barons | Unwrapped JSON packets waiting for the planetary step |
GameOutbound |
Immortal Barons | Complete JSON packets waiting for the handoff |
data/ftn-spool |
the transport | Usually empty; journals appear while a handoff is incomplete |
AttachDir (default data/att) |
connector/tosser | NNNNCCCC.BRP bundles waiting to be sent |
OutgoingNetmailDir |
scanner/tosser | Outgoing game-owned .msg envelopes |
IncomingFileDir |
mailer | Newly received bundles waiting for the unwrap step |
IncomingNetmailDir |
tosser | Received .msg envelopes naming an attached bundle |
| an obox | connector/mailer | Bundles queued for the peer owning that outbox |
| a BSO directory | tosser/mailer/connector | .?lo, .?ut, .bsy, and point subdirectories |
Do not point GameInbound or GameOutbound at a BBS inbound, filebox, obox,
or BSO directory. The separation is what keeps the game, the transport, and the
mailer from reading or deleting the same file at once.
When it runs¶
| Command | Before the planetary step | After the world is saved |
|---|---|---|
immortal-barons -maint (league board) |
unwrap | handoff |
immortal-barons -planetary |
unwrap | handoff |
immortal-barons -full |
unwrap | play, write the outbox, handoff |
a door session with no -full |
nothing | nothing |
The unwrap step runs when IncomingFileDir is set. The handoff runs when any
Link line is set, or when OutgoingNetmailDir is set and Mailer is not
None. Both take the transport's own lock (barons-ftn.lock in the data
directory), and neither holds the game's world lock while it waits for that
one.
- A failed unwrap is reported as a warning. The run goes on and applies
whatever is already in
GameInbound. - A failed handoff happens after the save, so the run's work is kept, and
the packets stay in
GameOutboundfor the next run. The first run to meet a failure ends non-zero and runs theOnFaultcommand, which is what a scheduler's alarm is for. The same failure on later runs is still printed but does not raise the alarm again, as with the league faults; a different failure does, and so does the same one after a run that succeeded. - Under
-fulla caller is waiting, so neither half waits for the transport lock: if another run holds it, that run is doing the same work, and this one says so on stderr and goes on. A failed handoff runsOnFaultbut does not end the door non-zero.
-planetary can run as often as you like. Run it from the mailer's
post-session event, or after the receive command returns, so what arrived is
applied at once; keep -maint on its timer for the game day. There is no
FTN-wide inbound semaphore, so the unwrap step cannot prove that an unrelated
mailer has finished writing a file. It validates a complete ZIP and every
member digest before it publishes anything.
The complete exchange order is:
- Let the mailer finish its inbound session.
- Run
immortal-barons -maintor-planetary. It unwraps what arrived, applies it, writes replies, scores and broadcasts, and hands them off. - Run the tosser when using
.msgattach links, then let the mailer send its obox or BSO queues.
-data defaults to ./data, relative to the process's working directory. It
can be omitted only when the scheduler starts the command in the Immortal
Barons installation directory.
Scheduling it safely¶
A scheduled run wants two things around it. This shape comes from a Synchronet board running the transport in a league:
#!/bin/bash
set -euo pipefail
# Keep the output. Stall reports are written for a run nobody watched.
exec >>/sbbs/xtrn/imb/data/planetary-run.log 2>&1
echo "=== $(date --iso-8601=seconds) ==="
# One run at a time. A second invocation while this one is working exits
# rather than queueing, since there is no FTN-wide inbound semaphore.
exec 9>/sbbs/xtrn/imb/data/planetary-run.lock
flock -n 9 || { echo "skipped: an earlier run still holds the lock"; exit 0; }
cd /sbbs/xtrn/imb
./immortal-barons -maint
/sbbs/exec/sbbsecho /sbbs/ctrl/sbbsecho.ini
/sbbs/exec/jsexec -c/sbbs/ctrl /sbbs/exec/binkit.js
flock -n keeps an overlapping run from starting. A scheduler that fires
hourly will one day fire while a slow run is still going, and the lock turns
that collision into a clean exit.
The log is opened before the lock so that a skipped run is written down. A run that hangs keeps the lock, and every later run is then skipped. Without the "skipped" line, the log just stops, and the game day, the league's mail and Travel Times all stop with it.
The log matters more than it looks. The handoff names the peers a snapshot is
still waiting on and how long they have been behind, and a scheduled run has
nowhere to print that unless the output is kept. It is also the only record of
every run: the game's own planetary.log gets a line only when a run has
something to report.
Keep it in a file of its own. The game writes planetary.log itself and trims
it to its last 500 lines, so the script's output there would push the game's
fault history out within hours.
cd into the installation directory. -data can then be left off, since it
defaults to ./data.
set -e stops the script when -maint exits non-zero, so the tosser and
mailer do not run after a new handoff failure or a new league fault. That is
usually right, but decide it on purpose. Recoverable transport problems are
reported as warnings and do not change the exit status.
Transport settings in bbs.cfg¶
These lines sit in bbs.cfg beside the board's other settings. The bbs.cfg
Reference lists each one's values and default. IncomingFileDir,
OutgoingNetmailDir and Mailer are the original's BBS.CFG lines 4, 5 and
7, named after the labels its manual gives them.
Inbound settings¶
IncomingFileDir /var/spool/binkp/inbound
OboxMeshFanout Yes
IncomingFileDiris the directory the mailer delivers received files into: attachments and raw obox/BSO bundles. Only a directory named here is unwrapped, apart fromGameInbound, which always is. Give it once per directory the mailer delivers into. Several mailers use more than one: a session that authenticates with a password and one that does not are filed apart, and the directory you leave out is read by nothing. ENiGMA½ is the clear case —secInboundfor an authenticated session,inboundfor the rest:
IncomingFileDir /enigma/mail/ftn_secin
IncomingFileDir /enigma/mail/ftn_in
Mystic files an unauthenticated session into an unsecure child of its
inbound. That child needs its own line too: the unwrap step reads each named
directory and does not descend into it. -ftn-status names any packet left
unread in a directory it can see, including such a child, so the report tells
you a line is missing.
- IncomingNetmailDir is where the tosser
leaves received .msg envelopes. Left unset it means every IncomingFileDir, so the order of those lines
cannot decide whether an envelope is seen. Set it only to look somewhere else
entirely.
- OboxMeshFanout defaults to Yes. It
controls only an unaddressed broadcast received without an attach envelope. See Mesh warning.
Stored-message attach settings¶
OutgoingNetmailDir /sbbs/fido/netmail
AttachDir /sbbs/fido/ib-attach
Mailer Binkley
SubjectPath Absolute
OutgoingNetmailDiris where the game writes outgoing.msgenvelopes for the scanner to pack. It is required when any peer usesAttach, including the default for a peer with noLinkline.AttachDirholds outgoing bundles for Attach and BSO links. If omitted, the transport usesdata/att(#231: deliberately not nested under its other spool directories, since this is the one path a mailer's Subject field has to spell out under a hard byte limit — see Keeping attach subjects short).Mailersays how the netmail asks for the attachment to be deleted once sent, or turns netmail off.SubjectPathsays how the attachment path is spelled in the Subject. The stored-message Subject has 71 usable bytes, or 70 with the^prefix.
On the receiving side, the tosser normally leaves both the bundle and its stored-message envelope in the configured inbound. The unwrap step verifies that the message:
- has the file-attach attribute
- identifies Immortal Barons
- names exactly one attachment inside an
IncomingFileDir - comes from a roster address
- is addressed to this board
Only after all packets are delivered or forwarded does it delete both files. Other netmail is never removed.
Keeping attach subjects short¶
The IB installation and data directories may be arbitrarily deep if
AttachDir is a short absolute path. For example:
AttachDir /var/spool/ib-attach
SubjectPath Absolute
This writes a Subject such as
/var/spool/ib-attach/7PRK0001.BRP; the installation path is not included.
A relative AttachDir is resolved beneath the data directory and therefore
does not provide this workaround. The data directory is always spelled in full,
even when -data is relative, so the default data/att puts the whole
installation path into the Subject. Create the attachment directory with
ownership and permissions that allow both the game and the mailer to use it.
Do not use /tmp or another automatically cleaned directory for this purpose.
An attachment may remain queued across a reboot or cleanup interval, and
removing it leaves the mailer with a dangling .msg envelope. Use a short,
persistent spool directory instead.
SubjectPath Basename shortens the Subject further, to only
7PRK0001.BRP, but it is correct only when the mailer is independently
configured to search the same directory named by AttachDir. The game
cannot infer or configure that mailer search path, and not every mailer has
one to configure — SBBSecho does not: it takes the directory straight from
the Subject with no attachment search path at all, so a bare filename is
looked for in its ctrl directory and reported not found. Basename is not a
usable option on SBBSecho for this reason; use AttachDir (or an absolute
SubjectPath prefix naming the same directory) instead. BSO flow files and
oboxes do not use a Type-2 Subject, so the 71-byte limit applies only to
Attach links.
Per-peer links¶
Each Link identifies a directly connected IBBS roster node:
Link 2 Attach
Link 3 Obox /var/spool/binkp/outbox/node3
Link 4 BSO /var/spool/ftn/outbound.309 Hold
The modes are:
Attachcreates a game-owned.msginOutgoingNetmailDiraddressed to that next hop. It takes no per-link directory. It is the compatibility default, and it is the weakest of the three: a tosser stands between the game and the mailer, and the Subject limit above is its alone. PreferBSOwhere the mailer keeps a Binkley-style outbound.Oboxatomically publishes the bundle in the named peer-specific directory. The mailer must treat a final-name appearance as a complete file.BSOtakes the destination's.bsy, then either merges into a compatible Barons bundle already named by that flavor's flow file or publishes a new bundle inAttachDirand adds a delete-after-send flow entry. The directory must be the exact root for that address's zone; the transport does not guess domain-to-zone mappings.
A link mode has to be one the peer can receive. It describes a handoff between two boards, so the mode you send with is only half of it:
Attachrequires the receiving board's mail system to leave the.msgenvelope as a file where its unwrap step can read it — itsIncomingNetmailDir, which unset means everyIncomingFileDir. Synchronet with SBBSecho does that. Mystic does not: it tosses netmail into its own message bases and leaves no.msgfile behind, so a Mystic board can never claim an attach. Reach a Mystic peer withOboxorBSO.OboxandBSOneed nothing of the receiver but its mailer, since the bundle arrives as an ordinary file in the inbound.
A board sent an attach it cannot claim does not refuse it. The bundle stays in
its inbound and is skipped on every run, with no warning on either side, while
the sender's own logs report a clean handoff. Since a peer with no Link line
of its own uses Attach, a bbs.cfg carrying no links at all cannot reach a
Mystic board — which is how this was found on a three-board test rig, after 30
bundles had collected.
A BSO link takes an optional flavor. A point address
uses the standard <net><node>.pnt/<point>.?lo layout automatically.
If a destination has no Link, it uses Attach, so a board with no Link
lines sends every next hop through the .msg chain. This fallback applies to
addressed routing. Once any Link is present,
unaddressed mesh fanout uses only the explicitly listed peers; otherwise the
transport would invent graph edges and defeat a ring or partial mesh. List every
direct fanout neighbor, including one that uses Attach. A hub may freely mix
all three modes.
Plain packets for boards that cannot read a bundle¶
A board runs raw by default, and that is deliberate for this release. A peer that cannot unwrap a bundle does not merely fail to read it — its inbound run stops on the first one it meets and applies nothing at all until someone removes the file by hand. So a sysop who upgrades and configures nothing keeps sending what every board already understands, and has to ask for the faster shape rather than arrive at it.
The test is what release the peer runs, not how it is set up. From v0.2.0,
-planetary, -maint and -full unwrap a bundle wherever it lands: in an
IncomingFileDir, or straight in GameInbound. So a board whose mailer drops
files into GameInbound — the file-drop arrangement described under Optional
FTN handoff — reads a bundle with no FTN
settings at all. A board on an older release cannot read one, whatever it has
configured.
A bundle found in GameInbound is checked as one from IncomingFileDir is,
and its packets are written beside it for the planetary step. A packet in it
addressed to another board is passed on by the planetary step, as it would be
had it arrived unbundled; nothing is forwarded over FTN from there. A file that
starts like a bundle but cannot be read is set aside in ftn-spool/bad once it
is five minutes old.
Turn bundling on for the whole board with Bundled once
every peer runs v0.2.0 or later:
Bundled Yes
Or per peer, when a league is part way through upgrading. Add Raw or
Bundled to the end of any link line; it overrides the board-wide setting for
that peer only:
Bundled Yes
Link 3 Obox /home/bbs/filebox/peer Raw
Raw is a modifier rather than a mode of its own, because the envelope is what
an old board cannot parse, not the way the file travels: it composes with
attach, obox and BSO alike, and on a BSO link it is never merged into a bundle
already advertised in the flow file.
Raw costs one attachment alias per packet, gives up coalescing, and carries no routing manifest — a receiver rebuilds the route from the packet's own origin and learns nothing about which peers a broadcast already reached, bounded by the hop limit and by replay detection instead. That is exactly how the transport behaved before bundles existed, and it is the price of reaching a board that cannot read one.
On a routed league only the Coordinator has to do anything. Every member
sends it plain packets already, and its unwrap step reads those whatever they
are.
It is the Coordinator's own sends that need Raw, and it can drop the setting
for one member at a time as each upgrades, or switch the whole board to
Bundled Yes once the last one is done.
Configuration examples¶
Two boards using direct oboxes¶
On node 1:
IncomingFileDir /mystic/echomail/in
Link 2 Obox /mystic/filebox/ib_z99n1n2
On node 2, reverse the peer and directory:
IncomingFileDir /mystic/echomail/in
Link 1 Obox /mystic/filebox/ib_z99n1n1
The game itself uses private paths:
GameInbound inbound
GameOutbound outbound
Routed star with mixed links¶
The roster makes node 1 the hub:
1 HOST 2 3 4
Hub BBS
777:10/1
...
The hub can use a different local handoff for every child:
IncomingFileDir /srv/ftn/inbound
OutgoingNetmailDir /sbbs/fido/netmail
AttachDir /srv/ib/attach
Mailer Binkley
Link 2 Attach
Link 3 Obox /srv/binkd/obox/node3
Link 4 BSO /srv/binkd/outbound Normal
A packet from node 2 to node 4 arrives inside node 2's attach. The hub's unwrap step unwraps it, leaves its signed JSON bytes untouched, and publishes a new transport bundle through node 4's BSO flow. It does not wait for the hub's next planetary run.
Synchronet¶
BinkIT keeps a Binkley-style outbound, so a Synchronet board should hand the bundle to that outbound directly:
IncomingFileDir /sbbs/fido/inbound
Link 1 BSO /sbbs/fido/outbound Normal
The outbound chain is:
immortal-barons -maint -> NNNNCCCC.BRP + .flo entry -> BinkIT
SBBSecho is not in that path. The Subject byte limit does not apply either,
because a flow file holds the whole pathname, so AttachDir can stay at its
default.
Name the outbound directory for the destination's zone. Synchronet writes the
system's own zone into the base directory and every other zone into
outbound.<zone in hex>. See Direct BSO/FLO handoff
for what the transport writes there.
Direct BSO/FLO handoff¶
IncomingFileDir /var/spool/binkd/in
AttachDir /var/spool/ib/attach
Link 3 BSO /var/spool/binkd/outbound Normal
For peer 1:229/300, the transport uses 00e5012c.bsy and 00e5012c.flo in the
configured BSO directory. The flow line begins with ^ and contains the full
attachment pathname, asking the mailer to delete it after success.
While it owns 00e5012c.bsy, a later run may add its new snapshot to an
existing compatible Barons bundle referenced by that flow file. It atomically
replaces the ZIP wrapper at the same pathname; every signed packet member is
copied byte-for-byte. Exact-member deduplication makes a replay after a crash
idempotent. Entries without ^, files outside AttachDir, non-Barons files,
other leagues or transmitters, and full bundles are not modified.
For point 1:229/300.4, the paths are:
00e5012c.pnt/00000004.bsy
00e5012c.pnt/00000004.flo
If .bsy already exists, that peer is normally reported busy and its durable
spool transaction remains pending. The invocation does not poll or sleep: other
peers continue, and the next scheduled run resumes pending transactions before
claiming new work. The narrowly scoped exception is an old semaphore carrying
the transport's own PID marker; recovery is described below.
Bundling, names, and recovery¶
Every handoff takes one fixed snapshot under the same game.lock used by
Immortal Barons. Packets written after that claim wait for the next run. All
packets in the snapshot which share a next hop go into one ZIP bundle.
The FTN alias is NNNNCCCC.BRP:
NNNNis a four-character base-36 namespace derived from this league and the transmitting hop's node number. The encoding reserves a distinct namespace for legacy league-0packets so one such packet cannot wedge a transport batch; that compatibility namespace is not a substitute for the Coordinator-assigned league number.CCCCis a persistent four-character base-36 counter.- The counter advances for every physical handoff, including each broadcast copy, and does not reset with a new game season.
The counter is reserved before publication, so a crash may skip a value but cannot reuse it. Wrap is reported loudly. An existing alias is never overwritten; the allocator advances until it finds a free one.
Attach and obox bundles are immutable after publication. Obox reuse may be possible with a particular mailer's documented claim/rename protocol, but no common obox lock is assumed here; it remains disabled pending interoperability and race testing.
BSO is the exception. FTS-5005 gives the destination one .bsy covering its
outbound files. After acquiring that semaphore, the transport may safely rebuild
a compatible bundle already advertised in the selected flow file. It releases
.bsy only after the replacement is durable.
FTS-5005 permits a .bsy to contain one line of PID information. A semaphore
created here contains barons-ftn pid=<number>, and the process also locks its
first-byte range on Windows, or takes a whole-file flock on Unix, for the
complete BSO update. A later run removes that semaphore as stale only when
all three checks agree:
- the marker is exactly ours
- the ownership lock can be acquired non-blockingly
- the file is at least five minutes old
It then retries the standard exclusive .bsy creation. Thus a live run remains
protected even if its semaphore's timestamp is old, while a crash becomes
recoverable without guessing from age alone.
An empty, malformed, young, locked, or foreign-marked .bsy is simply busy.
The transport never applies its five-minute policy to a mailer or tosser's
semaphore; the mailer's own FTS-5005 age/restart mechanism remains responsible
for those. A legacy empty semaphore left by an older release is likewise
indistinguishable and follows the mailer's policy. Never manually clear .bsy
files merely because a peer is slow or offline.
Progress journals live under data/ftn-spool; the claimed bundle itself is
written to AttachDir (default data/att) or to the peer's obox. A target is
marked complete only after its bundle and .msg, obox placement, or BSO flow
entry are durable. A restart uses the same alias and bytes, recognizes an
already-created attach message, and completes only unfinished targets.
Inbound rejection is per packet member, not per bundle. A wrong-league packet,
unknown destination, or routing cycle is recorded in the receipt while valid
members are still delivered or forwarded. After those valid members finish,
the complete original transport wrapper moves to ftn-spool/bad so the rejected
routing context remains available for diagnosis; it is not retried on every
later run. A local canonical-name collision is different: the receipt
and source stay pending because the operator must decide which bytes are valid.
Both halves of the transport hold barons-ftn.lock. Movement between the
connector spool and the private game directories also holds game.lock. The
lock order is always transport first, game second, and the game never waits
for the transport lock while it holds its own. Atomic
renames and exclusive file creation remain additional protections.
On local delivery, an existing canonical filename with identical bytes is logged as a duplicate, not rewritten, and not counted as a new delivery. If that canonical name already belongs to different bytes, the transport reports a collision and retains its receipt and source rather than overwriting either file or inventing a noncanonical name.
Routing and broadcasts¶
The JSON packet names its final destination. A transport bundle is addressed only to the next FTN hop. At a hub, the unwrap step reads enough JSON to choose the next hop but copies the original JSON bytes into the new bundle without changing or re-signing them. The actual node route and broadcast coverage live in the ZIP manifest and are discarded before local game delivery. The final route node is the transmitting hop, and the route length supplies the hop count, so neither fact is stored twice.
A routed league with HOST lines is the normal and recommended arrangement.
The game creates addressed broadcast copies before signing, and the connector
routes each copy normally.
Mesh warning¶
An old-style unaddressed broadcast has no final node. When it arrives over
Obox or BSO and OboxMeshFanout Yes, the unwrap step delivers it locally and sends it to
every configured peer in neither its route nor its covered list. Before a
sender publishes sibling copies, it puts every durably scheduled recipient in
the common covered list. This prevents those recipients from reflexively
cross-sending the same broadcast.
These lists limit amplification; they do not make distributed fanout exactly once. In particular, a simple cycle of four or more nodes can have independently scheduled branches meet after both are already in flight, producing duplicates. The hop limit prevents an infinite loop, and canonical-name plus exact-byte duplicate detection lets the inbound converge safely.
If the topology is a true mesh and the source already reaches every board, set:
OboxMeshFanout No
Then the unwrap step delivers an unaddressed broadcast locally and stops. The source
transport is responsible for putting one copy on every required direct link.
Do not use this switch to disguise a physical star whose roster claims to be a
mesh; describe that star with HOST lines instead.
Troubleshooting by file location¶
This table is about the transport. When the question is the game's — a packet that arrived and was refused, held, or quarantined, or a board that has gone quiet — see Inter-BBS Troubleshooting.
| Where files accumulate | Meaning | Action |
|---|---|---|
GameOutbound |
The handoff did not run, or failed | Run immortal-barons -planetary; read its error |
ftn-spool/out |
At least one target is busy or failed | Read the warning; inspect that peer's .bsy, path, or netmail directory |
AttachDir (default data/att), envelope still in OutgoingNetmailDir |
Normal. The attachment waits for the tosser to pack the .msg that names it |
Nothing. Run/check the tosser |
AttachDir (default data/att) with no .msg/flow |
Attach or BSO queue publication failed | Check subject length, OutgoingNetmailDir, BSO directory, and permissions |
OutgoingNetmailDir .msg |
The tosser has not packed outgoing netmail | Run/check the tosser and allow file attaches |
BSO .?lo |
The mailer has not successfully sent the referenced bundle | Check peer address, password, route, and .bsy |
| peer obox | The mailer has not sent or acknowledged the file | Check the peer session and outbox mapping |
IncomingFileDir |
The unwrap step did not run, ran before receive completion, or rejected the wrapper | Run -planetary after the session and read warnings |
IncomingFileDir, listed by -ftn-status as unclaimed |
Attach bundles whose .msg envelope never arrives here — see Per-peer links |
unzip -p FILE manifest.json to confirm "delivery": "attach"; have the sender switch that link to Obox or BSO |
a subdirectory of IncomingFileDir, named by -ftn-status |
The mailer filed an unauthenticated session's files apart from the rest; the unwrap step reads each IncomingFileDir and nothing below it |
Give that subdirectory its own IncomingFileDir line, or fix the session password for that peer and move the waiting files up |
ftn-spool/in |
Local publication or transit handoff is incomplete | Correct the named target; the next run resumes it |
GameInbound |
The planetary step has not applied the unwrapped packets | Run immortal-barons -planetary |
GameInbound, a bundle |
The unwrap did not run, another run held the transport lock, or the bundle's sender is not on this board's roster yet | Run immortal-barons -planetary and read its warnings |
ftn-spool/bad |
An outbound packet was malformed/unroutable, an inbound bundle contained a rejected member, or a file in GameInbound started like a bundle and could not be read |
Preserve it for diagnosis; correct the producing board, route, league, or roster |
One bad packet or busy peer does not stop unrelated destinations. Do not delete spool journals to make a warning disappear: they are the record that prevents partial work from being forgotten or blindly repeated.
The same goes for the files in AttachDir, which look more disposable than
they are. On a hub most of them are not this board's own mail at all: they are
packets that arrived addressed to somebody else and were re-published toward
their next hop. The board that sent one has already seen it handed over
successfully, so it will never send it again — deleting the attachment loses
that mail for good, and the recipient's only symptom is a board that went
quiet.
Before removing anything from AttachDir, decide which of the two rows above
applies, because they look identical in a file listing:
- Run
immortal-barons -ftn-status. A receipt held in transit for another board names that board and that peer's last error. Anything it still lists is owed to somebody. - Find the envelope. Each
Queued <packet> for <next hop> as <message>line from the run that created the attachment names the.msgthat carries it, so the mapping is in the log. An envelope still sitting inOutgoingNetmailDirmeans the tosser has not packed it yet and the pair is fine. An envelope that has gone while its attachment stayed is the fault worth chasing.
What a healthy spool looks like¶
A file count is the wrong measure here, and reading one as a backlog is the
mistake to avoid. ftn-spool/out holds one child per claimed snapshot of the
game's outbound, and a snapshot is kept whole until every target in it has been
published — so one unreachable peer retains that snapshot's packets and the
bundles of the peers that already went out. A peer that stays unavailable
therefore produces a growing series of snapshot directories while healthy peers
keep flowing, which is working as intended and not a queue of that many unsent
packets.
What to read instead:
- The handoff says so on every run. A run that publishes nothing because its peers are busy prints how many snapshots remain and which peers they wait on, so a scheduled event's log distinguishes an empty system from a stalled one. The same peer named run after run is the signal worth acting on.
ftn-spool/inshould drain. A receipt kept across runs means a canonical-name collision whose bytes differ, a transit handoff that has not completed, or a source or envelope that could not be removed. Itsreceipt.jsonnames which.- The journals date themselves. A snapshot records when it was claimed and when a target in it last published, and a target that failed keeps the reason. A run that queues nothing therefore reports how long the oldest snapshot has gone without progress and why each peer is behind, rather than only how many are waiting. All three fields are optional: a journal written before they existed still loads, and its file date stands in for the age.
immortal-barons -ftn-statusanswers all of this and changes nothing. It reports each peer's unfinished snapshots longest wait first, with the recorded reason, the pending inbound receipts and which of the three ways each is stuck, any journal that will not parse, and how many packets are set aside. Reach for it before reading directories by hand.- It also reports packets nobody has claimed, which are in neither spool.
A file the transport never took is a file no journal knows about, so the
counts above cannot show it.
-ftn-statuslists any.BRPthat has sat in anIncomingFileDir, or in a subdirectory of it, for over an hour, and the unwrap step warns about the same files as it runs. The troubleshooting guide has the two causes and what to do about each. immortal-barons -league-checkreports the same backlog alongside the rest of the league setup, for the sysop who has gone looking there first. A waiting peer is shown but not marked a fault — a peer can be legitimately offline for days — while a journal that cannot be read is a FAIL, because nothing else will ever mention it. A packet nobody has claimed is a FAIL for the same reason: it sits in neither spool, so no other line here counts it.ftn-spool/badonly grows. Nothing is retried from it and nothing removes it; it is yours to read and clear once the producing board, route, league or roster is corrected.AttachDir(defaultdata/att) should also drain: a bundle sitting there with no matching.msg/flow entry means the Attach or BSO queue publication step failed after the bundle was written — check the same causes as the troubleshooting table above (subject length,OutgoingNetmailDir, BSO directory, permissions). This directory is deliberately not underftn-spool/and not shown by-ftn-status's spool report — it is the one transport path a mailer's Subject field has to spell out under a byte limit, so it lives where the sysop can pointAttachDirat a short location if the default does not fit.
A published alias belongs to the mailer, not to the game. Once a target is published and marked done, its snapshot can disappear and the game no longer holds a journal saying that file is outstanding — the evidence moves to the transport:
| Mode | What holds the alias | Cleared when |
|---|---|---|
| Attach | the matching .msg names it |
the tosser and mailer chain sends it |
| BSO | a ^ entry in the flow file |
the mailer sends it and deletes it |
| Obox | the queued file is the mailer's own state | the peer session takes it |
So an alias sitting in a directory is not evidence of an abandoned file. A peer offline for a week is still a valid queue, and age alone cannot tell the two apart. Report growth, and delete only with mode-specific proof from the list above that the owning mailer is finished with it.
Upgrading from barons-ftn¶
Before this release the transport was a separate program, barons-ftn, with
its own settings file, ftn.cfg. Both are gone. On a board that still has
ftn.cfg, -maint and -planetary refuse to run and print that file's
settings rewritten as bbs.cfg lines. Paste those lines into bbs.cfg, delete
ftn.cfg, and take barons-ftn out of the scheduler and the mailer's hooks:
-maint and -planetary now do its work. bbs.cfg settings spelled the way an
older release wrote them are refused the same way, with their replacements.
A door launched with -full never keeps a caller out over this. It prints the
same lines, skips the league exchange, and lets the caller play. -ftn-status
prints them too, and then its report.
To check the move, run -ftn-status once ftn.cfg is gone. It names each
half of the transport that has no lines in bbs.cfg ("Sending: no
OutgoingNetmailDir or Link line…"). A board that ran barons-ftn should see
neither line.
An old barons-ftn binary left on disk and still scheduled does no harm once
ftn.cfg is deleted. It cannot find its settings, so it exits with an error on
every run and moves nothing. The transport lock keeps its old name, so an old
copy that does still run queues behind the game's own transport instead of
running beside it.
The packet format does not change in this release, so boards can upgrade one at a time.
Turning bundles on¶
A board sent a ZIP bundle needs a release that unwraps one: v0.2.0 or later,
which reads a bundle in IncomingFileDir and in GameInbound alike. An older
release cannot parse it as a JSON packet. Upgrade every receiver before any
sender switches to bundles:
- Upgrade every board, and run
-planetaryafter receive sessions. - Verify that raw
.brptraffic is still delivered to the game. - Configure the per-peer
Linkmodes. - Turn on
Bundled Yeson the senders.
Because the unwrap accepts raw JSON packets, steps 1–2 can be completed without coordinating an exact cutover minute.
This is the rolling case, and a protocol change is not. The order above
covers the transport container, which the game's Protocol number does not
describe. When a release moves that number, the league closes the game, lets
every board finish sending what it has queued, and switches together. Its
release notes will say so.
An Attach link with no AttachDir set gets one under the data directory (see
Stored-message attach settings). A board
whose data directory is already deep, as a Synchronet door is under the usual
<sbbs>/xtrn/<door>/data layout, can lose all its Subject margin to that alone
and publish nothing. If the handoff fails with an attachment subject ... is N
bytes error, set AttachDir to a short, persistent directory outside the data
tree per Keeping attach subjects short.
A Synchronet board should use a BSO link instead. See
Synchronet.