Skip to content

asg_client: remove vendor (K900/BES) imports from core-bound files ahead of A6 module split#3140

Open
nic-olo wants to merge 47 commits into
devfrom
cursor/pre-a6-vendor-decoupling-90cb
Open

asg_client: remove vendor (K900/BES) imports from core-bound files ahead of A6 module split#3140
nic-olo wants to merge 47 commits into
devfrom
cursor/pre-a6-vendor-decoupling-90cb

Conversation

@nic-olo

@nic-olo nic-olo commented Jun 12, 2026

Copy link
Copy Markdown
Member

Scope

Pre-A6 cleanup for asg_client: removes all K900/BES vendor imports from the files that will live in :asg-core after the A6 module split, so A6 becomes a mechanical directory move. No behavior changes intended.

Fix 1 — Core LED constants

  • New io/hardware/interfaces/RgbLedConstants (LED indexes 0-4, default brightness 100).
  • RgbLedCommandHandler, MediaCaptureService, AsgClientService no longer import K900RgbLedController.

Fix 2 — Transport-level hooks on IBluetoothManager

  • Four new default no-op methods: onMtuNegotiated, onTransportReset, onFileTransferConfirmation, onFileTransferAck. K900BluetoothManager overrides them, delegating to BesWireFormat / its existing file-transfer handlers.
  • BleConfigCommandHandler, PhoneReadyCommandHandler, TransferCompleteCommandHandler, FileTransferAckEventSubscriber now call the interface — the (K900BluetoothManager) casts and BesWireFormat static calls are gone. BleConfigCommandHandler takes AsgClientServiceManager like its sibling handlers.

Fix 3 — K900ProtocolStrategy injected, not hardcoded

  • CommandProtocolDetector ships only base strategies (JSON, Unknown, plus chunked support).
  • The vendor strategy is contributed via Hilt @IntoSet (new TransportModule), injected into AsgClientService, and registered through ServiceInitializerCommandProcessor before chunked support is added. Strategy order changes from (Chunked, Json, K900, Unknown) to (Chunked, K900, Json, Unknown) — behavior-equivalent because K900 only claims invalid-JSON C payloads, which Json/Chunked never claim (pinned by tests).

Fix 4 — IBesOtaController / IBesOtaRegistry interfaces

  • New core interfaces in io/ota/interfaces/; BesOtaManager / BesOtaRegistry implement them.
  • The three static version methods on BesOtaManager (getCurrentFirmwareVersion, parseServerVersionCode, isNewerVersion) became instance methods (Java forbids same-signature instance+static; their only external caller was OtaHelper). The static isBesOtaInProgress flag remains for internal use; the interface exposes an instance accessor.
  • OtaHelper, BesOtaAuthEventSubscriber, K900CommandHandler, DebugBesOtaReceiver, AsgClientServiceManager.getBesOtaManager(), OtaModule, AsgClientEntryPoint, AsgClientService, ServiceInitializer all consume the interfaces. OtaHelper BES-progress checks are now null-safe registry lookups (null controller = non-K900 = not in progress).

Fix 5 — Factory calls removed from ServiceInitializer

  • ServiceInitializer now receives ICompanionTransport / INetworkManager via constructor; AsgClientService injects them from the new TransportModule.
  • Providers are intentionally unscoped: AsgClientServiceManager.cleanup() shuts the transport down on service destroy, so a singleton would re-inject a dead instance on service restart. Unscoped matches the previous fresh-instance-per-service-creation factory behavior (pinned by tests).

Acceptance check

Zero vendor imports in the scoped core dirs (run from asg_client/):

rg "^import.*\.(K900|mentralive\.|BesWire|BesMessage|BesOtaManager|BesOtaRegistry|SerialPortBridge|BluetoothManagerFactory|NetworkManagerFactory)" \
  app/src/main/java/com/mentra/asg_client/service/core/ \
  app/src/main/java/com/mentra/asg_client/io/ota/helpers/ \
  app/src/main/java/com/mentra/asg_client/io/media/core/ \
| grep -v "service\.core\.handlers\.K900CommandHandler"

Returns zero results. Sole documented exclusion: CommandProcessorK900CommandHandler (intra-service.core import today; decoupling it is its own pre-A6 task, like OtaHelper splitting is B3). Known remaining boundary debt, intentionally untouched: AsgClientServicecom.dev.api.DevApi, all of service/legacy/.

