mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-08-06 18:59:43 +00:00
docs(protocol): record runtime architecture conformance
This commit is contained in:
@@ -11,7 +11,9 @@ Primary root cause:
|
||||
|
||||
- ESP32 and nRF platform adapters historically owned too much protocol business logic.
|
||||
- The current protocol decisions covered by the runtime migration are delegated to shared runtime/policy helpers.
|
||||
- The remaining gaps are platform execution, storage, projection, and intentionally advertised capability differences.
|
||||
- Standard protocol use-case orchestration now enters through `MeshProtocolFacade` / `ProtocolRuntimeBundle`;
|
||||
remaining differences are platform execution, storage, projection, MeshCore-specific runtime extensions, and
|
||||
intentionally advertised capability differences.
|
||||
|
||||
| Area | Status | Risk | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
@@ -19,9 +21,9 @@ Primary root cause:
|
||||
| Meshtastic broadcast `want_response` | Shared policy in working tree | Medium | ESP32 and nRF now share the app-data destination/ACK/response decision; broadcast air ACK is suppressed while request response intent is preserved. |
|
||||
| Meshtastic request/reply core | Shared runtime/policy, platform IO remains | Medium | NodeInfo/Position reply gating, NodeInfo/Position payload construction, direct Position/Waypoint share packet decisions, TraceRoute/Position outgoing request packet decisions, TraceRoute reply gating, TraceRoute payload mutation, and TraceRoute/Position action lifecycle tracking are shared; radio send still lives in adapters/UI executors. |
|
||||
| Meshtastic duplicated policy ownership | Shared runtime/policy, platform IO remains | Medium | App-data send intent, NodeInfo reannounce gate, NodeInfo/Position reply gates, NodeInfo self-announcement packet construction, Position/Waypoint payload construction, direct Position/Waypoint share packet decisions, TraceRoute/Position outgoing request packet decisions, TraceRoute reply gate, TraceRoute payload mutation, TraceRoute/Position result lifecycle, and PKI/NO_CHANNEL resync decisions now live in shared runtime/policy. Radio IO and local data sources still live in adapters. |
|
||||
| MeshCore NodeInfo query/reply | Shared runtime/effects | Medium | ESP32 and nRF now route `requestNodeInfo()` through `MeshCoreRuntime` and shared control payload codecs; platform adapters still own packet IO/projection. |
|
||||
| MeshCore trace | Shared lifecycle, platform-limited routing | Medium | ESP32 and nRF use native `PAYLOAD_TYPE_TRACE` and shared completion/timeout policy; nRF still uses a minimal one-hop hash route. |
|
||||
| MeshCore app-data ACK/capability | Shared lifecycle | Medium | ESP32 and nRF now declare ACK tracking only when runtime pending/completion handling is wired. ACK frame scheduling remains adapter IO. |
|
||||
| MeshCore NodeInfo query/reply | Facade -> shared runtime/effects | Medium | ESP32 and nRF now route standard NodeInfo use-cases through `MeshProtocolFacade -> MeshCoreRuntime` and shared control payload codecs; platform adapters still own packet IO/projection. |
|
||||
| MeshCore trace | Facade -> shared lifecycle, platform-limited routing | Medium | ESP32 and nRF use native `PAYLOAD_TYPE_TRACE` and shared completion/timeout policy through the standard facade path; nRF still uses a minimal one-hop hash route. |
|
||||
| MeshCore app-data ACK/capability | Shared runtime extension | Medium | ESP32 and nRF now declare ACK tracking only when runtime pending/completion handling is wired. ACK registration/completion is still a MeshCoreRuntime extension; ACK frame scheduling remains adapter IO. |
|
||||
| MeshCore direct routing/identity | Runtime-owned policy, capability-split execution | Medium | ESP32 advertises direct route table, identity keys, peer secret derivation, and rich trace projection; nRF advertises identity keys and peer secret derivation only. Missing-key and auto-discover decisions now go through `MeshCoreRuntime` effects/state. |
|
||||
| MeshCore duplicated/incomplete ownership | Shared runtime/policy, platform IO remains | Medium | MeshCore NodeInfo, discover, trace lifecycle, ACK lifecycle, direct route policy, and direct secret expansion are shared; route/pubkey/private-key storage, frame IO, and platform projections remain in adapters. |
|
||||
| Capability granularity | Fine-grained flags added | Medium | Coarse legacy fields remain for compatibility; new flags describe NodeInfo, Position, TraceRoute, app response, and ACK tracking separately. |
|
||||
@@ -37,6 +39,9 @@ Target architecture:
|
||||
- Shared Meshtastic runtime core owns NodeInfo, Position, TraceRoute, ACK/request-response, and PKI resync policy.
|
||||
- Shared MeshCore runtime core owns NodeInfo control frames, discover decisions, trace, ACK tracking,
|
||||
route/identity policy, and app-data semantics.
|
||||
- `MeshProtocolFacade` plus `ProtocolRuntimeBundle` now provide the standard protocol use-case orchestration
|
||||
boundary. UI paths use capture-mode projection; platform adapters use execute-mode projection when they need to
|
||||
write `Publish*` / route effects into platform queues.
|
||||
- `PROTOCOL_RUNTIME_DESIGN_SPEC.md` now defines the required Strategy / Command / State / Bridge /
|
||||
Adapter architecture for this migration.
|
||||
- ESP32 and nRF adapters own physical IO, SDK lifecycle, platform storage, timers, buffers, and queues only.
|
||||
@@ -253,6 +258,10 @@ Current state:
|
||||
|
||||
- NodeInfo query/info decision mapping is shared by `MeshCoreRuntime`.
|
||||
- NodeInfo control payload layout is shared by `meshcore_payload_helpers`.
|
||||
- ESP32 and nRF standard `requestNodeInfo()` paths now enter through
|
||||
`MeshProtocolFacade -> ProtocolRuntimeBundle -> MeshCoreRuntime`.
|
||||
- Incoming NodeInfo control handling enters runtime through `handleIncomingPacket(...)`, which carries explicit
|
||||
`PacketHandling` semantics before effects are executed.
|
||||
- ESP32 and nRF differ only in how the resulting `SendNodeInfoEffect` is transmitted and projected.
|
||||
|
||||
Residual risk:
|
||||
@@ -277,6 +286,8 @@ Expected behavior:
|
||||
Current state:
|
||||
|
||||
- Trace base payload build/decode and lifecycle policy are shared.
|
||||
- Standard trace request / terminal incoming trace / tick lifecycle orchestration now enters through
|
||||
`MeshProtocolFacade` on ESP32 and nRF MeshCore adapters.
|
||||
- ESP32 still owns richer route scheduling and BLE `TraceData` projection.
|
||||
- nRF declares `supports_trace_route_request` for its minimal native MeshCore trace path, but not richer route
|
||||
projection.
|
||||
@@ -296,6 +307,8 @@ Expected behavior:
|
||||
Current state:
|
||||
|
||||
- ACK pending/completed/timeout lifecycle is shared.
|
||||
- ACK registration, binding, and incoming ACK completion remain explicit `MeshCoreRuntime` extension calls until the
|
||||
generic facade grows an ACK-signature use-case API. They are runtime state calls, not adapter-local state machines.
|
||||
|
||||
Residual risk:
|
||||
|
||||
@@ -323,6 +336,9 @@ Current state:
|
||||
- Incoming MeshCore discover request/response decisions now run through `MeshCoreRuntime`: request filter/since
|
||||
matching emits `SendDiscoverResponseEffect`, and responses emit `PublishNodeInfoEffect` plus
|
||||
`UpdatePeerRouteEffect`.
|
||||
- Standard incoming discover control execution now enters through `MeshProtocolFacade` with
|
||||
`ProtocolProjectionPolicy::ExecuteAppFacing`, so platform route/contact projections are executed without the
|
||||
adapter reinterpreting protocol semantics.
|
||||
- ESP32 receive-side missing-peer auto-discover now uses `MeshCoreRuntime` for the peer-hash validity and
|
||||
cooldown decision table; the adapter only executes the discover effect and reports TX success back to runtime.
|
||||
- MeshCore direct shared-secret expansion and nRF peer-key derivation now use `MeshCoreDirectSecretCore`;
|
||||
@@ -339,6 +355,8 @@ Residual risk:
|
||||
transmission remain platform-owned.
|
||||
- Direct text/app-data missing-key discover side effects now enter the same
|
||||
`DiscoverIntent -> MeshCoreRuntime -> SendDiscoverRequestEffect` path as user-initiated discovery.
|
||||
- ESP32 detailed discovery result mapping remains platform-owned because `MeshActionResult` exposes product-specific
|
||||
failure detail not represented by `MeshProtocolFacadeResult`.
|
||||
- nRF can derive identity/peer secrets for request payloads through the shared helper but does not implement the
|
||||
ESP32 direct route table.
|
||||
|
||||
@@ -365,8 +383,8 @@ Residual risk:
|
||||
2. Move MeshCore peer route storage / pubkey persistence state toward shared runtime ownership only if future
|
||||
behavior requires cross-platform route-table parity; today it is an advertised ESP32 capability difference.
|
||||
3. Keep ACK burst scheduling, concrete frame transmission, private identity persistence, BLE `TraceData`
|
||||
projection, and GPS/source selection as platform execution unless a future spec promotes one into shared
|
||||
protocol state.
|
||||
projection, detailed discovery result mapping, and GPS/source selection as platform execution unless a future
|
||||
spec promotes one into shared protocol state or facade API.
|
||||
|
||||
## Guardrail
|
||||
|
||||
|
||||
@@ -177,8 +177,15 @@ Facade 不得:
|
||||
- 变成新的 God Object 或 Mediator。
|
||||
|
||||
Facade 的职责是隔离上层与协议编排。上层不应该直接拼 `ProtocolIntent` 后调用 runtime,
|
||||
也不应该直接遍历 `ProtocolEffects` 后调用 executor。过渡期允许少量平台 adapter 仍然这样做,
|
||||
但每个 active UI / ChatService 入口必须有迁入 `MeshProtocolFacade` 的计划和测试。
|
||||
也不应该直接遍历 `ProtocolEffects` 后调用 executor。active UI / ChatService 入口必须迁入
|
||||
`MeshProtocolFacade` 或本规格明确命名的等价边界。
|
||||
|
||||
`MeshProtocolFacade` 默认捕获 `EmitActionResultEffect`、`PublishIncomingTextEffect`、
|
||||
`PublishIncomingDataEffect`、`PublishNodeInfoEffect` 等 app-facing projection,让 UI 可以从
|
||||
`MeshProtocolFacadeResult` 读取结果而不把 projection 当平台 IO 执行。平台 adapter 需要把这些
|
||||
projection 写入平台队列、路由表或 contact projection 时,必须显式选择
|
||||
`ProtocolProjectionPolicy::ExecuteAppFacing`,这样 projection 处理策略是组合配置,而不是散落的
|
||||
if 分支。
|
||||
|
||||
### Effect
|
||||
|
||||
@@ -227,12 +234,18 @@ facts provider 接起来。这里使用 Abstract Factory / Factory Method 的意
|
||||
```cpp
|
||||
struct ProtocolRuntimeBundle
|
||||
{
|
||||
MeshProtocolFacade* facade;
|
||||
MeshProtocol protocol;
|
||||
IProtocolRuntime* runtime;
|
||||
IProtocolEffectExecutor* executor;
|
||||
const IProtocolRuntimeContextProvider* contextProvider;
|
||||
|
||||
MeshProtocolFacade createFacade(ProtocolProjectionPolicy policy);
|
||||
};
|
||||
|
||||
ProtocolRuntimeBundle protocolRuntimeFor(MeshProtocol protocol);
|
||||
ProtocolRuntimeBundle protocolRuntimeFor(MeshProtocol protocol,
|
||||
const ProtocolRuntimeSelection& selection,
|
||||
IProtocolEffectExecutor& executor,
|
||||
const IProtocolRuntimeContextProvider& contextProvider);
|
||||
```
|
||||
|
||||
Factory 可以知道产品/平台能力,但不得决定协议语义。它选择“用哪套 runtime/executor”,不决定
|
||||
@@ -253,6 +266,10 @@ enum class PacketHandling
|
||||
};
|
||||
```
|
||||
|
||||
代码级边界是 `IProtocolRuntime::handleIncomingPacket(...) -> IncomingPacketHandlingResult`。
|
||||
旧的 `handleIncoming(...) -> ProtocolEffects` 可以保留为兼容入口,但 active facade path 必须调用
|
||||
`handleIncomingPacket(...)`,并且 shared tests 必须断言 `PacketHandling`。
|
||||
|
||||
Meshtastic incoming chain 的概念顺序必须是:
|
||||
|
||||
1. wire/Data 解码与 channel / PKI 解密事实建立;
|
||||
@@ -328,7 +345,7 @@ classDiagram
|
||||
class RecordingProtocolExecutor
|
||||
|
||||
class ProtocolRuntimeFactory {
|
||||
+protocolRuntimeFor(MeshProtocol protocol) ProtocolRuntimeBundle
|
||||
+protocolRuntimeFor(MeshProtocol protocol, selection, executor, contextProvider) ProtocolRuntimeBundle
|
||||
}
|
||||
|
||||
class MeshtasticCodec
|
||||
@@ -427,7 +444,7 @@ sequenceDiagram
|
||||
Platform->>Adapter: raw packet/frame
|
||||
Adapter->>Adapter: decode/decrypt enough to form IncomingPacket facts
|
||||
Adapter->>Facade: handleIncoming(IncomingPacket)
|
||||
Facade->>Runtime: handleIncoming(IncomingPacket)
|
||||
Facade->>Runtime: handleIncomingPacket(IncomingPacket)
|
||||
Runtime->>Chain: decrypt/classify/route handlers
|
||||
alt NodeInfo request
|
||||
Chain->>State: apply NodeInfo rule
|
||||
@@ -641,18 +658,43 @@ radio execution details. The question "is this local send still pending, complet
|
||||
分支维持。
|
||||
8. 如果规格中的核心类名只存在于 Mermaid 图中,而代码里没有真实对象或等价声明,则该项未完成。
|
||||
|
||||
## Current Implementation Gaps
|
||||
## Implementation Status
|
||||
|
||||
截至本规格日期,runtime / effect 主干已经部分落地,但以下缺口仍然阻止本规格被判定为完成:
|
||||
截至 2026-06-14,本规格中的核心 runtime architecture 已落成代码对象,并由 shared smoke /
|
||||
platform build 覆盖:
|
||||
|
||||
1. `MeshProtocolFacade` 还没有真实代码对象。当前若干 active UI / platform path 仍直接构造
|
||||
`ProtocolIntent`、调用 `IProtocolRuntime`、遍历 `ProtocolEffects` 或手动处理 TX failure 回灌。
|
||||
2. Product composition 还没有统一的 factory / bundle 边界。平台代码各自持有 runtime / executor,
|
||||
组合逻辑仍可能继续散落。
|
||||
3. Incoming handler chain 尚未以 `PacketHandling` 或等价返回语义显式化。部分平台 adapter 仍保留
|
||||
巨型 decode/classify 分支,虽然其中若干协议决策已经下沉到 runtime/policy。
|
||||
4. `RecordingProtocolExecutor` 已覆盖 effect 可记录性,但还缺少 `MeshProtocolFacade` 级别的 smoke,
|
||||
用来证明 UI / ChatService 可以只通过 facade 发起 action 并观察 app-facing result。
|
||||
1. `IProtocolRuntime`、`MeshtasticRuntime`、`MeshCoreRuntime` 是真实代码对象;
|
||||
`trailmate_meshtastic_runtime_smoke` 和 `trailmate_meshcore_runtime_smoke` 覆盖 outgoing /
|
||||
incoming / tx result / tick。
|
||||
2. `MeshProtocolFacade` 是真实代码对象;`trailmate_mesh_protocol_facade_smoke` 覆盖 send text、
|
||||
trace、NodeInfo、position、incoming、tx result、tick,以及 UI capture / platform execute 两种
|
||||
projection policy。
|
||||
3. `ProtocolRuntimeBundle`、`ProtocolRuntimeSelection`、`protocolRuntimeFor(...)` 是真实 product
|
||||
composition 边界;`trailmate_protocol_runtime_factory_smoke` 覆盖 protocol selection、
|
||||
invalid protocol、context provider 更新和 platform-style projection execution。
|
||||
4. nRF mono UI、Linux uConsole 的 active protocol use-case path 已经通过 facade / factory 进入
|
||||
runtime;ESP32 与 nRF MeshCore adapter 的标准 NodeInfo、discover、incoming、tx result、tick path
|
||||
也通过 facade / factory 进入 runtime。
|
||||
5. Incoming handler chain 已以 `PacketHandling` / `IncomingPacketHandlingResult` 显式化;
|
||||
`MeshtasticRuntime` 和 `MeshCoreRuntime` 都由 `handleIncomingPacket(...)` 组织 handler 顺序,
|
||||
shared tests 直接断言 `HandledStop` / `NotHandled`。
|
||||
6. `MeshAdapterProtocolEffectExecutor` 和 platform adapters 只执行 `ProtocolEffect`。执行层可以选择
|
||||
projection policy,但不得重新决定协议语义。
|
||||
|
||||
### Accepted Runtime Extensions
|
||||
|
||||
以下保留项不是 legacy adapter 逻辑,而是目前尚未纳入通用 facade API 的 MeshCore runtime extension:
|
||||
|
||||
- MeshCore app ACK registration / binding / incoming ACK completion 仍通过
|
||||
`MeshCoreRuntime::trackAppAck(...)`、`bindAppAckToMessage(...)`、`handleAppAck(...)` 表达。ACK burst
|
||||
frame scheduling 和 multi-ACK frame construction 仍是 adapter IO。
|
||||
- ESP32 receive-side missing-peer auto-discover 的 cooldown state 仍通过
|
||||
`prepareAutoDiscoverMissingPeer(...)`、`markAutoDiscoverMissingPeerTxResult(...)`、
|
||||
`resetAutoDiscoverState()` 表达。协议决策在 runtime,route cache 和 radio scheduling 仍在 adapter。
|
||||
- ESP32 detailed discovery result (`MeshActionResult`) 仍使用 runtime effects 后由 adapter 映射成
|
||||
platform-specific detailed result;通用 `MeshProtocolFacadeResult` 目前不承诺替代该产品级结果类型。
|
||||
|
||||
这些 extension 可以在未来提升为 facade use-case API,但在提升前不得在 adapter 中复制协议决策表。
|
||||
|
||||
## Migration Rules
|
||||
|
||||
|
||||
Reference in New Issue
Block a user