swbt-python 0.5.1__tar.gz → 0.5.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. {swbt_python-0.5.1 → swbt_python-0.5.3}/PKG-INFO +11 -11
  2. {swbt_python-0.5.1 → swbt_python-0.5.3}/README.md +9 -9
  3. {swbt_python-0.5.1 → swbt_python-0.5.3}/pyproject.toml +2 -2
  4. {swbt_python-0.5.1/spec/wip → swbt_python-0.5.3/spec/complete}/unit_056/PAIRING_PROFILE_NAMING.md +10 -10
  5. {swbt_python-0.5.1/spec/wip → swbt_python-0.5.3/spec/complete}/unit_057/PAIRING_PROFILE_CONTROLLER_KIND.md +16 -16
  6. swbt_python-0.5.3/spec/complete/unit_070/DIAGNOSTICS_AND_UNUSED_PATHS_CLEANUP.md +174 -0
  7. swbt_python-0.5.3/spec/complete/unit_071/CONTROLLER_CONSTRUCTION_PATH.md +174 -0
  8. swbt_python-0.5.3/spec/complete/unit_072/CONNECTION_RUNTIME_INTEGRATION.md +152 -0
  9. swbt_python-0.5.3/spec/complete/unit_073/TEST_CONTRACT_BOUNDARY_CLEANUP.md +135 -0
  10. swbt_python-0.5.3/spec/complete/unit_074/PUBLIC_GAMEPAD_IMPLEMENTATION_OWNERSHIP.md +188 -0
  11. swbt_python-0.5.3/spec/complete/unit_075/CONCRETE_CONTROLLER_MODULE.md +169 -0
  12. swbt_python-0.5.3/spec/complete/unit_076/HARDWARE_HAPPY_CASE_VALIDATION.md +139 -0
  13. swbt_python-0.5.3/spec/complete/unit_077/RUNTIME_INPUT_UPDATE_DISPATCH.md +81 -0
  14. swbt_python-0.5.3/spec/complete/unit_078/TEST_RUNTIME_FIXTURES.md +80 -0
  15. swbt_python-0.5.3/spec/complete/unit_079/PAIRING_PROFILE_KEY_STORE.md +67 -0
  16. swbt_python-0.5.3/spec/complete/unit_080/TRANSPORT_PROTOCOL_CONTRACT.md +61 -0
  17. swbt_python-0.5.3/spec/complete/unit_081/PROTOCOL_HANDSHAKE.md +369 -0
  18. swbt_python-0.5.3/spec/complete/unit_082/REPLY_HOLDOFF_VALIDATION.md +133 -0
  19. swbt_python-0.5.3/spec/complete/unit_083/PROFILE_SCHEMA_V2_CURRENT_KEY_ONLY.md +133 -0
  20. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/hardware-test-log.md +18 -0
  21. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/api.md +3 -21
  22. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/architecture.md +15 -5
  23. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/lifecycle.md +10 -11
  24. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/protocol.md +12 -12
  25. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/roadmap.md +1 -1
  26. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/testing.md +5 -3
  27. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/transport-bumble.md +10 -14
  28. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/rearchitecture/01-design-change-overview.md +13 -5
  29. swbt_python-0.5.3/spec/rearchitecture/02-as-is-to-be.md +75 -0
  30. swbt_python-0.5.3/spec/rearchitecture/03-public-api-config-profile.md +39 -0
  31. swbt_python-0.5.3/spec/rearchitecture/04-runtime-profile-transport-details.md +23 -0
  32. swbt_python-0.5.3/spec/rearchitecture/05-milestones-implementation.md +38 -0
  33. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/rearchitecture/README.md +9 -3
  34. swbt_python-0.5.3/spec/wip/unit_084/BUMBLE_0_0_233.md +142 -0
  35. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/diagnostics.py +4 -27
  36. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/gamepad/__init__.py +1 -1
  37. swbt_python-0.5.3/src/swbt/gamepad/_config.py +53 -0
  38. swbt_python-0.5.3/src/swbt/gamepad/connection.py +24 -0
  39. swbt_python-0.5.3/src/swbt/gamepad/controllers.py +211 -0
  40. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/gamepad/interface.py +190 -31
  41. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/gamepad/output.py +6 -3
  42. swbt_python-0.5.3/src/swbt/gamepad/protocol_handshake.py +167 -0
  43. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/gamepad/runtime.py +264 -252
  44. swbt_python-0.5.3/src/swbt/gamepad/transport_factory.py +27 -0
  45. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/report_loop.py +25 -41
  46. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/state_store.py +1 -31
  47. swbt_python-0.5.3/src/swbt/transport/_bumble_acl.py +17 -0
  48. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_bumble_key_store.py +12 -90
  49. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_bumble_lifecycle.py +28 -54
  50. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_pairing_profile.py +7 -11
  51. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/base.py +7 -33
  52. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/bumble.py +16 -23
  53. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/fake.py +3 -15
  54. swbt_python-0.5.3/tests/__init__.py +1 -0
  55. swbt_python-0.5.3/tests/gamepad_factory.py +202 -0
  56. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_controller_colors.py +2 -1
  57. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_pairing_profile.py +9 -5
  58. swbt_python-0.5.3/tests/hardware/test_reply_holdoff.py +199 -0
  59. swbt_python-0.5.3/tests/integration/__init__.py +1 -0
  60. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/integration/test_examples.py +1 -1
  61. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/integration/test_pairing_profile.py +13 -21
  62. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/integration/test_switch_gamepad_fake_transport.py +70 -68
  63. swbt_python-0.5.3/tests/unit/__init__.py +1 -0
  64. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/fixtures/source_audit/switch_protocol_values.toml +9 -11
  65. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_bumble_acl.py +2 -3
  66. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_bumble_lifecycle.py +7 -0
  67. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_bumble_transport.py +128 -31
  68. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_diagnostics.py +25 -10
  69. swbt_python-0.5.3/tests/unit/test_gamepad_config.py +175 -0
  70. swbt_python-0.5.3/tests/unit/test_gamepad_connection_workflow.py +20 -0
  71. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_gamepad_transport_factory.py +1 -77
  72. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_package_import.py +8 -1
  73. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_pairing_profile.py +34 -14
  74. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_pairing_profile_runtime.py +21 -10
  75. swbt_python-0.5.3/tests/unit/test_protocol_handshake.py +138 -0
  76. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_protocol_profile.py +1 -1
  77. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_public_api_boundary.py +36 -295
  78. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_report_loop.py +71 -5
  79. swbt_python-0.5.3/tests/unit/test_source_audit_fixtures.py +143 -0
  80. swbt_python-0.5.1/spec/rearchitecture/02-as-is-to-be.md +0 -212
  81. swbt_python-0.5.1/spec/rearchitecture/03-public-api-config-profile.md +0 -368
  82. swbt_python-0.5.1/spec/rearchitecture/04-runtime-profile-transport-details.md +0 -387
  83. swbt_python-0.5.1/spec/rearchitecture/05-milestones-implementation.md +0 -359
  84. swbt_python-0.5.1/src/swbt/_testing/__init__.py +0 -1
  85. swbt_python-0.5.1/src/swbt/_testing/gamepad.py +0 -145
  86. swbt_python-0.5.1/src/swbt/gamepad/_config.py +0 -101
  87. swbt_python-0.5.1/src/swbt/gamepad/connection.py +0 -238
  88. swbt_python-0.5.1/src/swbt/gamepad/core.py +0 -732
  89. swbt_python-0.5.1/src/swbt/gamepad/transport_factory.py +0 -104
  90. swbt_python-0.5.1/src/swbt/transport/_bumble_acl.py +0 -33
  91. swbt_python-0.5.1/tests/unit/test_gamepad_connection_workflow.py +0 -62
  92. swbt_python-0.5.1/tests/unit/test_source_audit_fixtures.py +0 -508
  93. {swbt_python-0.5.1 → swbt_python-0.5.3}/AGENTS.md +0 -0
  94. {swbt_python-0.5.1 → swbt_python-0.5.3}/LICENSE +0 -0
  95. {swbt_python-0.5.1 → swbt_python-0.5.3}/examples/hardware_bringup.py +0 -0
  96. {swbt_python-0.5.1 → swbt_python-0.5.3}/examples/pairing_probe.py +0 -0
  97. {swbt_python-0.5.1 → swbt_python-0.5.3}/examples/tap_a.py +0 -0
  98. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_001/M0_PROTOCOL_CORE.md +0 -0
  99. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_002/M1_SWITCH_GAMEPAD_FAKE_TRANSPORT.md +0 -0
  100. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_003/M2_BUMBLE_HID_TRANSPORT.md +0 -0
  101. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_004/M3_PAIRING_L2CAP.md +0 -0
  102. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_005/M4_SUBCOMMAND_RESPONDER_HARDWARE.md +0 -0
  103. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_006/M5_INPUT_OPERATION_API.md +0 -0
  104. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_007/M6_RECONNECT_KEYSTORE_DIAGNOSTICS.md +0 -0
  105. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_008/M7_PACKAGING_EXAMPLES_CLI.md +0 -0
  106. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_009/PORTING_SOURCE_AUDIT.md +0 -0
  107. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_010/DIAGNOSTICS_TRACE_SCHEMA.md +0 -0
  108. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_011/HARDWARE_TEST_LOG_MATRIX.md +0 -0
  109. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_012/INITIAL_RELEASE_GATE.md +0 -0
  110. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_013/POST_M5_INPUT_SEMANTIC_CHARACTERIZATION.md +0 -0
  111. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_014/DEVICE_CLOSE_GRACEFUL_DISCONNECT.md +0 -0
  112. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_015/CONTEXT_MANAGER_RESOURCE_SCOPE.md +0 -0
  113. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_016/JSON_KEY_STORE_CURRENT_PREVIOUS.md +0 -0
  114. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_017/SWITCH_GAMEPAD_API_HARDENING.md +0 -0
  115. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_018/KEY_STORE_TRANSPORT_BOUNDARY.md +0 -0
  116. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_019/TRANSPORT_RECONNECT_CONTRACT.md +0 -0
  117. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_020/STRUCTURAL_REFACTOR_BOUNDARIES.md +0 -0
  118. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_021/SWITCH_GAMEPAD_INPUT_API_CONTRACT.md +0 -0
  119. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_022/PUBLIC_API_USAGE_HARDWARE_DOCS.md +0 -0
  120. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_023/MKDOCS_DOCUMENTATION_SITE.md +0 -0
  121. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_024/STICK_INPUT_SHORTHAND_API.md +0 -0
  122. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md +0 -0
  123. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_026/LINUX_MACOS_ADAPTER_EXPERIMENTAL.md +0 -0
  124. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_027/ADAPTER_DISCOVERY_API.md +0 -0
  125. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_028/CONTROLLER_PROFILE_CUSTOMIZATION.md +0 -0
  126. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_029/CONTROLLER_PROFILE_INJECTION.md +0 -0
  127. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_030/JOYCON_PROFILE_IDENTITY_SPI.md +0 -0
  128. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_031/JOYCON_INPUT_REPORT_MAPPING.md +0 -0
  129. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_032/PROFILE_AWARE_SUBCOMMAND_STATE.md +0 -0
  130. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_033/PROFILE_AWARE_BUMBLE_SDP.md +0 -0
  131. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_034/JOYCON_CONVENIENCE_API_DOCS.md +0 -0
  132. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_035/JOYCON_DEVICE_INFO_ADDRESS_WIRING.md +0 -0
  133. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_036/JOYCON_SDP_IDENTITY_POLICY.md +0 -0
  134. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_037/JOYCON_DEFAULT_CONTROLLER_COLORS.md +0 -0
  135. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_038/REARCHITECTURE_DECISION_BOUNDARY_TESTS.md +0 -0
  136. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_039/CONTROLLER_RUNTIME_EXTRACTION.md +0 -0
  137. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_040/PUBLIC_CONTROLLER_API_MODEL.md +0 -0
  138. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_041/CONTROLLER_CONFIG_PROFILE_OWNERSHIP.md +0 -0
  139. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_042/INTERNAL_TRANSPORT_FACTORY.md +0 -0
  140. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_043/PROTOCOL_PROFILE_MODULE_SPLIT.md +0 -0
  141. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_044/REARCHITECTURE_DOCS_RELEASE_MATRIX.md +0 -0
  142. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_045/INTERNAL_API_BOUNDARY_CLEANUP.md +0 -0
  143. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_046/HARDWARE_PROFILE_TEST_SCENARIOS.md +0 -0
  144. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_047/VIRTUAL_GYRO_CALIBRATION.md +0 -0
  145. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_048/VIRTUAL_ACCELEROMETER_CALIBRATION.md +0 -0
  146. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_049/IMU_SESSION_AND_ENCODING_REDESIGN.md +0 -0
  147. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_050/DIRECT_REPORTING_TYPES.md +0 -0
  148. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_051/CSR_BD_ADDR_REWRITE_EXPERIMENT.md +0 -0
  149. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_052/EXP_LOCAL_ADDRESS_PROFILE.md +0 -0
  150. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_053/EXP_LOCAL_ADDRESS_PROFILE_JOYCON.md +0 -0
  151. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_054/EXP_LOCAL_ADDRESS_PROFILE_DIRECT.md +0 -0
  152. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_055/REMOVE_NATIVE_KEY_STORE_API.md +0 -0
  153. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_058/MULTI_ADDRESS_RECONNECT.md +0 -0
  154. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_059/EXPERIMENTAL_DIRECT_SEND_TIMING_PROBE.md +0 -0
  155. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_060/HCI_ACL_COMPLETION_CORRELATION.md +0 -0
  156. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_061/EXPERIMENTAL_CLASSIC_LINK_POLICY_AB.md +0 -0
  157. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_062/PERIODIC_ACL_DRAIN_CHARACTERIZATION.md +0 -0
  158. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_063/PERIODIC_NO_DRAIN_CHARACTERIZATION.md +0 -0
  159. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_064/BUMBLE_ENQUEUE_COMPLETION_CONTRACT.md +0 -0
  160. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_065/PERIODIC_DEADLINE_SCHEDULER.md +0 -0
  161. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_066/PAIRING_PROFILE_DEFAULT_ADDRESS.md +0 -0
  162. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_067/DEFAULT_BATTERY_STATUS.md +0 -0
  163. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_068/DIRECT_PRE_CLOSE_INPUT_REFLECTION.md +0 -0
  164. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/complete/unit_069/CONTROLLER_HANDSHAKE_READINESS.md +0 -0
  165. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/dev-journal.md +0 -0
  166. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/README.md +0 -0
  167. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/naming.md +0 -0
  168. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/initial/risks.md +0 -0
  169. {swbt_python-0.5.1 → swbt_python-0.5.3}/spec/rearchitecture/mkdocs-nav-snippet.yml +0 -0
  170. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/__init__.py +0 -0
  171. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/adapter_discovery.py +0 -0
  172. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/errors.py +0 -0
  173. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/gamepad/constants.py +0 -0
  174. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/imu.py +0 -0
  175. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/input.py +0 -0
  176. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/probe.py +0 -0
  177. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/__init__.py +0 -0
  178. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/buttons.py +0 -0
  179. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/descriptors.py +0 -0
  180. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/imu_report.py +0 -0
  181. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/input_report.py +0 -0
  182. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/output_report.py +0 -0
  183. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/profiles/__init__.py +0 -0
  184. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/profiles/base.py +0 -0
  185. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/profiles/joycon.py +0 -0
  186. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/profiles/pro_controller.py +0 -0
  187. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/rumble.py +0 -0
  188. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/session.py +0 -0
  189. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/spi.py +0 -0
  190. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/protocol/subcommand.py +0 -0
  191. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/py.typed +0 -0
  192. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/__init__.py +0 -0
  193. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_adapter_identity.py +0 -0
  194. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_bumble_hidp.py +0 -0
  195. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_bumble_sdp.py +0 -0
  196. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_bumble_usb_devices.py +0 -0
  197. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_csr_bd_addr.py +0 -0
  198. {swbt_python-0.5.1 → swbt_python-0.5.3}/src/swbt/transport/_csr_bd_addr_harness.py +0 -0
  199. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/conftest.py +0 -0
  200. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/README.md +0 -0
  201. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_battery_status.py +0 -0
  202. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_bumble_transport.py +0 -0
  203. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_close_disconnect.py +0 -0
  204. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_context_manager_resource_scope.py +0 -0
  205. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_multi_address_reconnect.py +0 -0
  206. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/hardware/test_pairing_l2cap.py +0 -0
  207. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_adapter_discovery.py +0 -0
  208. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_adapter_identity.py +0 -0
  209. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_bumble_hidp.py +0 -0
  210. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_bumble_sdp.py +0 -0
  211. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_ci_workflow.py +0 -0
  212. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_csr_bd_addr_experiment.py +0 -0
  213. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_csr_bd_addr_harness.py +0 -0
  214. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_gamepad_output_dispatcher.py +0 -0
  215. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_imu_report.py +0 -0
  216. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_input_report.py +0 -0
  217. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_input_state.py +0 -0
  218. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_output_report.py +0 -0
  219. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_package_metadata.py +0 -0
  220. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_probe_cli.py +0 -0
  221. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_protocol_boundary.py +0 -0
  222. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_protocol_session.py +0 -0
  223. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_publish_workflow.py +0 -0
  224. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_rumble_state.py +0 -0
  225. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_subcommand_responder.py +0 -0
  226. {swbt_python-0.5.1 → swbt_python-0.5.3}/tests/unit/test_virtual_spi_flash.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swbt-python
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: Python library for presenting an NX-compatible virtual Bluetooth HID input device.
5
5
  Keywords: bluetooth,bluetooth-hid,controller,gamepad,hid,nx