Tests

  • ./gradlew :app:testDebugUnitTest: 357 tests, 0 failures, 0 errors (1 pre-existing skip in MediaUploadTest).
  • ./gradlew :app:assembleDebug: BUILD SUCCESSFUL — also validates the Hilt graph (interface bindings + @IntoSet multibinding).

New coverage (15 new test classes + 1 updated):

  • Unit: RgbLedConstantsTest (core/vendor parity pin), RgbLedCommandHandlerTest, IBluetoothManagerDefaultsTest, BleConfigCommandHandlerTest, PhoneReadyCommandHandlerTest, TransferCompleteCommandHandlerTest (regression guard for the old ClassCastException-prone cast, using a plain transport mock), FileTransferAckEventSubscriberTest, CommandProtocolDetectorTest (UNKNOWN without vendor strategy / K900 after runtime registration / chunked ordering), BesOtaRegistryTest, BesOtaManagerVersionTest, OtaHelperBesGuardTest (null-controller NPE guards + in-progress consultation), OtaModuleTest, TransportModuleTest (device selection + fresh-instance-per-call lifecycle pin).
  • Integration (JVM, real collaborators): CommandProcessorRoutingIntegrationTest — raw bytes through real CommandProcessor/CommandParser/detector/K900CommandHandler/McuEventParser to the peripheral bus and transport interface, with and without the injected vendor strategy; BesOtaAuthRoutingIntegrationTest — real SimplePeripheralBus + real subscribers to IBesOtaController/ICompanionTransport.
  • BesOtaAuthEventSubscriberTest updated to mock IBesOtaController instead of the concrete vendor class.
  • K900BluetoothManager's hook overrides are one-line delegations into BesWireFormat statics whose transitions are already covered by BesWireFormatTest; a construction-based test was skipped because the constructor starts a SerialPortBridge UART thread (device-bound).

Out of scope (per plan)

Splitting OtaHelper (B3); decoupling CommandProcessor from K900CommandHandler; moving files (A6); AsgClientServiceManager beyond the registry/getter type changes; BES OTA protocol logic; Kotlin migration.

Open in Web Open in Cursor 

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

📋 PR Review Helper

📱 Mobile App Build

Waiting for build...

🕶️ ASG Client Build

Ready to test! (commit c667deb)

📥 Download ASG APK


🔀 Test Locally

gh pr checkout 3140

@nic-olo

nic-olo commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: b2c1f9522c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@nic-olo nic-olo marked this pull request as ready for review June 12, 2026 07:52
@nic-olo nic-olo requested a review from a team as a code owner June 12, 2026 07:52
@cursor cursor Bot requested a review from aisraelov as a code owner June 23, 2026 04:30
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 23, 2026

Copy link
Copy Markdown

Deploying mentra-live-ota-site with  Cloudflare Pages  Cloudflare Pages

Latest commit: b9e093f
Status: ✅  Deploy successful!
Preview URL: https://e268e241.mentra-live-ota-site.pages.dev
Branch Preview URL: https://cursor-pre-a6-vendor-decoupl.mentra-live-ota-site.pages.dev

View logs

@nic-olo nic-olo enabled auto-merge (squash) June 23, 2026 04:30
@nic-olo nic-olo disabled auto-merge June 23, 2026 04:30
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 23, 2026

Copy link
Copy Markdown

Deploying mentra-store-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: b9e093f
Status: ✅  Deploy successful!
Preview URL: https://fb55e187.augmentos-appstore-2.pages.dev
Branch Preview URL: https://cursor-pre-a6-vendor-decoupl.augmentos-appstore-2.pages.dev

View logs

nic-olo added 17 commits June 23, 2026 04:33
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 23, 2026

Copy link
Copy Markdown

Deploying dev-augmentos-console with  Cloudflare Pages  Cloudflare Pages

Latest commit: b9e093f
Status: ✅  Deploy successful!
Preview URL: https://0a1f8d02.dev-augmentos-console.pages.dev
Branch Preview URL: https://cursor-pre-a6-vendor-decoupl.dev-augmentos-console.pages.dev

View logs

@github-actions

Copy link
Copy Markdown

bugbot run

4 similar comments
@github-actions

Copy link
Copy Markdown

bugbot run

@github-actions

Copy link
Copy Markdown

bugbot run

@github-actions

Copy link
Copy Markdown

bugbot run

@github-actions

Copy link
Copy Markdown

bugbot run

@nic-olo

nic-olo commented Jun 23, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ce6e512bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +81 to +84
@Inject ICompanionTransport companionTransport;

