Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jamesarich <2199651+jamesarich@users.noreply.github.com> Co-authored-by: James Rich <james.a.rich@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
20 KiB
Tasks: TAK v2 Protocol Integration
Input: Design documents from /specs/005-tak-v2-protocol/
Prerequisites: plan.md ✅, spec.md ✅, research.md ✅, data-model.md ✅, contracts/ ✅
Status: Retroactive — documents work completed in PR #5434 (99 files, +4698 lines). Use as verification checklist.
Tests: Included — the implementation ships with 12 test classes and 89+ test methods covering all CoT types.
Verification: Constitution-required validation tasks included (spotlessCheck, detekt, compile, allTests).
Format: [ID] [P?] [Story] Description
- [P]: Can run in parallel (different files, no dependencies)
- [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
Phase 1: Setup (Module & Dependencies)
Purpose: Create the core:takserver KMP module, configure dependencies, and establish project structure.
- T001 Create
core/takserver/build.gradle.ktswith TAKPacket-SDK v0.1.3, xmlutil, zstd-jni 1.5.7-7, Ktor Network, Okio, Koin, and Kermit dependencies - T002 Register
:core:takservermodule insettings.gradle.kts - T003 [P] Create source set directory structure:
commonMain,commonTest,jvmAndroidMain,androidMain,jvmMain,iosMainundercore/takserver/src/ - T004 [P] Add bundled mTLS certificates to
core/takserver/src/jvmAndroidMain/resources/tak_certs/ - T005 [P] Add 40 CoT XML test fixture files to
core/takserver/src/jvmAndroidMain/resources/tak_test_fixtures/ - T006 [P] Create Koin DI module in
core/takserver/src/commonMain/kotlin/org/meshtastic/core/takserver/di/CoreTakServerModule.kt
Phase 2: Foundational (Shared Models, Constants & Utilities)
Purpose: Core domain models, constants, and utilities that ALL user stories depend on.
⚠️ CRITICAL: No user story work can begin until this phase is complete.
- T007 Define domain models (CoTMessage, CoTContact, CoTGroup, CoTStatus, CoTTrack, CoTChat, TAKClientInfo, InboundCoTMessage) in
core/takserver/src/commonMain/kotlin/.../TAKModels.kt - T008 [P] Define constants (DEFAULT_TAK_PORT, MAX_TAK_WIRE_PAYLOAD_BYTES, MAX_DECOMPRESSED_SIZE, TAK_COORDINATE_SCALE, DICT_IDs, OFFLINE_QUEUE_TTL, KEEPALIVE_INTERVAL, MIN_MESH_STALE_TTL) in
core/takserver/src/commonMain/kotlin/.../TAKDefaults.kt - T009 [P] Implement XML escaping utilities (5 special characters: &, <, >, ", ') in
core/takserver/src/commonMain/kotlin/.../XmlUtils.kt - T010 [P] Implement CoT XML data classes for serialization in
core/takserver/src/commonMain/kotlin/.../CoTXmlDataClasses.kt - T011 [P] Implement ATAK preference XML schema classes in
core/takserver/src/commonMain/kotlin/.../TAKPrefXmlDataClasses.kt - T012 [P] Implement shared coordinate scaling and conversion helpers in
core/takserver/src/commonMain/kotlin/.../TakConversionHelpers.kt - T013 [P] Implement
TakV2TypeMapperwith 23 CoT types + 4 HOW types + CotType_Other fallback incore/takserver/src/commonMain/kotlin/.../TakV2TypeMapper.kt - T014 [P] Implement
CoTDetailStripperto strip 16 bloat XML elements (regex-based) incore/takserver/src/commonMain/kotlin/.../CoTDetailStripper.kt - T015 [P] Implement streaming
CoTXmlParser(XML → CoTMessage) incore/takserver/src/commonMain/kotlin/.../CoTXmlParser.kt - T016 [P] Implement
CoTXml(CoTMessage → XML serialization) incore/takserver/src/commonMain/kotlin/.../CoTXml.kt - T017 [P] Implement TCP stream framing in
core/takserver/src/commonMain/kotlin/.../CoTXmlFrameBuffer.kt - T018 [P] Implement shared conversion helpers in
core/takserver/src/commonMain/kotlin/.../CoTConversion.kt - T019 [P] Add
supportsTakV2capability flag (firmware >= 2.8.0 check) incore/model/src/commonMain/kotlin/.../Capabilities.kt - T020 [P] Define
AtakFileWriterexpect interface incore/takserver/src/commonMain/kotlin/.../AtakFileWriter.kt - T021 [P] Define
ZipArchiverexpect interface incore/takserver/src/commonMain/kotlin/.../ZipArchiver.kt - T022 [P] Define
TakFixtureLoaderexpect interface incore/takserver/src/commonMain/kotlin/.../TakFixtureLoader.kt - T023 [P] Define
TakV2Compressorexpect interface incore/takserver/src/commonMain/kotlin/.../TakV2Compressor.kt - T024 [P] Define
TAKServerexpect interface incore/takserver/src/commonMain/kotlin/.../TAKServer.kt
Checkpoint: Foundation ready — all shared types, constants, and interfaces established.
Phase 3: User Story 1 — Send Rich Tactical Data Over Mesh (Priority: P1) 🎯 MVP
Goal: Convert all CoT types from ATAK clients into compressed TAKPacketV2 and transmit over port 78. Receiving nodes decompress and forward to connected TAK clients.
Independent Test: Drop a hostile marker on one ATAK instance → appears on remote ATAK with correct type, icon, and position.
Tests for User Story 1
- T025 [P] [US1] Implement
CoTXmlParserTest(XML parsing for all 23 CoT types) incore/takserver/src/commonTest/kotlin/.../CoTXmlParserTest.kt - T026 [P] [US1] Implement
CoTXmlTest(CoTMessage → XML round-trip) incore/takserver/src/commonTest/kotlin/.../CoTXmlTest.kt - T027 [P] [US1] Implement
CoTConversionTest(conversion helper correctness) incore/takserver/src/commonTest/kotlin/.../CoTConversionTest.kt - T028 [P] [US1] Implement
CoTDetailStripperTest(16-element stripping) incore/takserver/src/commonTest/kotlin/.../CoTDetailStripperTest.kt - T029 [P] [US1] Implement
TAKPacketV2RawDetailTest(raw_detail round-trip for shapes/markers/routes) incore/takserver/src/commonTest/kotlin/.../TAKPacketV2RawDetailTest.kt - T030 [P] [US1] Implement
XmlUtilsTest(escaping correctness for 5 special chars) incore/takserver/src/commonTest/kotlin/.../XmlUtilsTest.kt - T031 [P] [US1] Implement
TAKDefaultsTest(constants validation) incore/takserver/src/commonTest/kotlin/.../TAKDefaultsTest.kt
Implementation for User Story 1
- T032 [US1] Implement
TAKPacketV2Conversion(CoTMessage ↔ TAKPacketV2 for all CoT types including pli, chat, raw_detail payloads) incore/takserver/src/commonMain/kotlin/.../TAKPacketV2Conversion.kt - T033 [P] [US1] Implement
TakV2Compressoractual (zstd dictionary compression via TAKPacket-SDK) incore/takserver/src/jvmAndroidMain/kotlin/.../TakV2Compressor.kt - T034 [P] [US1] Implement
TakV2CompressoriOS stub (uncompressed, flags=0xFF) incore/takserver/src/iosMain/kotlin/.../TakV2Compressor.kt - T035 [US1] Implement
RouteDataPackageGenerator(Route CoT → KML data package with MissionPackageManifest v2) incore/takserver/src/commonMain/kotlin/.../RouteDataPackageGenerator.kt - T036 [US1] Implement
TAKMeshIntegrationoutbound path (TAK client → CoT parse → detail strip → compress → MTU check → port 78 send) incore/takserver/src/commonMain/kotlin/.../TAKMeshIntegration.kt - T037 [US1] Implement
TAKMeshIntegrationinbound path (port 78 receive → decompress → decode → broadcast to TAK clients) incore/takserver/src/commonMain/kotlin/.../TAKMeshIntegration.kt - T038 [P] [US1] Implement
TakFixtureLoaderactual (JVM resource loading for test fixtures) incore/takserver/src/jvmAndroidMain/kotlin/.../TakFixtureLoader.kt - T039 [P] [US1] Implement
TakFixtureLoaderiOS stub incore/takserver/src/iosMain/kotlin/.../TakFixtureLoader.kt - T040 [P] [US1] Implement
ZipArchiveractual (java.util.zip) incore/takserver/src/jvmAndroidMain/kotlin/.../ZipArchiver.kt - T041 [P] [US1] Implement
ZipArchiveriOS stub incore/takserver/src/iosMain/kotlin/.../ZipArchiver.kt - T042 [P] [US1] Implement
AtakFileWriteractual (SAF/private directory) incore/takserver/src/androidMain/kotlin/.../AtakFileWriter.kt - T043 [P] [US1] Implement
AtakFileWriteractual (desktop filesystem) incore/takserver/src/jvmMain/kotlin/.../AtakFileWriter.kt - T044 [P] [US1] Implement
AtakFileWriteriOS stub incore/takserver/src/iosMain/kotlin/.../AtakFileWriter.kt - T045 [US1] Implement
TakMeshTestRunner(in-app diagnostic runner for per-CoT-type byte size and round-trip verification) incore/takserver/src/commonMain/kotlin/.../TakMeshTestRunner.kt
Checkpoint: All 28 CoT type mappings encode/decode correctly. Compressed PLI < 100 bytes. Shapes/markers/routes fit within 225-byte MTU after stripping + compression.
Phase 4: User Story 2 — Legacy Fallback for Mixed Firmware (Priority: P1)
Goal: Auto-detect firmware version and use TAKPacket v1 (port 72) for radios < 2.8.0. Drop unsupported CoT types on legacy with a warning. Always accept inbound on both ports.
Independent Test: Connect a node with firmware 2.7.x and verify PLI/GeoChat work on port 72 while markers are dropped with warning.
Tests for User Story 2
- T046 [P] [US2] Implement
TAKPacketConversionTest(v1 PLI + GeoChat encode/decode) incore/takserver/src/commonTest/kotlin/.../TAKPacketConversionTest.kt
Implementation for User Story 2
- T047 [US2] Implement
TAKPacketConversion(CoTMessage ↔ TAKPacket v1 for PLI and GeoChat only) incore/takserver/src/commonMain/kotlin/.../TAKPacketConversion.kt - T048 [US2] Implement version-gating logic in
TAKMeshIntegration— checkCapabilities.supportsTakV2per-send to select port 72 vs port 78 path incore/takserver/src/commonMain/kotlin/.../TAKMeshIntegration.kt - T049 [US2] Implement dual-port inbound listener in
TAKMeshIntegration— accept and decode packets from both port 72 and port 78 regardless of local firmware incore/takserver/src/commonMain/kotlin/.../TAKMeshIntegration.kt - T050 [US2] Implement CoT type filtering for legacy path — drop non-PLI/non-GeoChat types with logged warning on firmware < 2.8.0 in
core/takserver/src/commonMain/kotlin/.../TAKMeshIntegration.kt
Checkpoint: Mixed-firmware mesh maintains PLI/GeoChat for legacy nodes. Advanced CoT types dropped cleanly with user-visible warning.
Phase 5: User Story 3 — TAK Server Lifecycle and Reliability (Priority: P2)
Goal: Run a reliable local TLS/mTLS server on port 8089, maintain ATAK/iTAK connections through screen-off and Doze mode, support data package export.
Independent Test: Enable TAK server, connect ATAK via exported data package, verify connection persists for 10+ minutes with screen off.
Tests for User Story 3
- T051 [P] [US3] Implement
CoTXmlFrameBufferTest(TCP stream framing correctness) incore/takserver/src/commonTest/kotlin/.../CoTXmlFrameBufferTest.kt
Implementation for User Story 3
- T052 [US3] Implement
TAKServerJvmactual (JSSE SSLServerSocket with mTLS on port 8089) incore/takserver/src/jvmAndroidMain/kotlin/.../TAKServerJvm.kt - T053 [P] [US3] Implement
TAKServerIosactual (no-op stub) incore/takserver/src/iosMain/kotlin/.../TAKServerIos.kt - T054 [US3] Implement
TAKClientConnection(per-client coroutine scope, SupervisorJob, BufferedOutputStream + writeMutex, XML stream framing) incore/takserver/src/jvmAndroidMain/kotlin/.../TAKClientConnection.kt - T055 [US3] Implement
TakCertLoader(load bundled .p12/.pem certificates for mTLS) incore/takserver/src/jvmAndroidMain/kotlin/.../TakCertLoader.kt - T056 [US3] Implement
TAKServerManagerlifecycle (start/stop, client list, broadcast, 10-second keepalive interval, offline message queue: 50-msg cap, 5-min TTL) incore/takserver/src/commonMain/kotlin/.../TAKServerManager.kt - T057 [US3] Implement
TAKDataPackageGenerator(export .zip with server certificates and connection config for ATAK/iTAK import) incore/takserver/src/commonMain/kotlin/.../TAKDataPackageGenerator.kt - T058 [US3] Add
PARTIAL_WAKE_LOCKacquisition inMeshServicewhen TAK server is active incore/service/src/androidMain/kotlin/.../MeshService.kt - T059 [US3] Wire
TAKMeshIntegration.start(scope)call fromMeshServiceOrchestratorincore/service/src/commonMain/kotlin/.../MeshServiceOrchestrator.kt
Checkpoint: TAK server starts on port 8089, accepts mTLS connections, maintains keepalive, survives screen-off. Data package exportable.
Phase 6: User Story 4 — TAK Configuration UI (Priority: P2)
Goal: Compose Multiplatform settings UI for TAK module — server toggle, team/role selection, data package export, diagnostic test runner.
Independent Test: Navigate to TAK config, toggle server, change team/role, verify settings persist across app restart.
Implementation for User Story 4
- T060 [US4] Implement
TAKConfigItemListCompose UI (SwitchPreference for server toggle, DropDownPreference for team/role, TitledCard for status, export button, test runner button) infeature/settings/src/commonMain/kotlin/.../radio/component/TAKConfigItemList.kt - T061 [P] [US4] Implement
TakPermissionUtilexpect interface infeature/settings/src/commonMain/kotlin/.../tak/TakPermissionUtil.kt - T062 [P] [US4] Implement
TakPermissionUtilAndroid actual (ACCESS_LOCAL_NETWORK for API 37+) infeature/settings/src/androidMain/kotlin/.../tak/TakPermissionUtil.kt - T063 [P] [US4] Implement
TakPermissionUtilJVM actual (no-op) infeature/settings/src/jvmMain/kotlin/.../tak/TakPermissionUtil.kt - T064 [P] [US4] Implement
TakPermissionUtiliOS actual (no-op) infeature/settings/src/iosMain/kotlin/.../tak/TakPermissionUtil.kt
Checkpoint: TAK config screen functional — server toggle works, team/role persists, test runner shows per-CoT-type byte sizes.
Phase 7: User Story 5 — Inbound Dual-Path Tolerance (Priority: P3)
Goal: V2-capable nodes decode and forward ALL inbound mesh traffic (both port 72 and port 78) to connected TAK clients.
Independent Test: Send a legacy TAKPacket (port 72) to a firmware 2.8.0+ node → connected ATAK client receives the PLI as valid CoT XML.
Implementation for User Story 5
- T065 [US5] Verify inbound handler in
TAKMeshIntegrationcorrectly decodes port 72 legacy packets and broadcasts to TAK clients (implemented as part of T049, verify independently) - T066 [US5] Verify inbound handler in
TAKMeshIntegrationcorrectly decompresses port 78 packets (including 0xFF uncompressed from TAK_TRACKER) and broadcasts to TAK clients
Checkpoint: No tactical data lost in mixed deployments. Both v1 and v2 inbound traffic decoded and forwarded correctly.
Phase 8: Polish & Cross-Cutting Concerns
Purpose: Verification, compliance, and documentation tasks that span all user stories.
- T067 [P] Add TAK-related string resources to
core/resources/src/commonMain/composeResources/values/strings.xml - T068 [P] Review
TAKConfigItemList.ktagainst Meshtastic design standards — verify M3 components, accessibility (TalkBack), touch targets - T069 [P] Confirm no logs, telemetry, or config changes expose PII, location data, secrets, or modify
core/protosubmodule - T070 [P] Run constitution-required verification:
./gradlew spotlessApply spotlessCheck detekt assembleDebug :core:takserver:allTests :feature:settings:allTests - T071 [P] Verify all 12 test classes pass (89+ methods):
./gradlew :core:takserver:allTests - T072 [P] Validate quickstart.md instructions produce successful build from clean checkout
- T073 Run
gh pr checks 5434to confirm CI passes all checks - T074 [P] [US3] Add test for offline message queue: verify FIFO eviction at 50-message cap, per-message TTL expiry after 5 minutes, and replay of queued messages on client reconnect
- T075 [P] [US4] Add test for ACCESS_LOCAL_NETWORK permission denied on Android 17+: verify TAK server displays user-visible error and does not crash
- T076 [P] [US3] Add test for TAKServerJvm port-conflict error: verify graceful failure with user-visible error when port 8089 is already in use
- T077 [P] [US1] Add test for MAX_DECOMPRESSED_SIZE boundary: verify
TakV2Compressorrejects payloads exceeding the decompression size limit - T078 [P] [US1] Create
TAKMeshIntegrationTest.ktincore/takserver/src/commonTest/with lifecycle, inbound mesh, firmware gating, and GeoChat enrichment tests (10 tests) - T079 [P] [US3] Add
broadcastRawXmltests toTAKServerManagerTest.kt: verify forward-to-TAKServer when running and no-op when not running (2 tests) - T080 [P] Restrict
TAKServerManagerImplvisibility tointernalinTAKServerManager.kt— consumers use theTAKServerManagerinterface via Koin
Dependencies & Execution Order
Phase Dependencies
- Setup (Phase 1): No dependencies — can start immediately
- Foundational (Phase 2): Depends on Phase 1 — BLOCKS all user stories
- User Story 1 (Phase 3): Depends on Phase 2 — the MVP
- User Story 2 (Phase 4): Depends on Phase 2 + shares
TAKMeshIntegrationwith US1 - User Story 3 (Phase 5): Depends on Phase 2 — independent of US1/US2
- User Story 4 (Phase 6): Depends on Phase 5 (needs TAKServerManager for toggle state)
- User Story 5 (Phase 7): Depends on Phase 3 + Phase 4 (verification of dual-path handling)
- Polish (Phase 8): Depends on all user stories being complete
User Story Dependencies
- US1 (P1): After Phase 2 — no dependencies on other stories
- US2 (P1): After Phase 2 — shares
TAKMeshIntegration.ktwith US1 (co-implemented) - US3 (P2): After Phase 2 — independent (server infrastructure)
- US4 (P2): After US3 (needs server lifecycle for toggle state)
- US5 (P3): After US1 + US2 (verification of combined behavior)
Within Each User Story
- Tests written alongside implementation (retroactive — both exist in PR)
- Models/interfaces → actual implementations → integration → verification
- Platform actuals can be implemented in parallel (jvmAndroidMain, androidMain, jvmMain, iosMain)
Parallel Opportunities
- All Phase 1 tasks T003-T006 can run in parallel
- All Phase 2 tasks T008-T024 can run in parallel (independent files)
- All US1 test tasks T025-T031 can run in parallel
- Platform actuals within US1 (T033/T034, T040/T041, T042/T043/T044) can run in parallel
- US3 server tasks T052/T053 can run in parallel (JVM vs iOS)
- All US4 permission actuals T062/T063/T064 can run in parallel
Parallel Example: User Story 1
# Launch all tests for US1 together:
Task: "CoTXmlParserTest in commonTest"
Task: "CoTXmlTest in commonTest"
Task: "CoTConversionTest in commonTest"
Task: "CoTDetailStripperTest in commonTest"
Task: "TAKPacketV2RawDetailTest in commonTest"
Task: "XmlUtilsTest in commonTest"
Task: "TAKDefaultsTest in commonTest"
# Launch all platform actuals together:
Task: "TakV2Compressor jvmAndroidMain actual"
Task: "TakV2Compressor iosMain stub"
Task: "ZipArchiver jvmAndroidMain actual"
Task: "ZipArchiver iosMain stub"
Task: "AtakFileWriter androidMain actual"
Task: "AtakFileWriter jvmMain actual"
Task: "AtakFileWriter iosMain stub"
Implementation Strategy
MVP First (User Stories 1 + 2)
- Complete Phase 1: Module setup + dependencies
- Complete Phase 2: Shared models, constants, utilities
- Complete Phase 3: US1 — Rich tactical data over mesh (v2 path)
- Complete Phase 4: US2 — Legacy fallback (v1 path)
- STOP and VALIDATE: Run all tests, verify PLI/marker round-trip on actual hardware
Incremental Delivery
- Setup + Foundational → Module compilable
- US1 + US2 → Full bidirectional mesh ↔ TAK bridge (MVP!)
- US3 → Reliable TAK server lifecycle
- US4 → User configuration UI
- US5 → Dual-path tolerance verification
- Polish → CI green, design compliance confirmed
Retroactive Verification (PR #5434)
Since this implementation already exists, use this task list as:
- Verification checklist — confirm each task's output exists in the PR diff
- Code review guide — trace requirements → implementation → tests
- Regression detection — if future changes break a task's output, identify which user story is affected
Notes
- [P] tasks = different files, no dependencies between them
- [Story] label maps task to specific user story for traceability
- This is a retroactive task list — PR #5434 implements all tasks
- Verification:
./gradlew spotlessApply spotlessCheck detekt assembleDebug :core:takserver:allTests :feature:settings:allTests - Total implementation: 99 files changed, +4698 lines, 1 new KMP module (
core:takserver)