6
6
  Author: niart120
@@ -18,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
19
  Classifier: Topic :: Software Development :: Libraries
20
20
  Classifier: Typing :: Typed
21
- Requires-Dist: bumble>=0.0.230,<0.0.231
21
+ Requires-Dist: bumble==0.0.233
22
22
  Maintainer: niart120
23
23
  Maintainer-email: niart120 <38847256+niart120@users.noreply.github.com>
24
24
  Requires-Python: >=3.12
@@ -60,7 +60,9 @@ uv sync --dev
60
60
  同じ内容は `docs/` 配下でも確認できます。
61
61
 
62
62
  ## 利用例
63
+
63
64
  ### Pro Controller
65
+
64
66
  ```python
65
67
  import asyncio
66
68
  from swbt import Button, ProController
@@ -79,7 +81,9 @@ async def main() -> None:
79
81
  asyncio.run(main())
80
82
  ```
81
83
 
82
- Pro Controller 相当の一時的な仮想デバイスを作成し、ペアリング後に A ボタン入力を送信するコードの例です。接続情報を永続化する場合は `ProController.create_profile()` を使います。`local_address` を省略するとアダプタが現在報告する Bluetooth アドレスを維持し、揮発領域へ書き込みません。利用者管理のローカルアドレスへ切り替える手順は[利用例](docs/usage.md)、対応する専用 USB Bluetooth ドングルと復旧手順は[実機準備手順](docs/hardware.md)を参照してください。
84
+ Pro Controller 相当の仮想デバイスを作成し、ペアリング後に A ボタン入力を送信する例です。
85
+
86
+ 接続情報を保存して再利用する場合は、先に `ProController.create_profile()` で `profile_path` を作成します。アドレスの選択方法と復旧手順は[利用例](docs/usage.md)、専用 USB Bluetooth ドングルの準備は[実機準備手順](docs/hardware.md)を参照してください。
83
87
 