/** Device-appropriate network manager, constructed by the vendor wiring layer. */
@Inject INetworkManager injectedNetworkManager;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Defer transport construction until foreground start

These Hilt field injections are resolved before this service's onCreate() body reaches ensureForegroundStarted(). On K900, provideCompanionTransport() constructs K900BluetoothManager, whose constructor opens /dev/ttyS1 and starts the serial receive thread, and the injected network manager can also do device setup; previously those factories ran inside initializeServiceInitializer() after foreground promotion. When serial/network setup is slow during a startForegroundService launch, this moves heavy work back in front of startForeground() and can trip the foreground-service startup deadline; inject a Provider/factory and call it after ensureForegroundStarted() instead.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown

bugbot run

cursoragent and others added 5 commits June 23, 2026 05:16
…rom OtaHelper

Co-authored-by: Nicolo Micheletti <michelettinik@gmail.com>
Co-authored-by: Nicolo Micheletti <michelettinik@gmail.com>
…er until after ensureForegroundStarted

Co-authored-by: Nicolo Micheletti <michelettinik@gmail.com>
Co-authored-by: Nicolo Micheletti <michelettinik@gmail.com>
Co-authored-by: Nicolo Micheletti <michelettinik@gmail.com>
@cursor cursor Bot force-pushed the cursor/pre-a6-vendor-decoupling-90cb branch from 1ac9b09 to b9e093f Compare June 23, 2026 05:17
@github-actions

Copy link
Copy Markdown

PR Agent Handoff

Exit reason: Budget exhausted — fix or review cycle cap reached.

Metric Value
Fix rounds 0
Review cycles 8
Consecutive no-new-review cycles 0

CI status

Check Status Conclusion
MentraOS ASG Client Build in_progress

Remaining blocking findings

None

Nits (informational)

  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) clearAllCachedArtifacts() and pruneInvalidCachedArtifactsOnStartup() are no-op stubs invoked only by tests; dead API surface, consider removing if no caller remains.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) isBesOtaInProgress() returns false when the controller is null, slightly diverging from the old direct static-flag read in a stale-flag-after-clear() edge case; functionally equivalent in practice.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) Unused import 'dagger.hilt.android.EntryPointAccessors'; debugInstallBesFirmware uses the fully-qualified name instead. Remove the import or use the short name.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) clearAllCachedArtifacts() and pruneInvalidCachedArtifactsOnStartup() are dead no-ops referenced only by tests; consider removing rather than retaining for 'API compatibility' since no production caller exists.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) Unused import: EntryPointAccessors is imported but only referenced via its fully-qualified name at line 2791, leaving an unused import (lint warning).
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) Unused import: dagger.hilt.android.EntryPointAccessors is no longer referenced (the only call site at line 2791 uses the fully-qualified class name). Remove the import.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) isBesOtaInProgress() returns false when besOtaRegistry has been cleared while the global static BesOtaManager.isBesOtaInProgress is still true (e.g. registry.clear() during shutdown mid-OTA). Behaviorally harmless since the APK/MTK exclusion guards are moot during shutdown, but consider documenting the assumption.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/README.md) Doc references removed single-arg new OtaHelper(context) constructor; update to the two-arg (context, IBesOtaRegistry) form.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) clearAllCachedArtifacts()/pruneInvalidCachedArtifactsOnStartup() are public no-ops with no production callers, exercised only by tests. Remove the test-only API or document why it is retained.
  • (asg_client/AGENTS.md) States 'No Dagger/Hilt today' but module uses Hilt (TransportModule @Provides/@Singleton/@IntoSet). Update stale guidance.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) Unused import 'dagger.hilt.android.EntryPointAccessors' — the only usage (line ~2791) was switched to a fully-qualified name. Remove the import or use the short name at the call site.
  • (asg_client/app/src/main/java/com/mentra/asg_client/io/ota/helpers/OtaHelper.java) clearAllCachedArtifacts() and pruneInvalidCachedArtifactsOnStartup() are no-ops with no production callers (only tests invoke them); kept 'for API compatibility' but effectively dead code—consider removing.
  • (asg_client/AGENTS.md) Module guide states 'No Dagger/Hilt today' but this PR and existing OtaModule/AsgClientEntryPoint use Hilt; doc is stale and should be updated in a follow-up.

Humans merge when ready. Agents do not auto-merge. Label agent-resume to re-run the loop after new commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants