Files
trail-mate/docs/engineering/linux-peer-directory.md
T
Trail Mate Dev 6e613e382e Add CM0 Linux support and share device services across platforms
Compose the CM0 fullscreen application and standard Debian package, align the
Cardputer Zero shell, and share protocol, configuration, audio and storage
services with embedded targets through existing platform seams.

Add the paginated on-device TMAP creator using Center's published producer,
private workspace recovery and direct keyboard shortcuts. Preserve unfinished
management work behind its existing opt-in capability.

Include native, ARM and shared-core regression fixtures, integration records,
packaging helpers and dependency/license updates. Keep local build trees,
device credentials, produced packages and validation logs outside version control.

Validation before integration: ESP stack hygiene, Reticulum scope guard, staged
whitespace checks and GitNexus scope audit. Prior device/build evidence and
remaining hardware/package boundaries are recorded in the acceptance documents.
2026-10-29 10:29:29 +08:00

3.8 KiB

Native peer directory ownership

Shared data, native concurrency

LinuxPeerDirectory implements the existing IMeshPeerDirectory port around one MeshPeerDirectoryCore. Its format, protocol partitions, identity keys, fact-merging rules and local flags remain owned by that core. Native callers serialize memory operations through a short recursive mutex; no blob I/O runs under that mutex. Read-only visitor reentry is allowed, while mutation or flush from a visitor returns Busy instead of invalidating its scan or deadlocking.

One storage thread loads the existing blob, encodes persistence snapshots and saves them. Startup begin() waits for initial loading. Runtime record() acknowledges admission to the in-memory owner and schedules persistence; it does not assert a durable observation. Administrative mutations retain an explicit persistence barrier before returning, and flush() waits for a fresh attempt covering its target revision. These administrative/startup barriers can wait for storage and are not frame-loop query operations.

The storage thread allocates its encoded byte buffer outside the mutex, copies a coherent core revision under the mutex and performs the physical write after unlocking. It acknowledges a revision only after the port accepts that write. Concurrent newer observations stay dirty and are encoded again. Save failure retains dirty memory and retries with a bounded pause; a later explicit barrier does not reuse an earlier failed attempt as its result. Shutdown rejects new mutations and attempts the newest admitted snapshot, including updates that arrived during an older in-flight write. A failed volume cannot create an endless shutdown retry loop.

Core policy mutations apply in memory before persistence. An I/O error is reported by the barrier; it does not roll back that in-memory user decision. Callers must distinguish accepted policy from durable storage rather than assuming an error restores an older policy. This preserves the existing core merge model without introducing another policy table or optimistic UI owner.

File effects

The native composition still supplies the existing resolved storage path and logical mesh/peers.bin file. The resolved path is pinned before its storage thread starts, so shutdown I/O does not depend on the lifetime of a global path-configuration object. Linux publication uses an exclusively created, descriptor-relative temporary file, synchronizes file contents, atomically renames it over the target and synchronizes the containing directory. It does not unlink the previous book before publication. Failures retain the previous target whenever publication has not occurred. A rename followed by failed directory synchronization reports uncertainty as failure and leaves the core dirty for retry.

Corrupt and truncated existing snapshots refuse loading and do not accept ordinary mutations. Missing storage is distinct from a valid loaded book; the core's canonical codec still validates record shape and CRC. This is not a new peer-file format or an automatic repair/migration policy.

Verification

The native regression blocks the actual persistence port while reading and admitting a newer observation, checks that the newer revision is eventually saved, verifies explicit barriers, retries a failed revision, preserves local flags/aliases on runtime updates and rejects visitor mutation. It also stops with an older snapshot blocked and confirms that the later accepted update is drained. Reopen and corrupt-blob retention are covered. Source/core units run with ASan, UBSan and leak checks on native Linux.

Reticulum ingress now uses this port from its protocol worker. The UI contact service reads the same protected memory owner through its existing contract; node events do not introduce a second directory or perform background writes against an unprotected UI-owned core.