84
88
  ### Joy-Con L/R
85
89
 
@@ -104,9 +108,9 @@ async def main() -> None:
104
108
  asyncio.run(main())
105
109
  ```
106
110
 
107
- 「持ちかた/順番を変える」画面で Joy-Con としてペアリングする場合も、接続後に登録用の SR+SL 入力を追加送信する必要はありません。ライブラリは Joy-Con 用の初期化応答を返し、0 以外のプレイヤーライトが設定されるまで `connect()` を完了しません。Joy-Con L/R の `Button.SL` と `Button.SR` は、接続後に利用者が送る通常のボタン入力として引き続き利用できます。
111
+ 「持ちかた/順番を変える」画面でペアリングするときも、登録用の SR+SL 入力を追加送信する必要はありません。`connect()` Joy-Con 用の初期化とプレイヤーライトの設定が完了してから戻ります。
108
112
 
109
- Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetooth アドレスの選択方法とペアリングキーをまとめる `profile_path` を使います。新規プロファイルは各具象クラスの `create_profile()` で作成し、コントローラー形状と対象機器ごとに保存先を分けてください。v0.4.0 の `key_store_path` で使用していた JSON 形式のペアリング情報との互換経路はありません。Joy-Con L で右スティックや A/B/X/Y、Joy-Con R で左スティックや十字キーを入力すると `UnsupportedInputError` が送出されます。`JoyConPair` は未実装です。
113
+ `profile_path` はコントローラー形状と対象機器ごとに分けます。Joy-Con L では右スティックと A/B/X/Y、Joy-Con R では左スティックと十字キーを使えません。これらを指定すると `UnsupportedInputError` が送出されます。`JoyConPair` は未実装です。
110
114
 
111
115
  ## 接続方法
112
116
 
@@ -116,15 +120,11 @@ Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetoo
116
120
 
117
121
  ### 確認済み構成
118
122
 
119
- 2026-07-24 時点では、Windows 11 / CSR8510 A10 / WinUSB / `usb:0` で、Pro Controller、Joy-Con L、Joy-Con R の初回ペアリング、保存済みプロファイルを使う再接続、初期化完了後のオブジェクト返却を確認済みです。Joy-Con L/R は、登録用の SR+SL 入力を追加送信せずに初期化を完了しました。
120
-
121
- 同じ Windows 構成で、Pro Controller の主要なボタン / スティック入力、ニュートラル復帰と、Joy-Con L/R の対応ボタン / スティック入力も確認しています。確認済み範囲と未確認範囲の詳細は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)にあります。
122
-
123
- macOS 15.7.7 / CSR8510 A10 では、Pro Controller のペアリング、保存済みペアリング情報を使う再接続、ボタン入力、ニュートラル復帰を記録しています。
123
+ Windows 11 / CSR8510 A10 / WinUSB では、Pro Controller、Joy-Con L、Joy-Con R のペアリング、再接続、対応する入力操作を確認しています。macOS 15.7.7 / CSR8510 A10 では Pro Controller の限定的な動作を確認しています。条件と未確認範囲は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)を参照してください。
124
124
 
125
125
  ### 実験的構成
126
126
 
127
- Linux は experimental です。手順は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)に整備されていますが、専用 USB Bluetooth ドングルにアクセスできるか、ペアリングできるか、入力が反映されるかは未確認です。macOS Pro Controller の一部挙動のみ検証済みです。Joy-Con、別ドングル、別ファームウェアでの互換性は未確認です。
127
+ Linux は experimental です。専用 USB Bluetooth ドングルへのアクセス、ペアリング、入力反映は未確認です。macOS Joy-Con、別ドングル、別ファームウェアでの互換性も未確認です。
128
128
 
129
129
  ## 開発
130
130
 
@@ -34,7 +34,9 @@ uv sync --dev
34
34
  同じ内容は `docs/` 配下でも確認できます。
35
35
 
36
36
  ## 利用例
37
+
37
38
  ### Pro Controller
39
+
38
40
  ```python
39
41
  import asyncio
40
42
  from swbt import Button, ProController
@@ -53,7 +55,9 @@ async def main() -> None:
53
55
  asyncio.run(main())
54
56
  ```
55
57
 
56
- Pro Controller 相当の一時的な仮想デバイスを作成し、ペアリング後に A ボタン入力を送信するコードの例です。接続情報を永続化する場合は `ProController.create_profile()` を使います。`local_address` を省略するとアダプタが現在報告する Bluetooth アドレスを維持し、揮発領域へ書き込みません。利用者管理のローカルアドレスへ切り替える手順は[利用例](docs/usage.md)、対応する専用 USB Bluetooth ドングルと復旧手順は[実機準備手順](docs/hardware.md)を参照してください。
58
+ Pro Controller 相当の仮想デバイスを作成し、ペアリング後に A ボタン入力を送信する例です。
59
+
60
+ 接続情報を保存して再利用する場合は、先に `ProController.create_profile()` で `profile_path` を作成します。アドレスの選択方法と復旧手順は[利用例](docs/usage.md)、専用 USB Bluetooth ドングルの準備は[実機準備手順](docs/hardware.md)を参照してください。
57
61
 
58
62
  ### Joy-Con L/R
59
63
 
@@ -78,9 +82,9 @@ async def main() -> None:
78
82
  asyncio.run(main())
79
83
  ```
80
84
 
81
- 「持ちかた/順番を変える」画面で Joy-Con としてペアリングする場合も、接続後に登録用の SR+SL 入力を追加送信する必要はありません。ライブラリは Joy-Con 用の初期化応答を返し、0 以外のプレイヤーライトが設定されるまで `connect()` を完了しません。Joy-Con L/R の `Button.SL` と `Button.SR` は、接続後に利用者が送る通常のボタン入力として引き続き利用できます。
85
+ 「持ちかた/順番を変える」画面でペアリングするときも、登録用の SR+SL 入力を追加送信する必要はありません。`connect()` Joy-Con 用の初期化とプレイヤーライトの設定が完了してから戻ります。
82
86
 
83
- Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetooth アドレスの選択方法とペアリングキーをまとめる `profile_path` を使います。新規プロファイルは各具象クラスの `create_profile()` で作成し、コントローラー形状と対象機器ごとに保存先を分けてください。v0.4.0 の `key_store_path` で使用していた JSON 形式のペアリング情報との互換経路はありません。Joy-Con L で右スティックや A/B/X/Y、Joy-Con R で左スティックや十字キーを入力すると `UnsupportedInputError` が送出されます。`JoyConPair` は未実装です。
87
+ `profile_path` はコントローラー形状と対象機器ごとに分けます。Joy-Con L では右スティックと A/B/X/Y、Joy-Con R では左スティックと十字キーを使えません。これらを指定すると `UnsupportedInputError` が送出されます。`JoyConPair` は未実装です。
84
88
 
85
89
  ## 接続方法
86
90
 
@@ -90,15 +94,11 @@ Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetoo
90
94
 
91
95
  ### 確認済み構成
92
96
 
93
- 2026-07-24 時点では、Windows 11 / CSR8510 A10 / WinUSB / `usb:0` で、Pro Controller、Joy-Con L、Joy-Con R の初回ペアリング、保存済みプロファイルを使う再接続、初期化完了後のオブジェクト返却を確認済みです。Joy-Con L/R は、登録用の SR+SL 入力を追加送信せずに初期化を完了しました。
94
-
95
- 同じ Windows 構成で、Pro Controller の主要なボタン / スティック入力、ニュートラル復帰と、Joy-Con L/R の対応ボタン / スティック入力も確認しています。確認済み範囲と未確認範囲の詳細は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)にあります。
96
-
97
- macOS 15.7.7 / CSR8510 A10 では、Pro Controller のペアリング、保存済みペアリング情報を使う再接続、ボタン入力、ニュートラル復帰を記録しています。
97
+ Windows 11 / CSR8510 A10 / WinUSB では、Pro Controller、Joy-Con L、Joy-Con R のペアリング、再接続、対応する入力操作を確認しています。macOS 15.7.7 / CSR8510 A10 では Pro Controller の限定的な動作を確認しています。条件と未確認範囲は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)を参照してください。
98
98
 
99
99
  ### 実験的構成
100
100
 
101
- Linux は experimental です。手順は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)に整備されていますが、専用 USB Bluetooth ドングルにアクセスできるか、ペアリングできるか、入力が反映されるかは未確認です。macOS Pro Controller の一部挙動のみ検証済みです。Joy-Con、別ドングル、別ファームウェアでの互換性は未確認です。
101
+ Linux は experimental です。専用 USB Bluetooth ドングルへのアクセス、ペアリング、入力反映は未確認です。macOS Joy-Con、別ドングル、別ファームウェアでの互換性も未確認です。
102
102
 
103
103
  ## 開発
104
104
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "swbt-python"
3
- version = "0.5.1"
3
+ version = "0.5.3"
4
4
  description = "Python library for presenting an NX-compatible virtual Bluetooth HID input device."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -34,7 +34,7 @@ classifiers = [
34
34
  "Typing :: Typed",
35
35
  ]
36
36
  dependencies = [
37
- "bumble>=0.0.230,<0.0.231",
37
+ "bumble==0.0.233",
38
38
  ]
39
39
 
40
40
  [project.scripts]
@@ -61,16 +61,16 @@
61
61
 
62
62
  | status | item | type | layer | hardware | notes |
63
63
  |---|---|---|---|---|---|
64
- | implemented / smoke passed | `local_address` で作成した profile が従来の JSON payload を保存・読み込みできる | regression | unit | no | system Python smoke test で確認。pytest は環境遮断 |
65
- | implemented / blocked | adapter identity 準備失敗が新しい例外型で復旧を要求する | regression | unit | no | adapter は開かない fake session。pytest は環境遮断 |
66
- | implemented / blocked | concrete controller が `local_address` で profile を作成して再利用できる | regression | integration | no | fake transport。pytest は環境遮断 |
64
+ | green | `local_address` で作成した profile が従来の JSON payload を保存・読み込みできる | regression | unit | no | 現行 unit test CI で確認 |
65
+ | green | adapter identity 準備失敗が新しい例外型で復旧を要求する | regression | unit | no | adapterを開かない fake sessionで確認 |
66
+ | green | concrete controller が `local_address` で profile を作成して再利用できる | regression | integration | no | fake transport integrationで確認 |
67
67
 
68
68
  ## 8. 文書検証計画
69
69
 
70
70
  | document | audience / task | source of truth | mechanical check | review result | unresolved |
71
71
  |---|---|---|---|---|---|
72
- | API / usage / hardware docs | profile の作成と再利用 | 本仕様 §6、実装 | `uv run mkdocs build --strict` | manual pass / build blocked | `uv` cache が read-only |
73
- | release notes / agent brief | 例外名と用語 | 本仕様 §6、実装 | link / build | manual pass / build blocked | `uv` cache が read-only |
72
+ | API / usage / hardware docs | profile の作成と再利用 | 本仕様 §6、実装 | `uv run --group docs mkdocs build --strict` | done | none |
73
+ | release notes / agent brief | 例外名と用語 | 本仕様 §6、実装 | link / diff review | done | none |
74
74
 
75
75
  ## 9. 設計メモ
76
76
 
@@ -97,10 +97,10 @@
97
97
  | GitHub Actions CI #142 | passed | 新規 shape-only 値の保存と `direct_*` の未対応扱いを含む unit / integration test |
98
98
  | `ruff 0.15.20 format --check .` | passed | CI と同じ Ruff version を一時領域で実行 |
99
99
  | `ruff 0.15.20 check .` | passed | CI と同じ Ruff version を一時領域で実行 |
100
- | `uv run ty check --no-progress` | blocked | 同上 |
101
- | `uv run pytest tests/unit` | blocked | 同上。Bumble を含む依存が未導入 |
102
- | `uv run pytest tests/integration` | blocked | 同上 |
103
- | `uv run mkdocs build --strict` | blocked | 同上 |
100
+ | `uv run ty check --no-progress` | pass | current mainでAll checks passed |
101
+ | `uv run pytest tests/unit` | pass | current mainで439 passed |
102
+ | `uv run pytest tests/integration` | pass | current mainで154 passed |
103
+ | `uv run --group docs mkdocs build --strict` | pass | current mainでstrict build成功 |
104
104
 
105
105
  ## 12. 実機実行条件
106
106
 
@@ -115,7 +115,7 @@
115
115
 
116
116
  ## 13. 先送り事項
117
117
 
118
- - ReportingMode 分類の削除は unit_057 で扱う。
118
+ - none(ReportingMode 分類の削除は unit_057 で完了)
119
119
 
120
120
  ## 14. チェックリスト
121
121
 
@@ -64,17 +64,17 @@ pairing profile の `controller_kind` から、入力レポートの送信方式
64
64
 
65
65
  | status | item | type | layer | hardware | notes |
66
66
  |---|---|---|---|---|---|
67
- | implemented / CI passed | 新規 profile が ReportingMode を含まない controller shape を保存する | regression | unit | no | 新規保存は `pro` / `joycon_l` / `joycon_r`。GitHub Actions CI #142 で確認 |
68
- | implemented / CI passed | 旧 direct kind を持つ JSON が未対応値として adapter open 前に失敗する | regression | unit | no | `direct_*` を特別扱いせず、既存の `controller_kind` 検証で拒否。GitHub Actions CI #142 で確認 |
69
- | implemented / local passed | 同じ controller shape の periodic / direct が profile を相互利用できる | regression | unit | no | Direct controller の `open()` が profile path と local address を fake transport factory へ渡すことを確認 |
70
- | implemented / CI passed | controller shape が異なる profile は adapter open 前に拒否される | regression | unit | no | `ControllerKind` 比較の guard を GitHub Actions CI #142 で確認 |
67
+ | green | 新規 profile が ReportingMode を含まない controller shape を保存する | regression | unit | no | 新規保存は `pro` / `joycon_l` / `joycon_r`。CIと現行unitで確認 |
68
+ | green | 旧 direct kind を持つ JSON が未対応値として adapter open 前に失敗する | regression | unit | no | `direct_*` を特別扱いせず、既存の `controller_kind` 検証で拒否 |
69
+ | green | 同じ controller shape の periodic / direct が profile を相互利用できる | regression | unit | no | fake transport regression 3 passed |
70
+ | green | controller shape が異なる profile は adapter open 前に拒否される | regression | unit | no | `ControllerKind`比較のguardを確認 |
71
71
  | deferred | Direct / Periodic 間 profile 再利用の実機 pairing / reconnect | characterization | hardware | yes | 明示承認と専用 adapter が必要 |
72
72
 
73
73
  ## 8. 文書検証計画
74
74
 
75
75
  | document | audience / task | source of truth | mechanical check | review result | unresolved |
76
76
  |---|---|---|---|---|---|
77
- | API / usage / hardware docs | プロファイルの再利用範囲 | 本仕様 §6、実装、対象 test | `uv run --with mkdocs mkdocs build --strict` | 2026-07-21 docs-quality-review strict build が pass | 実機共有は未検証 |
77
+ | API / usage / hardware docs | プロファイルの再利用範囲 | 本仕様 §6、実装、対象 test | `uv run --group docs mkdocs build --strict` | done | Direct / Periodicの実機共有はdeferred |
78
78
 
79
79
  ## 9. 設計メモ
80
80
 
@@ -88,7 +88,7 @@ pairing profile の `controller_kind` から、入力レポートの送信方式
88
88
  |---|---|---|
89
89
  | `src/swbt/transport/_pairing_profile.py` | modify | `ControllerKind` 化と shape-only の値だけの受理 |
90
90
  | `src/swbt/gamepad/_config.py` | modify | profile kind config の削除 |
91
- | `src/swbt/gamepad/core.py` | modify | direct / periodic 共通の shape 利用 |
91
+ | `src/swbt/gamepad/controllers.py` | modify | direct / periodic 共通の shape 利用 |
92
92
  | `src/swbt/gamepad/runtime.py` | modify | protocol profile の kind による guard |
93
93
  | `tests/` | modify | legacy / cross-mode / mismatch 回帰 |
94
94
  | `docs/`, `spec/initial/` | modify | profile 共有範囲の説明 |
@@ -102,10 +102,10 @@ pairing profile の `controller_kind` から、入力レポートの送信方式
102
102
  | GitHub Actions CI #142 | passed | 新規 shape-only 値の保存と `direct_*` の未対応扱いを含む unit / integration test |
103
103
  | `ruff 0.15.20 format --check .` | passed | CI と同じ Ruff version を一時領域で実行 |
104
104
  | `ruff 0.15.20 check .` | passed | CI と同じ Ruff version を一時領域で実行 |
105
- | `uv run ty check --no-progress` | blocked | 同上 |
106
- | `uv run pytest tests/unit` | blocked | 同上。Bumble を含む依存が未導入 |
107
- | `uv run pytest tests/integration` | blocked | 同上 |
108
- | `uv run mkdocs build --strict` | blocked | 同上 |
105
+ | `uv run ty check --no-progress` | pass | current mainでAll checks passed |
106
+ | `uv run pytest tests/unit` | pass | current mainで439 passed |
107
+ | `uv run pytest tests/integration` | pass | current mainで154 passed |
108
+ | `uv run --group docs mkdocs build --strict` | pass | current mainでstrict build成功 |
109
109
  | `uv run pytest tests/unit/test_pairing_profile_runtime.py::test_direct_controller_reuses_profile_for_the_same_controller_shape -q` | passed | 3 passed。P2 review finding の fake transport regression |
110
110
  | `uv run --with mkdocs mkdocs build --strict` | passed | 2026-07-21。公開 docs の strict build |
111
111
 
@@ -113,16 +113,16 @@ pairing profile の `controller_kind` から、入力レポートの送信方式
113
113
 
114
114
  | 項目 | 内容 |
115
115
  |---|---|
116
- | 実機要否 | required for deferred characterization |
117
- | 承認範囲 | dedicated adapter open、target Switch pairing、active reconnect、normal close |
118
- | adapter | 実行直前に確認する専用 adapter |
116
+ | 実機要否 | not required for this unit(deferred characterization only) |
117
+ | 承認範囲 | この完了ではなし。将来実行する場合は明示承認を取得する |
118
+ | adapter | この完了では該当なし |
119
119
  | 実行遮断 | 環境変数による実行遮断は採用しない。明示承認、対象 adapter、command、cleanup plan で管理する |
120
- | log / artifact | `spec/hardware-test-log.md` に環境、command、result、cleanup を記録する |
121
- | cleanup | normal close 後に dedicated adapter を切り離す |
120
+ | log / artifact | この完了では新規記録なし。将来実行時は `spec/hardware-test-log.md` に記録する |
121
+ | cleanup | この完了では該当なし |
122
122
 
123
123
  ## 13. 先送り事項
124
124
 
125
- - Direct / Periodic 間での実機 pairing / reconnect hardware characterization として別途実行する。
125
+ - Direct / Periodic 間での実機 pairing / reconnect は、今回のprofile shape分離の完了条件に含めない。fake transportで公開契約を確認済みであり、実機再検証の追加価値は低いため、release gateで必要になった場合だけ専用hardware runとして扱う。
126
126
 
127
127
  ## 14. チェックリスト
128
128
 
@@ -0,0 +1,174 @@
1
+ # 診断履歴と未使用経路の削除 仕様書
2
+
3
+ ## 1. 概要
4
+
5
+ ### 1.1 目的
6
+
7
+ 公開 API、HID report、送信順序を変えずに、無制限に増える診断 event 履歴と本番から使われない内部経路を削除する。
8
+
9
+ ### 1.2 起点 / source
10
+
11
+ | source | 内容 | path |
12
+ |---|---|---|
13
+ | GitHub Issue | 診断履歴、test-only reply queue、状態更新 helper、未使用 control 送信経路の削除 | `https://github.com/niart120/swbt-python/issues/115` |
14
+ | 親 Issue | 観測可能な公開挙動を維持した内部境界の整理 | `https://github.com/niart120/swbt-python/issues/114` |
15
+ | 初期設計 | sender、report loop、transport、diagnostics の責務 | `spec/initial/architecture.md` |
16
+ | 初期設計 | output report と subcommand reply の送信経路 | `spec/initial/protocol.md` |
17
+ | 初期設計 | transport interface と Bumble 実装境界 | `spec/initial/transport-bumble.md` |
18
+
19
+ ### 1.3 use case
20
+
21
+ | actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
22
+ |---|---|---|---|
23
+ | 長時間動作する gamepad | trace writer なしで周期 `0x30` を送信する | report counter は増えるが、送信回数に比例した event 履歴を保持しない | `GamepadStatus` の集計値は維持する |
24
+ | diagnostics 利用者 | trace writer ありで lifecycle、report、subcommand、error を記録する | 既存 schema の JSON Lines を受け取る | event 名と field を変えない |
25
+ | Switch output report 処理 | subcommand を含む `0x01` を受信する | reply と periodic input が同じ sender lock と timer を使い、reply 後の holdoff が働く | reply bytes と送信順序を変えない |
26
+ | public gamepad API | button、stick、IMU、neutral を更新する | 従来と同じ `InputState` が確定する | `InputStateStore.update()` / `apply()` に集約する |
27
+ | transport 上位層 | host から control channel data を受信する | `on_control_data()` callback が従来どおり呼ばれる | 未使用の device-to-host `send_control()` は削除する |
28
+
29
+ ## 2. 対象範囲
30
+
31
+ - `DiagnosticsRecorder` の全 event 履歴と `events` property を削除する。
32
+ - report counter、last subcommand ID、last raw rumble、last error を有界な状態として保持する。
33
+ - trace writer への JSON Lines 出力を維持する。
34
+ - 本番 call site がない `record_state_transition()` を削除する。
35
+ - `ReportLoop` の test-only reply queue と専用送信経路を削除する。
36
+ - 実際の `send_subcommand_reply()`、共通 sender lock、timer、reply 後 holdoff を維持する。
37
+ - `InputStateStore` の個別 helper を削除し、production call site を `update()` / `apply()` へ移す。
38
+ - 本番 call site がない `HidDeviceTransport.send_control()` と Fake / Bumble 実装を削除する。
39
+ - `on_control_data()` を維持する。
40
+ - 関連する初期設計とテストを現行経路へ合わせる。
41
+
42
+ ## 3. 対象外
43
+
44
+ - `GamepadStatus` の公開フィールド変更。
45
+ - public gamepad の `press()`、`release()`、`sticks()`、`imu()`、`neutral()` の変更。
46
+ - input report、output report、subcommand reply、SPI、rumble の byte layout 変更。
47
+ - report period、reply holdoff 時間、timer の進め方の変更。
48
+ - Direct の transport 受理後 commit 条件の変更。
49
+ - Bumble adapter、Switch 実機を使う検証。
50
+ - 親 Issue #114 の他の子 Issue。
51
+
52
+ ## 4. 関連 docs
53
+
54
+ - `spec/initial/architecture.md`
55
+ - `spec/initial/api.md`
56
+ - `spec/initial/protocol.md`
57
+ - `spec/initial/transport-bumble.md`
58
+ - `spec/initial/lifecycle.md`
59
+ - `spec/initial/testing.md`
60
+ - `spec/initial/roadmap.md`
61
+
62
+ ## 5. 根拠監査
63
+
64
+ | 項目 | 要否 | 状態 | 根拠 / 理由 |
65
+ |---|---|---|---|
66
+ | Switch HID / report bytes | required | done | `ReportSender.send_subcommand_reply()` と既存 unit / integration test を維持し、report builder、parser、定数、payload は変更しない |
67
+ | Bumble / transport | required | done | `rg` で `send_control()` の production call site は定義以外 0 件。host-to-device の `on_control_data()` は `ControllerRuntime` が登録しているため維持する |
68
+ | OS / driver / adapter | not applicable | not applicable | adapter を開かず、driver や OS 依存挙動を変更しない |
69
+
70
+ ### 5.1 監査結果
71
+
72
+ | 項目 | 値 / 判断 | 根拠分類 | source | status |
73
+ |---|---|---|---|---|
74
+ | subcommand reply 経路 | `OutputReportDispatcher` から `send_subcommand_reply()` を呼び、`ReportSender` の lock 内で reply を生成・送信する | implementation fact | `src/swbt/gamepad/output.py`, `src/swbt/gamepad/runtime.py`, `src/swbt/report_loop.py` | confirmed |
75
+ | reply と input の直列化 | `0x21` と `0x30` は同じ `ReportSender._send_lock` と timer を使う | implementation fact | `src/swbt/report_loop.py`, `tests/unit/test_report_loop.py` | confirmed |
76
+ | outbound control 送信 | `send_control()` は protocol 定義、Fake、Bumble 実装と test にだけ存在し、本番 call site はない | implementation fact | `rg -n "send_control" src tests` | confirmed |
77
+ | inbound control 受信 | `ControllerRuntime` が `on_control_data()` を登録し、integration test が reply まで確認する | implementation fact | `src/swbt/gamepad/runtime.py`, `tests/integration/test_switch_gamepad_fake_transport.py` | confirmed |
78
+ | protocol bytes | builder、parser、profile、定数を変更しない | implementation fact | 対象差分と既存 unit / integration test | unit 475 件、integration 154 件で確認 |
79
+
80
+ ## 6. 振る舞い仕様
81
+
82
+ | 振る舞い | 入力・状態 | 期待結果 | 備考 |
83
+ |---|---|---|---|
84
+ | diagnostics の有界保持 | trace writer なしで多数の report event を記録 | recorder が通常 event を履歴として保持せず、counter だけが増える | last error 1 件の保持は許容する |
85
+ | status 集計 | report、subcommand、rumble、error を記録 | 従来と同じ counter、last ID、raw bytes、last error を返す | dict / bytes は防御的に返す |
86
+ | trace 出力 | trace writer ありで event を記録 | 既存 event schema の JSON Lines を逐次出力する | flush を維持する |
87
+ | reply 送信 | periodic input と subcommand reply が競合する | 同じ lock と timer で直列化し、reply 後は periodic を holdoff する | test-only queue は使わない |
88
+ | state 更新 | public API から IMU または neutral を更新 | `update()` / `apply()` 経由で従来と同じ state になる | Direct commit 条件は不変 |
89
+ | control channel 受信 | Fake transport へ control data を注入 | output dispatcher を通って `0x21` reply を送る | `on_control_data()` を維持する |
90
+
91
+ ## 7. TDD Test List
92
+
93
+ | status | item | type | layer | hardware | notes |
94
+ |---|---|---|---|---|---|
95
+ | refactor-done | trace writer なしで report event を繰り返しても過去 event object を保持せず、counter は正しく増える | regression | unit | no | `_events` 保持による red 後に有界集計へ変更して green |
96
+ | refactor-done | trace writer が既存 schema を維持し、last error を含む集計値を返す | characterization | unit / integration | no | `events` property の検査を trace または集計値へ置換 |
97
+ | refactor-done | subcommand reply と input report が共通 timer / lock を使い、reply 後 holdoff を維持する | characterization | unit / integration | no | 実際の `send_subcommand_reply()` 経路で検証し、reply queue 専用 test を削除 |
98
+ | refactor-done | state store helper 削除後も public IMU / neutral / concurrent state update と Direct commit が維持される | regression | unit / integration | no | `update()` / `apply()` へ集約 |
99
+ | refactor-done | outbound `send_control()` 削除後も inbound control data が subcommand reply へ到達する | regression | integration | no | Bumble adapter を開かず fake transport で確認 |
100
+
101
+ ## 8. 文書検証計画
102
+
103
+ 公開文書は変更しない。`spec/initial` と本作業仕様は、実装の call graph、検索結果、unit / integration test と照合する。
104
+
105
+ ## 9. 設計メモ
106
+
107
+ - diagnostics event は trace writer へ同期出力した後に破棄する。`last_error` だけは `GamepadStatus` のため 1 件保持する。
108
+ - reply は queue へ積まず、output report callback から共有 sender へ直接渡す。共有 lock 内で reply を構築するため、session state 変更と ACK の順序を維持できる。
109
+ - Periodic holdoff は `ReportLoop.send_subcommand_reply()` の完了後に設定する。
110
+ - `InputStateStore` は complete state の `apply()` と atomic read-modify-write の `update()` に絞る。
111
+ - HID control channel は host-to-device 受信に必要である。device-to-host の未使用送信 method を削除しても control channel 自体は削除しない。
112
+
113
+ ## 10. 対象ファイル
114
+
115
+ | path | change | 内容 |
116
+ |---|---|---|
117
+ | `src/swbt/diagnostics.py` | modify | event 履歴、`events`、未使用 transition helper を削除 |
118
+ | `src/swbt/report_loop.py` | modify | reply queue と既成 reply 送信経路を削除 |
119
+ | `src/swbt/state_store.py` | modify | 個別 state helper を削除 |
120
+ | `src/swbt/gamepad/runtime.py` | modify | IMU / neutral 更新を `update()` / `apply()` へ移行 |
121
+ | `src/swbt/gamepad/output.py` | modify | reply 経路の説明を現行実装へ合わせる |
122
+ | `src/swbt/transport/base.py` | modify | `send_control()` を protocol から削除 |
123
+ | `src/swbt/transport/fake.py` | modify | outbound control report の保持と送信を削除 |
124
+ | `src/swbt/transport/bumble.py` | modify | outbound control 送信実装を削除 |
125
+ | `tests/unit/test_diagnostics.py` | modify | 無制限保持と集計値を検証 |
126
+ | `tests/unit/test_report_loop.py` | modify | 実際の reply 経路で timer / holdoff を検証 |
127
+ | `tests/unit/test_bumble_transport.py` | modify | `events` / `send_control()` 専用検査を trace / interrupt 検査へ置換 |
128
+ | `tests/unit/test_public_api_boundary.py` | modify | test transport から未使用 method を削除 |
129
+ | `tests/integration/test_switch_gamepad_fake_transport.py` | modify | reply queue 用語を実際の送信順序へ置換 |
130
+ | `spec/initial/protocol.md` | modify | direct reply + shared sender 経路へ更新 |
131
+ | `spec/initial/transport-bumble.md` | modify | outbound control method を interface から削除 |
132
+ | `spec/initial/roadmap.md` | modify | M1 の完了表現を現行 reply 経路へ更新 |
133
+
134
+ ## 11. 検証
135
+
136
+ | command | result | notes |
137
+ |---|---|---|
138
+ | `uv run pytest tests/unit/test_diagnostics.py::test_report_events_are_not_retained_without_a_trace_writer -q` | red | `_events` が最初の `report_tx` event を保持して `1 failed` |
139
+ | 同上 | pass | 履歴削除後に `1 passed` |
140
+ | `uv run pytest tests/unit/test_diagnostics.py tests/unit/test_report_loop.py::test_imu_mode_transition_and_ack_share_periodic_send_lock ... -q` | pass | 変更前 characterization と診断変更後の対象検査 `10 passed` |
141
+ | `uv run pytest tests/unit/test_report_loop.py tests/integration/test_switch_gamepad_fake_transport.py::test_subcommand_reply_precedes_the_next_periodic_input tests/integration/test_switch_gamepad_fake_transport.py::test_imu_mode_ack_precedes_first_periodic_input_in_the_new_format -q` | pass | queue 削除後の timer / lock / holdoff `10 passed` |
142
+ | state store 対象 integration 4 件 | pass | IMU、neutral、disconnect、Direct commit を変更前後とも `4 passed` |
143
+ | `uv run pytest tests/unit/test_bumble_transport.py::test_bumble_interrupt_send_fails_until_l2cap_channel_is_connected tests/integration/test_switch_gamepad_fake_transport.py::test_control_output_report_injection_sends_subcommand_reply -q` | pass | outbound method 削除と inbound control 維持 `2 passed` |
144
+ | `uv sync --dev` | pass | `Resolved 53 packages` |
145
+ | `uv run ruff format --check .` | pass | `100 files already formatted` |
146
+ | `uv run ruff check .` | pass | `All checks passed!` |
147
+ | `uv run ty check --no-progress` | pass | `All checks passed!` |
148
+ | `uv run pytest tests/unit` | pass | `475 passed in 2.23s` |
149
+ | `uv run pytest tests/integration` | pass | `154 passed in 8.27s` |
150
+ | `git diff --check` | pass | whitespace error なし |
151
+ | `uv run mkdocs build --strict` | not run | `mkdocs` が project の開発依存に含まれず program not found。Issue #115 の指定 gate ではないため依存を追加せず、正本との手動照合を実施 |
152
+
153
+ ## 12. 実機実行条件
154
+
155
+ | 項目 | 内容 |
156
+ |---|---|
157
+ | 実機要否 | not required |
158
+ | 承認範囲 | adapter / Switch-facing command を実行しない |
159
+ | adapter | none |
160
+ | 実行遮断 | 環境変数による遮断は採用しない。`bumble` / `hardware` marker を実行対象から除外する |
161
+ | log / artifact | local unit / integration test output |
162
+ | cleanup | none |
163
+
164
+ ## 13. 先送り事項
165
+
166
+ - none
167
+
168
+ ## 14. チェックリスト
169
+
170
+ - [x] 対象範囲と対象外を確認した
171
+ - [x] TDD Test List または文書検証計画を更新した
172
+ - [x] 必要な根拠監査を記録した
173
+ - [x] 実機実行条件を記録した
174
+ - [x] 検証結果または未実行理由を記録した
@@ -0,0 +1,174 @@
1
+ # Controller 構築経路一本化 仕様書
2
+
3
+ ## 1. 概要
4
+
5
+ ### 1.1 目的
6
+
7
+ 公開 controller から `ControllerRuntime` と transport を構築する内部経路を1本にし、値のコピーだけを行う設定型、factory object、constructor 回避、production package 内の test-only factory を削除する。公開 constructor と観測可能な runtime 挙動は変えない。
8
+
9
+ ### 1.2 起点 / source
10
+
11
+ | source | 内容 | path |
12
+ |---|---|---|
13
+ | GitHub Issue | controller 構築経路、設定型、runtime constructor、transport 生成、test injection の一本化 | `https://github.com/niart120/swbt-python/issues/116` |
14
+ | 親 Issue | 観測可能な公開挙動を維持した不要境界の段階的削除 | `https://github.com/niart120/swbt-python/issues/114` |
15
+ | 依存 Issue | 診断履歴と未使用経路の削除 | `https://github.com/niart120/swbt-python/issues/115` |
16
+ | 初期設計 | public gamepad、runtime、transport の所有関係 | `spec/initial/architecture.md` |
17
+ | 初期設計 | 6 concrete controller の constructor 契約 | `spec/initial/api.md` |
18
+ | 初期設計 | fake transport と import boundary の検証方針 | `spec/initial/testing.md` |
19
+
20
+ ### 1.3 use case
21
+
22
+ | actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
23
+ |---|---|---|---|
24
+ | public API 利用者 | 6 concrete controller を既存引数で構築 | constructor 名、parameter、default、例外が変わらない | transport / profile seam を公開しない |
25
+ | runtime | 正規化済み controller 設定と optional injected transport を受け取る | 1個の constructor だけで全内部状態を構築する | `__new__()` 回避を使わない |
26
+ | default transport 利用者 | injected transport なしで controller を open | `create_default_transport()` を直接使う | adapter 必須、Bumble は遅延 import |
27
+ | fake integration test | Fake transport で public controller の lifecycle を検証 | tests 配下の support から公開 constructor 経路を使う | production package に test factory を置かない |
28
+ | pairing profile 利用者 | 異なる controller kind の profile path を渡す | adapter preparation / transport 作成前に mismatch を拒否する | profile schema は変更しない |
29
+
30
+ ## 2. 対象範囲
31
+
32
+ - `_SwitchGamepadConfig` と `_RuntimeConfig` を、正規化済みの内部設定型1個へ統合する。
33
+ - `_ControllerSpec` を削除し、各 concrete controller が固定 profile を class 属性で直接所有する。
34
+ - profile の `device_name` / `default_report_period_us` と明示値の優先規則を維持する。
35
+ - `controller_colors` の明示上書きと profile default を維持する。
36
+ - `ControllerRuntime.__init__()` へ初期化を集約し、`_init_from_config()` / `from_config()` / `__new__()` 回避を削除する。
37
+ - production から未使用の runtime async context manager を削除する。
38
+ - `_TransportFactory`、`_BumbleTransportFactory`、`_StaticTransportFactory` を削除する。
39
+ - injected transport はその instance を使い、未指定時は `create_default_transport()` を直接呼ぶ。
40
+ - `create_default_transport()` の Bumble 遅延 import を維持する。
41
+ - `src/swbt/_testing/gamepad.py` の6 factory と `_RuntimeBackedGamepad._from_config()` を削除する。
42
+ - fake transport test を tests 配下の support と公開 constructor 経路へ移す。
43
+ - 関連する初期設計とテストを現行構築経路へ更新する。
44
+
45
+ ## 3. 対象外
46
+
47
+ - `SwitchGamepad` / `PeriodicSwitchGamepad` / `DirectSwitchGamepad` の公開型階層変更。
48
+ - `ConnectionWorkflow` の削除や callback 構成変更。
49
+ - HID report、subcommand、SPI、SDP、pairing profile schema、CSR identity preparation の変更。
50
+ - public constructor への transport / profile 引数追加。
51
+ - dependency injection container、registry、manager の追加。
52
+ - Issue #117 以降の親 Issue 子項目。
53
+
54
+ ## 4. 関連 docs
55
+
56
+ - `spec/initial/architecture.md`
57
+ - `spec/initial/api.md`
58
+ - `spec/initial/testing.md`
59
+ - `spec/initial/transport-bumble.md`
60
+ - `spec/initial/lifecycle.md`
61
+ - `spec/complete/unit_070/DIAGNOSTICS_AND_UNUSED_PATHS_CLEANUP.md`
62
+
63
+ ## 5. 根拠監査
64
+
65
+ | 項目 | 要否 | 状態 | 根拠 / 理由 |
66
+ |---|---|---|---|
67
+ | Switch HID / report bytes | not applicable | not applicable | protocol builder、parser、定数、payload を変更しない |
68
+ | Bumble / transport | required | done | factory object を削除するが `create_default_transport()` とその関数内の遅延 import、Bumble constructor 引数は維持する。既存 import boundary test と transport factory test を根拠にする |
69
+ | OS / driver / adapter | not applicable | not applicable | adapter を開かず、driver / identity preparation の意味を変更しない |
70
+
71
+ ### 5.1 監査結果
72
+
73
+ | 項目 | 値 / 判断 | 根拠分類 | source | status |
74
+ |---|---|---|---|---|
75
+ | public import | `import swbt` は Bumble module を import / resolve しない | implementation fact | `tests/unit/test_public_api_boundary.py` | baseline green |
76
+ | transport factory import | `import swbt.gamepad.transport_factory` は Bumble module を import しない | implementation fact | `tests/unit/test_gamepad_transport_factory.py` | baseline green |
77
+ | default transport | `create_default_transport()` だけが `swbt.transport.bumble` を遅延 import する | implementation fact | `src/swbt/gamepad/transport_factory.py` | 維持 |
78
+ | profile kind mismatch | `PairingProfile.require_controller_kind()` が transport 作成前に拒否する | implementation fact | `src/swbt/gamepad/runtime.py`, `tests/unit/test_pairing_profile_runtime.py` | 維持 |
79
+ | construction result | concrete controller、`_GamepadConfig`、`ControllerRuntime.__init__()`、`create_default_transport()` の順に一本化した | implementation fact | `src/swbt/gamepad/` と unit / integration gate | done |
80
+
81
+ ## 6. 振る舞い仕様
82
+
83
+ | 振る舞い | 入力・状態 | 期待結果 | 備考 |
84
+ |---|---|---|---|
85
+ | public signature | 6 concrete controller を introspection | parameter 名と default が変更前と一致する | Direct に `report_period_us` を追加しない |
86
+ | adapter validation | default transport で adapter を省略 | `InvalidInputError` を constructor で送出する | injected runtime transport は adapter なしを許す |
87
+ | profile default | device name / report period の明示値なし | concrete profile の default を正規化済み設定へ入れる | profile object の値をコピーするだけの第2設定型は作らない |
88
+ | explicit override | report period / controller colors を指定 | explicit 値を runtime / report builder へ渡す | profile 自体は変更しない |
89
+ | profile kind | profile path の kind が concrete controller と不一致 | adapter preparation / transport creation 前に拒否する | 既存例外型を維持 |
90
+ | default transport | controller open 時に injected transport なし | `create_default_transport()` を直接1回呼ぶ | factory object を生成しない |
91
+ | injected transport | runtime に transport instance を渡す | default transport を作らず、その instance を使用する | tests support から利用 |
92
+ | import boundary | public API または transport factory module を import | Bumble を import / resolve しない | `create_default_transport()` 呼び出し時だけ解決 |
93
+ | resource ownership | public gamepad の `async with` | gamepad が open / close を所有する | runtime 自体は context manager を公開しない |
94
+
95
+ ## 7. TDD Test List
96
+
97
+ | status | item | type | layer | hardware | notes |
98
+ |---|---|---|---|---|---|
99
+ | done | production package に test-only gamepad factory module が存在しない | regression | unit | no | 削除前の red と削除後の green を確認 |
100
+ | done | 6 concrete controller の signature、型階層、adapter validation が維持される | characterization | unit | no | public API boundary test |
101
+ | done | profile default と明示 report period / controller colors の優先規則が維持される | characterization | unit / integration | no | `_GamepadConfig` と fake transport test |
102
+ | done | profile kind mismatch が transport 作成前に拒否される | characterization | unit | no | pairing profile runtime test |
103
+ | done | injected transport と default transport が同じ runtime constructor を使い、default 側だけ factory 関数を呼ぶ | regression | unit / integration | no | factory object を削除 |
104
+ | done | public import と transport factory import が Bumble を import / resolve しない | characterization | unit | no | subprocess / guarded import |
105
+ | done | fake transport integration が production test factory なしで Periodic / Direct 全経路を維持する | regression | integration | no | tests support は公開 constructor を使用 |
106
+
107
+ ## 8. 文書検証計画
108
+
109
+ 公開 docs site は変更しない。`spec/initial` の内部構築説明と fake transport test 方針を、実装 call graph、import boundary test、constructor signature test と照合する。
110
+
111
+ ## 9. 設計メモ
112
+
113
+ - 正規化済み設定型は `profile`、adapter / profile path、確定済み device name / report period、optional colors override を保持する。
114
+ - concrete controller は `_profile` class 属性を直接持つ。profile 選択用 wrapper object は置かない。
115
+ - public constructor は `_profile` から設定を作り、`ControllerRuntime(config, ...)` を1回呼ぶ。
116
+ - runtime は optional transport を受け取る。transport が `None` の場合だけ、open 時に `create_default_transport()` を直接呼ぶ。
117
+ - tests 配下の support は public controller constructor を呼ぶ際に runtime constructor を差し替え、Fake transport を注入する。production controller に `_from_config()` を戻さない。
118
+ - `create_default_transport()` は `transport_factory.py` に残し、Bumble import を関数内に閉じ込める。
119
+
120
+ ## 10. 対象ファイル
121
+
122
+ | path | change | 内容 |
123
+ |---|---|---|
124
+ | `src/swbt/gamepad/_config.py` | modify | 設定型を正規化済み1個へ統合 |
125
+ | `src/swbt/gamepad/core.py` | modify | class profile、public constructor から runtime への単一路 |
126
+ | `src/swbt/gamepad/runtime.py` | modify | constructor 一本化、factory object / context manager 削除 |
127
+ | `src/swbt/gamepad/transport_factory.py` | modify | factory class を削除し関数だけ維持 |
128
+ | `src/swbt/_testing/gamepad.py` | delete | production test factories を削除 |
129
+ | `src/swbt/_testing/__init__.py` | delete | 空の test-only package を削除 |
130
+ | `tests/gamepad_factory.py` | new | public constructor と runtime injection を使う test support |
131
+ | `tests/unit/test_public_api_boundary.py` | modify | 単一設定型、class profile、seam 削除、既存契約 |
132
+ | `tests/unit/test_gamepad_transport_factory.py` | modify | 関数と import boundary の検証へ集約 |
133
+ | `tests/integration/test_switch_gamepad_fake_transport.py` | modify | production test factory / `_from_config()` を除去 |
134
+ | `tests/integration/test_examples.py` | modify | tests support を利用 |
135
+ | `spec/initial/architecture.md` | modify | controller 構築経路を記録 |
136
+ | `spec/initial/api.md` | modify | production test helper 参照を削除 |
137
+ | `spec/initial/testing.md` | modify | tests support と public constructor 経路へ更新 |
138
+
139
+ ## 11. 検証
140
+
141
+ | command | result | notes |
142
+ |---|---|---|
143
+ | `uv run pytest tests/unit/test_package_import.py::test_production_package_has_no_test_gamepad_factory_module -q` | red / green | 削除前は `swbt._testing.gamepad` が見つかり失敗、削除後は unit gate 内で成功 |
144
+ | `uv run pytest tests/unit/test_package_import.py tests/unit/test_gamepad_transport_factory.py tests/unit/test_public_api_boundary.py tests/unit/test_pairing_profile_runtime.py -q` | pass | 54 passed |
145
+ | `uv sync --dev` | pass | 53 packages resolved、41 packages checked |
146
+ | `uv run ruff format --check .` | pass | 102 files already formatted |
147
+ | `uv run ruff check .` | pass | All checks passed |
148
+ | `uv run ty check --no-progress` | pass | All checks passed |
149
+ | `uv run pytest tests/unit` | pass | 468 passed |
150
+ | `uv run pytest tests/integration` | pass | 154 passed |
151
+ | `git diff --check` | pass | whitespace error なし |
152
+
153
+ ## 12. 実機実行条件
154
+
155
+ | 項目 | 内容 |
156
+ |---|---|
157
+ | 実機要否 | not required |
158
+ | 承認範囲 | adapter / Switch-facing command を実行しない |
159
+ | adapter | none |
160
+ | 実行遮断 | 環境変数による遮断は採用しない。`bumble` / `hardware` marker を実行対象から除外する |
161
+ | log / artifact | local unit / integration / CI output |
162
+ | cleanup | none |
163
+
164
+ ## 13. 先送り事項
165
+
166
+ - none
167
+
168
+ ## 14. チェックリスト
169
+
170
+ - [x] 対象範囲と対象外を確認した
171
+ - [x] TDD Test List または文書検証計画を更新した
172
+ - [x] 必要な根拠監査を記録した
173
+ - [x] 実機実行条件を記録した
174
+ - [x] 検証結果または未実行理由を記録した