release: prepare v0.0.1-rc.4

This commit is contained in:
2026-03-07 15:51:21 -05:00
parent 86875075fc
commit da09094d3e
52 changed files with 1076 additions and 1234 deletions

View File

@@ -36,7 +36,7 @@ body:
id: openbitdo_version id: openbitdo_version
attributes: attributes:
label: OpenBitdo version label: OpenBitdo version
placeholder: v0.0.1-rc.1 placeholder: v0.0.1-rc.4
validations: validations:
required: true required: true
- type: textarea - type: textarea

View File

@@ -4,13 +4,13 @@ on:
workflow_call: workflow_call:
inputs: inputs:
tag: tag:
description: "Release tag to publish (for example: v0.0.1-rc.2)" description: "Release tag to publish (for example: v0.0.1-rc.4)"
required: true required: true
type: string type: string
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
description: "Release tag to publish (for example: v0.0.1-rc.2)" description: "Release tag to publish (for example: v0.0.1-rc.4)"
required: true required: true
type: string type: string

View File

@@ -30,21 +30,21 @@ jobs:
container: archlinux:base container: archlinux:base
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install AUR packaging toolchain - name: Install packaging validation toolchain
run: | run: |
pacman -Sy --noconfirm --needed base-devel git pacman -Sy --noconfirm --needed base-devel git jq
- name: Ensure package metadata has pinned checksum fields - name: Validate release metadata rendering
run: | run: |
set -euo pipefail set -euo pipefail
if grep -nE 'SKIP|:no_check' \
packaging/aur/openbitdo-bin/PKGBUILD \
packaging/homebrew/Formula/openbitdo.rb; then
echo "Found placeholder checksum markers; release metadata must be pinned." >&2
exit 1
fi
test -f packaging/scripts/render_release_metadata.sh test -f packaging/scripts/render_release_metadata.sh
test -f packaging/aur/openbitdo-bin/PKGBUILD.tmpl test -f packaging/aur/openbitdo-bin/PKGBUILD.tmpl
test -f packaging/homebrew/Formula/openbitdo.rb.tmpl test -f packaging/homebrew/Formula/openbitdo.rb.tmpl
test ! -f packaging/homebrew/Formula/openbitdo.rb
bash packaging/scripts/test_render_release_metadata.sh
- name: Validate Homebrew tap sync helper
run: |
set -euo pipefail
bash packaging/homebrew/test_sync_tap.sh
- name: Validate PKGBUILD and .SRCINFO - name: Validate PKGBUILD and .SRCINFO
run: | run: |
useradd -m builder useradd -m builder
@@ -53,6 +53,10 @@ jobs:
cd '$GITHUB_WORKSPACE/packaging/aur/openbitdo-bin'; \ cd '$GITHUB_WORKSPACE/packaging/aur/openbitdo-bin'; \
makepkg --printsrcinfo > /tmp/openbitdo-bin.srcinfo; \ makepkg --printsrcinfo > /tmp/openbitdo-bin.srcinfo; \
diff -u .SRCINFO /tmp/openbitdo-bin.srcinfo" diff -u .SRCINFO /tmp/openbitdo-bin.srcinfo"
- name: Check docs consistency
run: |
set -euo pipefail
bash sdk/scripts/check_docs_consistency.sh
tui-smoke-test: tui-smoke-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest

82
.github/workflows/homebrew-publish.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
name: Homebrew Publish
on:
workflow_call:
inputs:
tag:
description: "Release tag to publish (for example: v0.0.1-rc.4)"
required: true
type: string
workflow_dispatch:
inputs:
tag:
description: "Release tag to publish (for example: v0.0.1-rc.4)"
required: true
type: string
permissions:
contents: read
jobs:
publish-homebrew:
if: vars.HOMEBREW_PUBLISH_ENABLED == '1'
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ inputs.tag }}
steps:
- uses: actions/checkout@v4
- name: Wait for release assets
run: |
set -euo pipefail
for attempt in $(seq 1 30); do
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "release ${TAG} is available"
exit 0
fi
sleep 10
done
echo "release ${TAG} was not found after waiting" >&2
exit 1
- name: Render Homebrew formula from released assets
run: |
set -euo pipefail
mkdir -p /tmp/release-input /tmp/release-metadata
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
--pattern "openbitdo-${TAG}-linux-x86_64.tar.gz" \
--pattern "openbitdo-${TAG}-linux-aarch64.tar.gz" \
--pattern "openbitdo-${TAG}-macos-arm64.tar.gz" \
--dir /tmp/release-input
bash packaging/scripts/render_release_metadata.sh \
"$TAG" \
"$GITHUB_REPOSITORY" \
/tmp/release-input \
/tmp/release-metadata
- name: Upload rendered Homebrew formula (audit)
uses: actions/upload-artifact@v4
with:
name: homebrew-rendered-formula-${{ inputs.tag }}
path: |
/tmp/release-metadata/homebrew/Formula/openbitdo.rb
/tmp/release-metadata/checksums.env
- name: Sync Homebrew tap
env:
HOMEBREW_PUBLISH_ENABLED: "1"
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
HOMEBREW_TAP_REPO: ${{ vars.HOMEBREW_TAP_REPO }}
FORMULA_SOURCE: /tmp/release-metadata/homebrew/Formula/openbitdo.rb
run: |
set -euo pipefail
if [[ -z "${HOMEBREW_TAP_TOKEN:-}" ]]; then
echo "missing required secret: HOMEBREW_TAP_TOKEN" >&2
exit 1
fi
if [[ -z "${HOMEBREW_TAP_REPO:-}" ]]; then
echo "missing required variable: HOMEBREW_TAP_REPO" >&2
exit 1
fi
bash packaging/homebrew/sync_tap.sh

View File

@@ -269,61 +269,11 @@ jobs:
publish-homebrew: publish-homebrew:
if: vars.HOMEBREW_PUBLISH_ENABLED == '1' if: vars.HOMEBREW_PUBLISH_ENABLED == '1'
runs-on: ubuntu-latest
needs: publish needs: publish
env: uses: ./.github/workflows/homebrew-publish.yml
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Wait for release assets
run: |
set -euo pipefail
for attempt in $(seq 1 30); do
if gh release view "${GITHUB_REF_NAME}" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
exit 0
fi
sleep 10
done
echo "release ${GITHUB_REF_NAME} was not found after waiting" >&2
exit 1
- name: Render Homebrew formula with release checksums
run: |
set -euo pipefail
mkdir -p /tmp/release-input /tmp/release-metadata
gh release download "${GITHUB_REF_NAME}" --repo "$GITHUB_REPOSITORY" \
--pattern "openbitdo-${GITHUB_REF_NAME}-linux-x86_64.tar.gz" \
--pattern "openbitdo-${GITHUB_REF_NAME}-linux-aarch64.tar.gz" \
--pattern "openbitdo-${GITHUB_REF_NAME}-macos-arm64.tar.gz" \
--dir /tmp/release-input
bash packaging/scripts/render_release_metadata.sh \
"${GITHUB_REF_NAME}" \
"$GITHUB_REPOSITORY" \
/tmp/release-input \
/tmp/release-metadata
- name: Upload rendered Homebrew formula (audit)
uses: actions/upload-artifact@v4
with: with:
name: homebrew-rendered-formula-${{ github.ref_name }} tag: ${{ github.ref_name }}
path: | secrets: inherit
/tmp/release-metadata/homebrew/Formula/openbitdo.rb
/tmp/release-metadata/checksums.env
- name: Sync Homebrew tap
env:
HOMEBREW_PUBLISH_ENABLED: "1"
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
HOMEBREW_TAP_REPO: ${{ vars.HOMEBREW_TAP_REPO }}
FORMULA_SOURCE: /tmp/release-metadata/homebrew/Formula/openbitdo.rb
run: |
set -euo pipefail
if [[ -z "${HOMEBREW_TAP_TOKEN:-}" ]]; then
echo "missing required secret: HOMEBREW_TAP_TOKEN" >&2
exit 1
fi
bash packaging/homebrew/sync_tap.sh
publish-aur: publish-aur:
if: vars.AUR_PUBLISH_ENABLED == '1' if: vars.AUR_PUBLISH_ENABLED == '1'

View File

@@ -1,40 +1,41 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file. All notable changes to OpenBitdo are tracked here.
## Unreleased ## Unreleased
## v0.0.1-rc.4
### Changed ### Changed
- CLI contract reverted to single-command interactive launch:
- `openbitdo [--mock]` - Release docs are being rewritten around the `v0.0.1-rc.4` flow.
- subcommand forms `openbitdo ui ...` and `openbitdo run ...` are rejected. - Homebrew publishing is being moved to a reusable workflow with the separate tap repo kept as the canonical Homebrew destination.
- Headless automation output remains available in the `bitdo_tui` Rust API (human and line-delimited JSON records). - TUI copy is being expanded so first-run guidance is clearer and blocked-action reasons are easier to understand.
- AUR packaging/publish flow now targets `openbitdo-bin` only. - The checked-in Homebrew formula output is being removed; the template and rendered release metadata remain the source of truth.
- Settings schema is now documented as v2:
- `schema_version` ## v0.0.1-rc.3
- `advanced_mode`
- `report_save_mode` ### Added
- `device_filter_text`
- `dashboard_layout_mode` - Tag-driven GitHub prerelease assets for Linux `x86_64`, Linux `aarch64`, and macOS arm64.
- `last_panel_focus` - AUR publication for `openbitdo-bin` with release-derived checksums.
- Diagnostics screen with richer per-check detail and saved-report flow.
### Changed
- Firmware update defaults remain safe until the user explicitly acknowledges risk.
- Temporary recommended-firmware downloads are cleaned up after success, failure, or cancellation.
- Invalid persisted settings are surfaced as warnings instead of being silently discarded.
## v0.0.1-rc.1 ## v0.0.1-rc.1
### Added ### Added
- Beginner-first `openbitdo` TUI flow with device-specific JP108 and Ultimate2 guided mapping paths.
- About screen showing app version, git commit, build date, and runtime/target platform.
- Release packaging scripts for Linux (`x86_64`, `aarch64`) and macOS arm64 outputs.
- macOS arm64 unsigned/ad-hoc `.pkg` packaging to `/opt/homebrew/bin/openbitdo`.
- AUR packaging sources for `openbitdo` and `openbitdo-bin`.
- Homebrew formula scaffolding and deferred tap sync script.
- Release workflow for tag-triggered GitHub pre-releases using changelog content.
- Release metadata rendering that computes authoritative checksums from published assets for AUR/Homebrew updates.
### Changed - Beginner-first `openbitdo` launcher and terminal dashboard.
- Project license transitioned to BSD 3-Clause. - Release packaging scripts for Linux and macOS artifacts.
- CI expanded to include macOS arm64 package build validation and AUR package metadata validation. - Unsigned, non-notarized macOS `.pkg` output for RC distribution.
- Release process documentation updated for clean-tree requirements and RC gating policy. - AUR and Homebrew release metadata rendering.
### Notes ### Notes
- Homebrew and AUR publication paths are automated and remain controlled by repo variables (`HOMEBREW_PUBLISH_ENABLED`, `AUR_PUBLISH_ENABLED`).
- Hardware CI gates remain required as configured in `ci.yml`. - Historical RC notes are preserved here for audit continuity.

View File

@@ -1,46 +1,24 @@
# OpenBitdo Migration Notes # OpenBitdo Migration Notes
## Scope This file explains the current user and contributor surface after the CLI and packaging cleanup.
This migration restores the single-command `openbitdo` CLI contract and removes the `ui`/`run` subcommand surface from user-facing usage.
## What changed ## Current CLI Contract
- `bitdoctl` was removed.
- `openbitdo cmd ...` was removed.
- `openbitdo` now launches interactive TUI directly (with optional `--mock`).
- subcommand forms `openbitdo ui ...` and `openbitdo run ...` are rejected (historical).
- headless output modes remain available through the Rust API, not the CLI.
- Settings schema moved to v2 fields while keeping compatibility defaults for v1 files.
## Command mapping - `openbitdo` launches the interactive dashboard.
| Prior command form | Current command | - `openbitdo --mock` launches the dashboard without real hardware.
| --- | --- | - Historical subcommand-style entry points are no longer part of the supported CLI.
| `cargo run -p openbitdo --` | `cargo run -p openbitdo --` |
| `cargo run -p openbitdo -- --mock` | `cargo run -p openbitdo -- --mock` |
| `openbitdo ui --mock` (historical) | `openbitdo --mock` |
| `openbitdo run ...` (historical) | Not supported in CLI |
## New usage ## Current Packaging Contract
From `/Users/brooklyn/data/8bitdo/cleanroom/sdk`:
Interactive dashboard: - GitHub prereleases are the canonical release source.
- AUR publishes `openbitdo-bin`.
- Homebrew publishes through the separate tap repo `bybrooklyn/homebrew-openbitdo`.
- macOS artifacts remain unsigned and non-notarized until Apple credentials exist.
```bash ## Current Settings Contract
cargo run -p openbitdo --
cargo run -p openbitdo -- --mock
```
## Historical note Persisted UI state uses `schema_version = 2` with these fields:
The temporary subcommand surface (`openbitdo ui` / `openbitdo run`) is historical (historical) and should not be used for current workflows.
## Headless library API
Headless automation remains available to Rust callers through `bitdo_tui`:
```bash
run_headless(core, RunLaunchOptions { output_mode: HeadlessOutputMode::Json, ..Default::default() })
```
## Settings schema migration
Current schema is `schema_version = 2` with fields:
- `advanced_mode` - `advanced_mode`
- `report_save_mode` - `report_save_mode`
- `device_filter_text` - `device_filter_text`
@@ -48,10 +26,21 @@ Current schema is `schema_version = 2` with fields:
- `last_panel_focus` - `last_panel_focus`
Compatibility behavior: Compatibility behavior:
- v1 settings files load with defaults for missing v2 fields.
- if `advanced_mode = false`, `report_save_mode = off` is normalized to `failure_only`.
## CI note - v1 settings still load with defaults for new fields.
The CLI smoke coverage now validates: - invalid settings files now raise a warning and fall back to defaults instead of being silently accepted.
- `openbitdo --help` exposes single-command option usage.
- `openbitdo ui ...` and `openbitdo run ...` fail as unsupported forms (historical). ## Current Library Contract
OpenBitdo keeps headless automation as a Rust API, not a public CLI surface.
The supported entry points remain:
- `bitdo_tui::run_headless`
- `bitdo_tui::RunLaunchOptions`
- `bitdo_tui::HeadlessOutputMode`
## Practical Migration Guidance
- If you used the historical CLI subcommands, switch to `openbitdo` or `openbitdo --mock`.
- If you need automation, call the Rust API instead of expecting a supported headless CLI.
- If you document install paths, prefer Homebrew tap, AUR, tarball, or source build rather than old ad hoc command forms.

View File

@@ -1,44 +1,26 @@
# OpenBitdo RC Checklist (`v0.0.1-rc.2`) # OpenBitdo RC Checklist (`v0.0.1-rc.4`)
This checklist defines release-candidate readiness for the `v0.0.1-rc.2` public RC tag. This checklist defines the release-candidate gate for the current public RC tag.
## Candidate Policy ## Release Policy
- Tag format: `v*` (for this RC: `v0.0.1-rc.2`)
- Tag format: `v*`
- Current RC tag: `v0.0.1-rc.4`
- Tag source: `main` only - Tag source: `main` only
- Release trigger: tag push - Release trigger: tag push
- RC gate: all required CI checks + manual smoke validation - Public RC rule: zero open issues labeled `release-blocker`
## Release-Blocker Policy ## Required CI Checks
Use GitHub issue labels:
- `release-blocker`
- `severity:p0`
- `severity:p1`
- `severity:p2`
Public RC gate rule: - `guard`
- zero open issues labeled `release-blocker` - `aur-validate`
- `tui-smoke-test`
- `build-macos-arm64`
- `test`
Daily review cadence: ## Clean Tree Gate
- run once per day until RC tag:
- `gh issue list -R bybrooklyn/openbitdo --label release-blocker --state open --limit 200`
- release remains blocked while this list is non-empty.
- AUR auth troubleshooting runbook:
- [aur_publish_troubleshooting.md](/Users/brooklyn/data/8bitdo/cleanroom/process/aur_publish_troubleshooting.md)
## Scope-Completeness Gate ("Good Point") From `cleanroom/`:
Before tagging `v0.0.1-rc.2`, RC scope must match the locked contract:
- JP108 mapping supports dedicated keys only (`A/B/K1-K8`) for RC.
- Ultimate2 expanded mapping supports RC-required fields only:
- remappable slots `A/B/K1-K8`
- known controller-button targets
- profile slot read/write/readback
- firmware version in diagnostics/reports
- L2/R2 analog read (and write where capability allows)
Release gate is checklist-driven for RC (no separate scorecard artifact).
## Clean-Tree Requirement (Before Tagging)
Run from `/Users/brooklyn/data/8bitdo/cleanroom`:
```bash ```bash
git status --porcelain git status --porcelain
@@ -46,108 +28,53 @@ git clean -ndX
``` ```
Expected: Expected:
- `git status --porcelain` prints nothing (no modified, staged, or untracked files)
- `git clean -ndX` output reviewed for ignored-build artifacts only
Tracked-path audit: - no tracked modifications or staged changes
- ignored-output review only from `git clean -ndX`
```bash
git ls-files | rg '(^sdk/dist/|^sdk/target/|^harness/reports/)'
```
Expected:
- no tracked artifact/build-output paths matched
## Required CI Checks
- `guard`
- `aur-validate`
- `tui-smoke-test`
- `build-macos-arm64`
- `test`
## Release Secret Preflight (Tag Workflow)
Tag preflight must fail early if any required secret is missing:
- `AUR_USERNAME`
- `AUR_SSH_PRIVATE_KEY`
- `HOMEBREW_TAP_TOKEN`
## Artifact Expectations ## Artifact Expectations
Release assets must include: Release assets must include:
- `openbitdo-v0.0.1-rc.2-linux-x86_64.tar.gz`
- `openbitdo-v0.0.1-rc.2-linux-x86_64`
- `openbitdo-v0.0.1-rc.2-linux-aarch64.tar.gz`
- `openbitdo-v0.0.1-rc.2-linux-aarch64`
- `openbitdo-v0.0.1-rc.2-macos-arm64.tar.gz`
- `openbitdo-v0.0.1-rc.2-macos-arm64`
- `openbitdo-v0.0.1-rc.2-macos-arm64.pkg`
- corresponding `.sha256` files for every artifact above
## Verify Checksums - `openbitdo-v0.0.1-rc.4-linux-x86_64.tar.gz`
Run from release asset directory: - `openbitdo-v0.0.1-rc.4-linux-x86_64`
- `openbitdo-v0.0.1-rc.4-linux-aarch64.tar.gz`
- `openbitdo-v0.0.1-rc.4-linux-aarch64`
- `openbitdo-v0.0.1-rc.4-macos-arm64.tar.gz`
- `openbitdo-v0.0.1-rc.4-macos-arm64`
- `openbitdo-v0.0.1-rc.4-macos-arm64.pkg`
- `.sha256` files for every artifact above
```bash ## Distribution Gate
shasum -a 256 -c openbitdo-v0.0.1-rc.2-linux-x86_64.tar.gz.sha256
shasum -a 256 -c openbitdo-v0.0.1-rc.2-linux-x86_64.sha256
shasum -a 256 -c openbitdo-v0.0.1-rc.2-linux-aarch64.tar.gz.sha256
shasum -a 256 -c openbitdo-v0.0.1-rc.2-linux-aarch64.sha256
shasum -a 256 -c openbitdo-v0.0.1-rc.2-macos-arm64.tar.gz.sha256
shasum -a 256 -c openbitdo-v0.0.1-rc.2-macos-arm64.sha256
shasum -a 256 -c openbitdo-v0.0.1-rc.2-macos-arm64.pkg.sha256
```
## Manual Smoke Matrix - GitHub prerelease assets must be published successfully.
1. Linux `x86_64` - AUR publish must render checksum-pinned metadata and update `openbitdo-bin`.
- Extract tarball, run `./bin/openbitdo --mock` - Homebrew publish must render a checksum-pinned formula and update `bybrooklyn/homebrew-openbitdo`.
- Confirm dashboard renders (device list, quick actions, event panel)
- Confirm settings screen opens and returns to dashboard
2. Linux `aarch64` ## macOS Packaging Gate
- Extract tarball, run `./bin/openbitdo --mock`
- Confirm dashboard navigation and preflight/task render
3. macOS arm64 - `.pkg` remains unsigned and non-notarized for this RC.
- Run standalone binary `openbitdo --mock` - Gatekeeper friction is expected and must be documented.
- Install `.pkg`, then run `/opt/homebrew/bin/openbitdo --mock` - Tarball and standalone binary remain the fallback paths.
- Confirm launch and settings view behavior
## Help Surface Verification ## Manual Smoke Expectations
- `openbitdo --help` shows single-command usage with `--mock`.
## Distribution Readiness Notes 1. Linux `x86_64`: launch `openbitdo --mock`
- Homebrew publication runs after release asset publish when `HOMEBREW_PUBLISH_ENABLED=1`. 2. Linux `aarch64`: launch `openbitdo --mock`
- AUR publication runs after release asset publish when `AUR_PUBLISH_ENABLED=1`. 3. macOS arm64 standalone binary: launch `openbitdo --mock`
- Both package paths use release-derived SHA256 values (no `SKIP`, no `:no_check` in published metadata). 4. macOS arm64 `.pkg`: confirm payload installation path and launch behavior where possible
## Current Status Snapshot
## RC Gate Snapshot (Local)
| Gate | Status | Notes | | Gate | Status | Notes |
| --- | --- | --- | | --- | --- | --- |
| Clean tree | Pass | Verified empty on `c3115da` before final checklist update (`git status --porcelain`). | | Required CI checks | Pass | Current required checks are configured in GitHub branch protection. |
| Secrets present | Pass | `AUR_USERNAME`, `AUR_SSH_PRIVATE_KEY`, `HOMEBREW_TAP_TOKEN` exist in repo secrets. | | GitHub prerelease assets | Pending | Verify `v0.0.1-rc.4` assets after the tag workflow completes. |
| Required checks configured | Pass | `guard`, `test`, `tui-smoke-test`, `aur-validate`, `build-macos-arm64`. | | AUR publication | Pending | Verify `openbitdo-bin` updates to `v0.0.1-rc.4` after release publication. |
| Open release-blocker issues | Pass | `0` open (`gh issue list --label release-blocker --state open`). | | Homebrew publication | Pending | Verify `bybrooklyn/homebrew-openbitdo` updates to `v0.0.1-rc.4` after release publication. |
| RC release allowed | Fail | `No` yet: AUR SSH auth still returns `Permission denied (publickey)`. | | macOS notarization | Deferred | Explicitly out of scope until Apple credentials exist. |
## RC Execution Log ## Historical Notes
Historical note: entries below may mention older command forms from prior milestones and are preserved as-is for audit history.
- 2026-03-02T20:54:31Z: governance preflight complete; release blocker remains open by policy. - Historical RC activity for earlier candidates is preserved in commit history and the changelog.
- 2026-03-02T21:38:17Z: set `HOMEBREW_TAP_REPO=bybrooklyn/homebrew-openbitdo`; repository and tap visibility switched to public. - Troubleshooting for AUR SSH publication lives in `process/aur_publish_troubleshooting.md`.
- 2026-03-02T21:40:00Z: bootstrapped tap repo `bybrooklyn/homebrew-openbitdo` with initial `Formula/openbitdo.rb`.
- 2026-03-02T21:45:27Z to 2026-03-02T21:48:55Z: CI run `22597105846` on commit `c3115da` passed `guard`, `test`, `tui-smoke-test`, `aur-validate`, `build-macos-arm64`, `build-linux-x86_64`, and `build-linux-aarch64`.
- 2026-03-02T21:49:00Z to 2026-03-02T21:55:00Z: downloaded CI artifacts and manually verified each artifact hash against `.sha256` content (all matched) for:
- `openbitdo-v0.0.0-ci-linux-x86_64.tar.gz`
- `openbitdo-v0.0.0-ci-linux-x86_64`
- `openbitdo-v0.0.0-ci-linux-aarch64.tar.gz`
- `openbitdo-v0.0.0-ci-linux-aarch64`
- `openbitdo-v0.0.0-ci-macos-arm64.tar.gz`
- `openbitdo-v0.0.0-ci-macos-arm64`
- `openbitdo-v0.0.0-ci-macos-arm64.pkg`
- 2026-03-02T21:56:00Z to 2026-03-02T22:00:00Z: Linux artifact smoke completed in containers for `linux/amd64` and `linux/arm64` by launching `openbitdo --mock` and observing successful TUI startup.
- 2026-03-02T21:57:00Z: local macOS packaging smoke completed via `./sdk/scripts/package-macos.sh v0.0.0-local arm64` (tarball, standalone binary, pkg generated).
- 2026-03-02T21:58:00Z: local standalone macOS smoke completed (`openbitdo-v0.0.0-local-macos-arm64 --mock`) with TUI startup and clean exit via scripted key input.
- 2026-03-02T21:59:00Z: pkg payload path validated by expansion (`Payload/opt/homebrew/bin/openbitdo`); direct installer invocation requires root (`installer: Must be run as root to install this package`).
- 2026-03-02T21:59:30Z: About behavior validated by test run `cargo test -p bitdo_tui about_state_roundtrip_returns_home`.
- 2026-03-02T22:02:00Z: Wave 2 issues `#2` through `#13` closed with per-issue evidence comments.
- 2026-03-02T22:03:00Z: epic issue `#1` closed and `release-blocker` label removed after child closure summary.
- 2026-03-02T22:04:00Z: clean-tree gate confirmed on baseline commit `c3115da` (`git status --porcelain` empty).
- 2026-03-02T22:10:00Z: removed hardware self-hosted checks from branch protection and CI/release gate policy.

211
README.md
View File

@@ -1,185 +1,62 @@
# OpenBitdo # OpenBitdo
OpenBitdo is a clean-room implementation workspace for beginner-friendly 8BitDo tooling. OpenBitdo is a clean-room, beginner-first 8BitDo utility built around a modern terminal UI.
OpenBitDo is an unofficial tool and should be used at your own risk. The authors are not responsible for device damage, firmware corruption, or data loss. This project is not affiliated with or endorsed by 8BitDo. See the [LICENSE](/Users/brooklyn/data/8bitdo/cleanroom/LICENSE) file for details. It focuses on safe diagnostics first, guided firmware/update flows for confirmed devices, and clear blocked-action messaging for devices that are still under investigation.
## Beginner Quickstart OpenBitdo is unofficial and not affiliated with 8BitDo. Firmware updates and device changes always carry risk. Read the prompts carefully and keep backups or recovery plans where available.
From `/Users/brooklyn/data/8bitdo/cleanroom/sdk`:
```bash ## What OpenBitdo Does Today
cargo run -p openbitdo --
```
Optional mock mode: - Detect connected 8BitDo devices and explain their current support level.
- Run diagnostics and save support reports.
- Stage verified firmware updates on full-support devices.
- Edit supported mappings for the currently confirmed JP108 and Ultimate 2 flows.
- Keep unconfirmed devices in safe read-only or detect-only paths.
```bash ## Install
cargo run -p openbitdo -- --mock
```
`openbitdo` launches the interactive dashboard directly. | Path | Command | Best for |
## Install (Public RC)
Homebrew tap install path for RC:
```bash
brew tap bybrooklyn/openbitdo
brew install openbitdo
```
Homebrew Core inclusion (`brew install openbitdo` without tapping) is not an RC blocker and may land later.
AUR package names:
- `openbitdo-bin` (prebuilt binary)
macOS RC caveat:
- `.pkg` installers are unsigned/ad-hoc for `v0.0.1-rc.2`.
- notarization is required starting with `v0.1.0`.
## UI Language Support
| Language | Status | Notes |
| --- | --- | --- | | --- | --- | --- |
| English | Supported | Default and primary beginner flow language. | | Homebrew | `brew tap bybrooklyn/openbitdo && brew install openbitdo` | macOS or Linux users who want the standard tap flow |
| Spanish | In Progress | Roadmap item for core wizard screens. | | AUR | `paru -S openbitdo-bin` | Arch Linux users who want a prebuilt package |
| Japanese | Planned | Planned after Spanish stabilization. | | GitHub Releases | Download a release tarball and run `bin/openbitdo` | Users who want a standalone binary without a package manager |
| German | Planned | Planned after Spanish stabilization. | | From source | `cargo run -p openbitdo --` from `sdk/` | Contributors and local development |
| French | Planned | Planned after Spanish stabilization. |
## Support Status Model ## First Run
| Runtime Tier | README Status | Meaning | 1. Launch `openbitdo`.
| --- | --- | --- | 2. If you do not have hardware attached yet, launch `openbitdo --mock` to preview the interface.
| `full` | Supported | Mapping/update paths allowed when safety gates are satisfied. | 3. Pick a controller from the dashboard.
| `candidate-readonly` | In Progress | Detect/identify/diagnostics enabled, writes and firmware transfer blocked. | 4. Use `Diagnose` first if you are unsure what is safe for that device.
| `detect-only` | Planned | Detect/identify baseline now, broader functionality planned. | 5. Follow the support-tier guidance shown in the UI before attempting update or mapping work.
Beginner UI note: candidate devices are shown with blocked-action messaging in the TUI so new users always see the safe path first. ## Support Tiers
## Protocol Family Overview | Tier | What it means |
| --- | --- |
| `supported` | Diagnostics, update, and any confirmed mapping flows are available when safety gates are satisfied. |
| `read-only candidate` | Diagnostics are available, but update and mapping stay blocked until runtime and hardware confirmation are complete. |
| `detect-only` | OpenBitdo can identify the device, but deeper workflows are intentionally unavailable. |
| Family | PID Rows | Notes | ## macOS Packaging Caveat
| --- | --- | --- |
| Standard64 | 36 | Largest family, mixed status from Planned to Supported. |
| DInput | 11 | Includes current full-support Ultimate2 and Pro3 lines. |
| JpHandshake | 9 | Includes JP108 full support and keyboard-related candidate lines. |
| DS4Boot | 0 | No standalone canonical PID rows in current catalog. |
| Unknown | 1 | Sentinel/internal row only. |
DS4Boot explicit note: there are currently no active canonical PID rows in this catalog. Current macOS release artifacts are unsigned and non-notarized.
That means Gatekeeper friction is expected for the `.pkg`, tarball, and standalone binary.
If the installer path is inconvenient, use the extracted tarball or Homebrew tap as the fallback path.
Apple Developer signing and notarization are deferred until credentials are available.
## Compatibility Verification Dates (Manual, ISO) ## Release And Package Map
| Family | Last verified date | Notes |
| --- | --- | --- |
| Standard64 | 2026-03-02 | Manual RC verification date. |
| DInput | 2026-03-02 | Manual RC verification date. |
| JpHandshake | 2026-03-02 | Manual RC verification date. |
| DS4Boot | 2026-03-02 | No active canonical rows. |
| Unknown | 2026-03-02 | Sentinel/internal row only. |
## Device Compatibility (Canonical, No Duplicate PIDs) - GitHub prereleases publish the canonical release assets.
Device naming references are documented in [device_name_catalog.md](/Users/brooklyn/data/8bitdo/cleanroom/spec/device_name_catalog.md) and [device_name_sources.md](/Users/brooklyn/data/8bitdo/cleanroom/process/device_name_sources.md). - AUR publishes `openbitdo-bin` from the Linux tarballs and release-derived checksums.
- Homebrew publishes through the separate tap repo `bybrooklyn/homebrew-openbitdo`.
- Package-manager metadata is rendered from published assets so release checksums stay authoritative.
### Unknown ## Where To Go Next
| Canonical ID | Display Name | PID (hex) | Family | Status | Current User Actions | Firmware Path | Notes | - Developer and release-engineering details: [sdk/README.md](sdk/README.md)
| --- | --- | --- | --- | --- | --- | --- | --- | - Current RC release gate: [RC_CHECKLIST.md](RC_CHECKLIST.md)
| `PID_None` | No Device (Sentinel) | `0x0000` | Unknown | Planned | None | N/A | Internal sentinel row only. | - Changelog and release notes: [CHANGELOG.md](CHANGELOG.md)
- CLI and packaging migration notes: [MIGRATION.md](MIGRATION.md)
### Standard64 - Device catalog: [spec/device_name_catalog.md](spec/device_name_catalog.md)
- Protocol overview: [spec/protocol_spec.md](spec/protocol_spec.md)
| Canonical ID | Display Name | PID (hex) | Family | Status | Current User Actions | Firmware Path | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `PID_IDLE` | Unconfirmed Internal Device (PID_IDLE) | `0x3109` | Standard64 | Planned | Detect, identify | Blocked | Internal interface row. |
| `PID_SN30Plus` | SN30 Pro+ | `0x6002` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_USB_Ultimate` | Unconfirmed Internal Device (PID_USB_Ultimate) | `0x3100` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_USB_Ultimate2` | Unconfirmed Internal Device (PID_USB_Ultimate2) | `0x3105` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_USB_UltimateClasses` | Unconfirmed Internal Device (PID_USB_UltimateClasses) | `0x3104` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_Xcloud` | Unconfirmed Internal Device (PID_Xcloud) | `0x2100` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Xcloud2` | Unconfirmed Internal Device (PID_Xcloud2) | `0x2101` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_ArcadeStick` | Arcade Stick | `0x901a` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Pro2` | Pro 2 Bluetooth Controller | `0x6003` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Pro2_CY` | Unconfirmed Variant Name (PID_Pro2_CY) | `0x6006` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Pro2_Wired` | Pro 2 Wired Controller | `0x3010` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Ultimate_PC` | Ultimate PC Controller | `0x3011` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Ultimate2_4` | Ultimate 2.4G Controller | `0x3012` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Ultimate2_4RR` | Ultimate 2.4G Adapter | `0x3013` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_UltimateBT` | Ultimate Wireless Controller | `0x6007` | Standard64 | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_UltimateBTRR` | Ultimate Wireless Adapter | `0x3106` | Standard64 | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_NUMPAD` | Retro 18 Mechanical Numpad | `0x5203` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_NUMPADRR` | Retro 18 Adapter | `0x5204` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Pro3DOCK` | Charging Dock for Pro 3S Gamepad | `0x600d` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_NGCDIY` | Mod Kit for NGC Controller | `0x5750` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_NGCRR` | Retro Receiver for NGC | `0x902a` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_Mouse` | Retro R8 Mouse | `0x5205` | Standard64 | Planned | Detect, identify | Blocked | Canonical row for `0x5205`. |
| `PID_MouseRR` | Retro R8 Adapter | `0x5206` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_SaturnRR` | Retro Receiver for Saturn | `0x902b` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_UltimateBT2C` | Ultimate 2C Bluetooth Controller | `0x301a` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_Lashen` | Ultimate Mobile Gaming Controller | `0x301e` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_N64BT` | 64 Bluetooth Controller | `0x3019` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_N64` | 64 2.4G Wireless Controller | `0x3004` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_N64RR` | Retro Receiver for N64 | `0x9028` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_XBOXUK` | Retro 87 Mechanical Keyboard - Xbox (UK) | `0x3026` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_XBOXUKUSB` | Retro 87 Mechanical Keyboard Adapter - Xbox (UK) | `0x3027` | Standard64 | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_LashenX` | Ultimate Mobile Gaming Controller For Xbox | `0x200b` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_N64JoySticks` | Joystick v2 for N64 Controller | `0x3021` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_DoubleSuper` | Wireless Dual Super Button | `0x203e` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_Cube2RR` | Retro Cube 2 Adapter - N Edition | `0x2056` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_Cube2` | Retro Cube 2 Speaker - N Edition | `0x2039` | Standard64 | Planned | Detect, identify | Blocked | Planned support only. |
### JpHandshake
| Canonical ID | Display Name | PID (hex) | Family | Status | Current User Actions | Firmware Path | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `PID_JP` | Retro Mechanical Keyboard | `0x5200` | JpHandshake | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_JPUSB` | Retro Mechanical Keyboard Receiver | `0x5201` | JpHandshake | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_108JP` | Retro 108 Mechanical Keyboard | `0x5209` | JpHandshake | Supported | Detect, diagnose, dedicated mapping (`A/B/K1-K8`), recommended update | Stable download + local fallback | Full-support JP108 flow. |
| `PID_108JPUSB` | Retro 108 Mechanical Adapter | `0x520a` | JpHandshake | Supported | Detect, diagnose, dedicated mapping (`A/B/K1-K8`), recommended update | Stable download + local fallback | Full-support JP108 receiver flow. |
| `PID_XBOXJP` | Retro 87 Mechanical Keyboard - Xbox Edition | `0x2028` | JpHandshake | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_XBOXJPUSB` | Retro 87 Mechanical Keyboard Adapter - Xbox Edition | `0x202e` | JpHandshake | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_68JP` | Retro 68 Keyboard - N40 | `0x203a` | JpHandshake | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_68JPUSB` | Retro 68 Keyboard Adapter - N40 | `0x2049` | JpHandshake | In Progress | Detect, identify, diagnose | Blocked (`NotHardwareConfirmed`) | Candidate read-only. |
| `PID_ASLGJP` | Riviera Keyboard | `0x205a` | JpHandshake | Planned | Detect, identify | Blocked | Planned support only. |
### DInput
| Canonical ID | Display Name | PID (hex) | Family | Status | Current User Actions | Firmware Path | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `PID_QINGCHUN2` | Ultimate 2C Controller | `0x310a` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_QINGCHUN2RR` | Ultimate 2C Wireless Adapter | `0x301c` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_Xinput` | Unconfirmed Interface Name (PID_Xinput) | `0x310b` | DInput | Planned | Detect, identify | Blocked | Planned support only. |
| `PID_Pro3` | Pro 3 Bluetooth Gamepad | `0x6009` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_Pro3USB` | Pro 3 Bluetooth Adapter | `0x600a` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_Ultimate2` | Ultimate 2 Wireless Controller | `0x6012` | DInput | Supported | Detect, diagnose, slot mapping (`A/B/K1-K8`), analog L2/R2, recommended update | Stable download + local fallback | Full-support Ultimate2 RC scope (known controller-button targets). |
| `PID_Ultimate2RR` | Ultimate 2 Wireless Adapter | `0x6013` | DInput | Supported | Detect, diagnose, slot mapping (`A/B/K1-K8`), analog L2/R2, recommended update | Stable download + local fallback | Full-support Ultimate2 receiver RC scope (known controller-button targets). |
| `PID_UltimateBT2` | Ultimate 2 Bluetooth Controller | `0x600f` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_UltimateBT2RR` | Ultimate 2 Bluetooth Adapter | `0x6011` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_HitBox` | Arcade Controller | `0x600b` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
| `PID_HitBoxRR` | Arcade Controller Adapter | `0x600c` | DInput | Supported | Detect, diagnose, recommended update | Stable download + local fallback | Full-support runtime. |
## Alias Appendix (Non-Canonical Names)
These aliases are intentionally excluded from canonical PID rows to guarantee uniqueness.
| Alias PID Name | Canonical PID Name | PID (hex) |
| --- | --- | --- |
| `PID_Pro2_OLD` | `PID_Pro2` | `0x6003` |
| `PID_ASLGMouse` | `PID_Mouse` | `0x5205` |
See [alias_index.md](/Users/brooklyn/data/8bitdo/cleanroom/spec/alias_index.md) for details.
## Hardware Support Confidence
Support is implemented to our best current knowledge. Coverage and confidence are expanded and confirmed over time through community testing and hardware reports.
## Dirty-Room Evidence Backlog
- [dirtyroom_evidence_backlog.md](/Users/brooklyn/data/8bitdo/cleanroom/process/dirtyroom_evidence_backlog.md)
- [dirtyroom_collection_playbook.md](/Users/brooklyn/data/8bitdo/cleanroom/process/dirtyroom_collection_playbook.md)
- [dirtyroom_dossier_schema.md](/Users/brooklyn/data/8bitdo/cleanroom/process/dirtyroom_dossier_schema.md)
- [community_evidence_intake.md](/Users/brooklyn/data/8bitdo/cleanroom/process/community_evidence_intake.md)
## Source Notes
- Canonical clean-room naming catalog: [device_name_catalog.md](/Users/brooklyn/data/8bitdo/cleanroom/spec/device_name_catalog.md)
- Dirty-room source index + official web cross-check URLs: [device_name_sources.md](/Users/brooklyn/data/8bitdo/cleanroom/process/device_name_sources.md)
## Public RC Gate
The next RC remains blocked until release-blocker issues are zero and all required checks are green.
RC gating is checklist-based (see [RC_CHECKLIST.md](/Users/brooklyn/data/8bitdo/cleanroom/RC_CHECKLIST.md)).

View File

@@ -1,17 +1,22 @@
# AUR Packaging # AUR Packaging
This directory contains AUR package sources for: This directory holds the tracked AUR source for `openbitdo-bin`.
- `openbitdo-bin` (prebuilt release assets)
Publishing is automated by `.github/workflows/aur-publish.yml` and remains gated: ## Source Of Truth
- requires repository variable `AUR_PUBLISH_ENABLED=1`
- requires secrets `AUR_SSH_PRIVATE_KEY` and `AUR_USERNAME`
Publish flow: - tracked metadata: `packaging/aur/openbitdo-bin/PKGBUILD` and `.SRCINFO`
1. wait for release assets from a `v*` tag - template: `packaging/aur/openbitdo-bin/PKGBUILD.tmpl`
2. compute authoritative SHA256 values from released artifacts - renderer: `packaging/scripts/render_release_metadata.sh`
3. render `PKGBUILD`/`.SRCINFO` with pinned hashes
4. push updates to AUR repo
Template files used for release rendering: ## Publish Flow
- `openbitdo-bin/PKGBUILD.tmpl`
1. Publish GitHub release assets for a `v*` tag.
2. Render `PKGBUILD` and `.SRCINFO` from those assets.
3. Upload rendered metadata as a workflow artifact for audit.
4. Push the updated metadata to the AUR repo for `openbitdo-bin`.
## Required Controls
- repo variable `AUR_PUBLISH_ENABLED=1`
- secrets `AUR_USERNAME` and `AUR_SSH_PRIVATE_KEY`
- no placeholder checksums in published metadata

View File

@@ -1,15 +1,15 @@
pkgbase = openbitdo-bin pkgbase = openbitdo-bin
pkgdesc = Prebuilt beginner-first clean-room 8BitDo utility pkgdesc = Prebuilt beginner-first clean-room 8BitDo utility
pkgver = 0.0.1rc1 pkgver = 0.0.1rc3
pkgrel = 1 pkgrel = 1
url = https://github.com/bybrooklyn/openbitdo url = https://github.com/bybrooklyn/openbitdo
arch = x86_64 arch = x86_64
arch = aarch64 arch = aarch64
license = BSD-3-Clause license = BSD-3-Clause
depends = hidapi depends = hidapi
source_x86_64 = openbitdo-v0.0.1-rc.1-linux-x86_64.tar.gz::https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.1/openbitdo-v0.0.1-rc.1-linux-x86_64.tar.gz source_x86_64 = openbitdo-v0.0.1-rc.3-linux-x86_64.tar.gz::https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.3/openbitdo-v0.0.1-rc.3-linux-x86_64.tar.gz
sha256sums_x86_64 = 0000000000000000000000000000000000000000000000000000000000000000 sha256sums_x86_64 = fa7ae583796dc979a64eaeb670a06fc7c10fd51bbb12fce5815d66629e18c9a0
source_aarch64 = openbitdo-v0.0.1-rc.1-linux-aarch64.tar.gz::https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.1/openbitdo-v0.0.1-rc.1-linux-aarch64.tar.gz source_aarch64 = openbitdo-v0.0.1-rc.3-linux-aarch64.tar.gz::https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.3/openbitdo-v0.0.1-rc.3-linux-aarch64.tar.gz
sha256sums_aarch64 = 0000000000000000000000000000000000000000000000000000000000000000 sha256sums_aarch64 = 992586ff89da6dfdb137fd424f651ccedb4a65de0f43d615cda682e31e222dd0
pkgname = openbitdo-bin pkgname = openbitdo-bin

View File

@@ -1,16 +1,16 @@
pkgname=openbitdo-bin pkgname=openbitdo-bin
pkgver=0.0.1rc1 pkgver=0.0.1rc3
_upstream_tag=v0.0.1-rc.1 _upstream_tag=v0.0.1-rc.3
pkgrel=1 pkgrel=1
pkgdesc="Prebuilt beginner-first clean-room 8BitDo utility" pkgdesc="Open source 8BitDo utility"
arch=('x86_64' 'aarch64') arch=('x86_64' 'aarch64')
url="https://github.com/bybrooklyn/openbitdo" url="https://github.com/bybrooklyn/openbitdo"
license=('BSD-3-Clause') license=('BSD-3-Clause')
depends=('hidapi') depends=('hidapi')
source_x86_64=("openbitdo-${_upstream_tag}-linux-x86_64.tar.gz::${url}/releases/download/${_upstream_tag}/openbitdo-${_upstream_tag}-linux-x86_64.tar.gz") source_x86_64=("openbitdo-${_upstream_tag}-linux-x86_64.tar.gz::${url}/releases/download/${_upstream_tag}/openbitdo-${_upstream_tag}-linux-x86_64.tar.gz")
source_aarch64=("openbitdo-${_upstream_tag}-linux-aarch64.tar.gz::${url}/releases/download/${_upstream_tag}/openbitdo-${_upstream_tag}-linux-aarch64.tar.gz") source_aarch64=("openbitdo-${_upstream_tag}-linux-aarch64.tar.gz::${url}/releases/download/${_upstream_tag}/openbitdo-${_upstream_tag}-linux-aarch64.tar.gz")
sha256sums_x86_64=('0000000000000000000000000000000000000000000000000000000000000000') sha256sums_x86_64=('fa7ae583796dc979a64eaeb670a06fc7c10fd51bbb12fce5815d66629e18c9a0')
sha256sums_aarch64=('0000000000000000000000000000000000000000000000000000000000000000') sha256sums_aarch64=('992586ff89da6dfdb137fd424f651ccedb4a65de0f43d615cda682e31e222dd0')
package() { package() {
local extracted_dir local extracted_dir

View File

@@ -1,33 +0,0 @@
class Openbitdo < Formula
desc "Beginner-first clean-room 8BitDo TUI utility"
homepage "https://github.com/bybrooklyn/openbitdo"
license "BSD-3-Clause"
version "0.0.1-rc.1"
on_macos do
if Hardware::CPU.arm?
url "https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.1/openbitdo-v0.0.1-rc.1-macos-arm64.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
end
end
on_linux do
if Hardware::CPU.intel?
url "https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.1/openbitdo-v0.0.1-rc.1-linux-x86_64.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
elsif Hardware::CPU.arm?
url "https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.1/openbitdo-v0.0.1-rc.1-linux-aarch64.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
end
end
# Release automation rewrites checksums in the tap with authoritative values
# from published assets.
def install
bin.install "bin/openbitdo"
end
test do
assert_match "openbitdo", shell_output("#{bin}/openbitdo --help")
end
end

View File

@@ -1,14 +1,24 @@
# Homebrew Packaging # Homebrew Packaging
Formula source lives in `Formula/openbitdo.rb`. Homebrew publishing uses the separate tap repo `bybrooklyn/homebrew-openbitdo`.
Template source used for release rendering: `Formula/openbitdo.rb.tmpl`.
Planned tap: ## Source Of Truth
- `bybrooklyn/homebrew-openbitdo`
Current status: - template: `packaging/homebrew/Formula/openbitdo.rb.tmpl`
- release workflow computes checksum-pinned formula values from published assets - renderer: `packaging/scripts/render_release_metadata.sh`
- tap sync remains gated by `HOMEBREW_PUBLISH_ENABLED=1` - sync helper: `packaging/homebrew/sync_tap.sh`
Optional sync helper: The main repo does not keep a checked-in rendered formula. Release rendering produces the formula from published assets, and the tap repo is the canonical published destination.
- `sync_tap.sh` (disabled by default unless `HOMEBREW_PUBLISH_ENABLED=1`)
## Publish Flow
1. Publish GitHub release assets for a `v*` tag.
2. Render a checksum-pinned formula from those assets.
3. Upload the rendered formula as a workflow artifact for audit.
4. Sync the rendered formula to `bybrooklyn/homebrew-openbitdo`.
## Required Controls
- repo variable `HOMEBREW_PUBLISH_ENABLED=1`
- repo variable `HOMEBREW_TAP_REPO=bybrooklyn/homebrew-openbitdo`
- secret `HOMEBREW_TAP_TOKEN`

View File

@@ -23,9 +23,22 @@ HOMEBREW_TAP_TOKEN="$(
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TAP_REPO="${HOMEBREW_TAP_REPO:-bybrooklyn/homebrew-openbitdo}" TAP_REPO="${HOMEBREW_TAP_REPO:-bybrooklyn/homebrew-openbitdo}"
FORMULA_SOURCE="${FORMULA_SOURCE:-$ROOT/packaging/homebrew/Formula/openbitdo.rb}" FORMULA_SOURCE="${FORMULA_SOURCE:-}"
TMP="$(mktemp -d)" TMP="$(mktemp -d)"
decode_base64() {
if base64 --help 2>/dev/null | grep -q -- "--decode"; then
base64 --decode
else
base64 -D
fi
}
if [[ -z "$FORMULA_SOURCE" ]]; then
echo "FORMULA_SOURCE must point to a rendered formula; run render_release_metadata.sh first" >&2
exit 1
fi
if [[ ! -f "$FORMULA_SOURCE" ]]; then if [[ ! -f "$FORMULA_SOURCE" ]]; then
echo "formula source not found: $FORMULA_SOURCE" >&2 echo "formula source not found: $FORMULA_SOURCE" >&2
exit 1 exit 1
@@ -69,7 +82,7 @@ remote_content_file="$TMP/remote_formula.rb"
if api_with_fallback "repos/${TAP_REPO}/contents/${formula_path}?ref=main" >"$TMP/remote.json" 2>/dev/null; then if api_with_fallback "repos/${TAP_REPO}/contents/${formula_path}?ref=main" >"$TMP/remote.json" 2>/dev/null; then
remote_sha="$(jq -r '.sha // ""' "$TMP/remote.json")" remote_sha="$(jq -r '.sha // ""' "$TMP/remote.json")"
jq -r '.content // ""' "$TMP/remote.json" | tr -d '\n' | base64 --decode >"$remote_content_file" jq -r '.content // ""' "$TMP/remote.json" | tr -d '\n' | decode_base64 >"$remote_content_file"
if cmp -s "$FORMULA_SOURCE" "$remote_content_file"; then if cmp -s "$FORMULA_SOURCE" "$remote_content_file"; then
echo "no formula changes to push" echo "no formula changes to push"
exit 0 exit 0

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
MOCK_BIN="$TMP/bin"
mkdir -p "$MOCK_BIN"
cat >"$MOCK_BIN/gh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
STATE_DIR="${MOCK_GH_STATE_DIR:?}"
if [[ "${1:-}" != "api" ]]; then
echo "mock gh only supports api" >&2
exit 1
fi
shift
method="GET"
if [[ "${1:-}" == "--method" ]]; then
method="$2"
shift 2
fi
endpoint="$1"
shift
case "${method}:${endpoint}" in
GET:repos/*/contents/Formula/openbitdo.rb\?ref=main)
if [[ -f "$STATE_DIR/remote_formula.rb" ]]; then
content="$(base64 < "$STATE_DIR/remote_formula.rb" | tr -d '\n')"
printf '{"sha":"remote-sha","content":"%s"}\n' "$content"
exit 0
fi
exit 1
;;
PUT:repos/*/contents/Formula/openbitdo.rb)
content=""
while [[ $# -gt 0 ]]; do
if [[ "$1" == "-f" ]]; then
case "$2" in
content=*)
content="${2#content=}"
;;
esac
shift 2
else
shift
fi
done
printf '%s' "$content" | base64 --decode >"$STATE_DIR/updated_formula.rb"
echo "put" >>"$STATE_DIR/requests.log"
printf '{"content":{"sha":"new-sha"}}\n'
;;
*)
echo "unexpected mock gh call: ${method} ${endpoint}" >&2
exit 1
;;
esac
EOF
chmod +x "$MOCK_BIN/gh"
FORMULA_SOURCE="$TMP/openbitdo.rb"
cat >"$FORMULA_SOURCE" <<'EOF'
class Openbitdo < Formula
desc "OpenBitdo"
end
EOF
run_sync() {
PATH="$MOCK_BIN:$PATH" \
MOCK_GH_STATE_DIR="$TMP/mock-state" \
GH_TOKEN="job-token" \
HOMEBREW_TAP_TOKEN="tap-token" \
HOMEBREW_TAP_REPO="bybrooklyn/homebrew-openbitdo" \
HOMEBREW_PUBLISH_ENABLED="1" \
FORMULA_SOURCE="$FORMULA_SOURCE" \
bash "$ROOT/packaging/homebrew/sync_tap.sh"
}
mkdir -p "$TMP/mock-state"
cp "$FORMULA_SOURCE" "$TMP/mock-state/remote_formula.rb"
run_sync >"$TMP/noop.out"
grep -Fq "no formula changes to push" "$TMP/noop.out"
test ! -f "$TMP/mock-state/updated_formula.rb"
cat >"$TMP/mock-state/remote_formula.rb" <<'EOF'
class Openbitdo < Formula
desc "Old formula"
end
EOF
run_sync >"$TMP/update.out"
grep -Fq "updated bybrooklyn/homebrew-openbitdo:Formula/openbitdo.rb" "$TMP/update.out"
cmp -s "$FORMULA_SOURCE" "$TMP/mock-state/updated_formula.rb"

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
sha256() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
else
shasum -a 256 "$1" | awk '{print $1}'
fi
}
INPUT_DIR="$TMP/input"
OUTPUT_DIR="$TMP/output"
mkdir -p "$INPUT_DIR"
printf 'x86_64 archive payload\n' >"$INPUT_DIR/openbitdo-v0.0.1-rc.4-linux-x86_64.tar.gz"
printf 'aarch64 archive payload\n' >"$INPUT_DIR/openbitdo-v0.0.1-rc.4-linux-aarch64.tar.gz"
printf 'macos archive payload\n' >"$INPUT_DIR/openbitdo-v0.0.1-rc.4-macos-arm64.tar.gz"
bash "$ROOT/packaging/scripts/render_release_metadata.sh" \
"v0.0.1-rc.4" \
"bybrooklyn/openbitdo" \
"$INPUT_DIR" \
"$OUTPUT_DIR"
PKGBUILD="$OUTPUT_DIR/aur/openbitdo-bin/PKGBUILD"
FORMULA="$OUTPUT_DIR/homebrew/Formula/openbitdo.rb"
CHECKSUMS="$OUTPUT_DIR/checksums.env"
test -f "$PKGBUILD"
test -f "$FORMULA"
test -f "$CHECKSUMS"
expected_x86="$(sha256 "$INPUT_DIR/openbitdo-v0.0.1-rc.4-linux-x86_64.tar.gz")"
expected_aarch64="$(sha256 "$INPUT_DIR/openbitdo-v0.0.1-rc.4-linux-aarch64.tar.gz")"
expected_macos="$(sha256 "$INPUT_DIR/openbitdo-v0.0.1-rc.4-macos-arm64.tar.gz")"
grep -Fq "pkgver=0.0.1rc4" "$PKGBUILD"
grep -Fq "_upstream_tag=v0.0.1-rc.4" "$PKGBUILD"
grep -Fq "sha256sums_x86_64=('${expected_x86}')" "$PKGBUILD"
grep -Fq "sha256sums_aarch64=('${expected_aarch64}')" "$PKGBUILD"
grep -Fq 'version "0.0.1-rc.4"' "$FORMULA"
grep -Fq "sha256 \"${expected_x86}\"" "$FORMULA"
grep -Fq "sha256 \"${expected_aarch64}\"" "$FORMULA"
grep -Fq "sha256 \"${expected_macos}\"" "$FORMULA"
grep -Fq 'https://github.com/bybrooklyn/openbitdo/releases/download/v0.0.1-rc.4/openbitdo-v0.0.1-rc.4-linux-x86_64.tar.gz' "$FORMULA"
if grep -nE '@[A-Z0-9_]+@' "$PKGBUILD" "$FORMULA"; then
echo "rendered metadata still contains template placeholders" >&2
exit 1
fi
grep -Fq "TAG=v0.0.1-rc.4" "$CHECKSUMS"
grep -Fq "VERSION=0.0.1-rc.4" "$CHECKSUMS"
grep -Fq "AUR_PKGVER=0.0.1rc4" "$CHECKSUMS"
grep -Fq "LINUX_X86_64_SHA256=${expected_x86}" "$CHECKSUMS"
grep -Fq "LINUX_AARCH64_SHA256=${expected_aarch64}" "$CHECKSUMS"
grep -Fq "MACOS_ARM64_SHA256=${expected_macos}" "$CHECKSUMS"

View File

@@ -1,68 +1,37 @@
# Add Device Support (Hardcoded Path) # Add Device Support
This guide keeps device support simple and explicit: everything is added directly in Rust code. This guide describes the clean-room path for adding or promoting a device.
## 1) Add/verify PID in hardcoded registry ## Update The Runtime Catalog
File:
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/crates/bitdo_proto/src/pid_registry_table.rs`
Add a `PidRegistryRow` with: 1. Add or verify the PID row in `sdk/crates/bitdo_proto/src/pid_registry_table.rs`.
- `name` 2. Update capability defaults and support-tier policy in `sdk/crates/bitdo_proto/src/registry.rs`.
- `pid` 3. Add or verify command rows in `sdk/crates/bitdo_proto/src/command_registry_table.rs`.
- `support_level` 4. Update candidate-readonly gating in `sdk/crates/bitdo_proto/src/session.rs` when the new PID needs safe-read diagnostics.
- `support_tier`
- `protocol_family`
## 2) Update capability policy ## Update The Sanitized Evidence
File:
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/crates/bitdo_proto/src/registry.rs`
Update `default_capability_for(...)` and support-tier PID lists so capability flags match evidence. Keep the spec and evidence artifacts aligned:
## 3) Add/verify command declarations - `spec/device_name_catalog.md`
File: - `spec/protocol_spec.md`
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/crates/bitdo_proto/src/command_registry_table.rs` - `process/device_name_sources.md`
- dossier and matrix artifacts where applicable
Add/verify command rows: ## Update Tests
- `id`
- `safety_class`
- `confidence`
- `experimental_default`
- `report_id`
- `request`
- `expected_response`
- `applies_to`
- `operation_group`
## 4) Confirm runtime policy At minimum, touch the tests that prove:
Runtime policy is derived in code (not scripts):
- `confirmed` -> enabled by default
- inferred `SafeRead` -> experimental-gated
- inferred `SafeWrite`/unsafe -> blocked until confirmed
File: - support-tier gating is correct
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/crates/bitdo_proto/src/registry.rs` - command/runtime policy is correct
- diagnostics or mapping behavior is correct for the new device family
## 5) Update candidate gating allowlists ## Validation
File:
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/crates/bitdo_proto/src/session.rs`
Update `is_command_allowed_for_candidate_pid(...)` so detect/diag behavior for the new PID is explicit. From `cleanroom/sdk`:
## 6) Keep spec artifacts in sync ```bash
Files: ./scripts/cleanroom_guard.sh
- `/Users/brooklyn/data/8bitdo/cleanroom/spec/pid_matrix.csv` cargo clippy --workspace --all-targets -- -D warnings
- `/Users/brooklyn/data/8bitdo/cleanroom/spec/command_matrix.csv` cargo test --workspace --all-targets
- `/Users/brooklyn/data/8bitdo/cleanroom/spec/evidence_index.csv` ```
- `/Users/brooklyn/data/8bitdo/cleanroom/spec/dossiers/...`
## 7) Add tests
- Extend candidate gating tests:
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/tests/candidate_readonly_gating.rs`
- Extend runtime policy tests:
- `/Users/brooklyn/data/8bitdo/cleanroom/sdk/tests/runtime_policy.rs`
## 8) Validation
From `/Users/brooklyn/data/8bitdo/cleanroom/sdk`:
- `cargo test --workspace --all-targets`
- `./scripts/cleanroom_guard.sh`

View File

@@ -1,14 +1,15 @@
# AUR Publish SSH Troubleshooting # AUR Publish Troubleshooting
This runbook focuses on resolving AUR publish failures such as `Permission denied (publickey)` in release workflows. Use this runbook when the AUR release path fails, especially on SSH authentication.
## Preconditions ## Typical Failure Signatures
- `AUR_USERNAME` secret exists.
- `AUR_SSH_PRIVATE_KEY` secret exists and contains the full private key block.
- Runner can reach `aur.archlinux.org:22`.
## 1) Key format and permissions checks - `Permission denied (publickey)`
Run on a secure local shell before updating secrets: - `Host key verification failed`
- missing `AUR_USERNAME`
- missing `AUR_SSH_PRIVATE_KEY`
## Local SSH Sanity Check
```bash ```bash
mkdir -p /tmp/aur-debug && cd /tmp/aur-debug mkdir -p /tmp/aur-debug && cd /tmp/aur-debug
@@ -20,10 +21,11 @@ ssh-keygen -y -f aur_key >/tmp/aur_key.pub
``` ```
Expected: Expected:
- `ssh-keygen -y` succeeds.
- no passphrase prompt for CI use.
## 2) Known hosts and host verification - the key parses successfully
- no CI-incompatible passphrase prompt
## Known Hosts Check
```bash ```bash
mkdir -p ~/.ssh && chmod 700 ~/.ssh mkdir -p ~/.ssh && chmod 700 ~/.ssh
@@ -31,40 +33,27 @@ ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts chmod 600 ~/.ssh/known_hosts
``` ```
Expected: ## Remote Auth Check
- `aur.archlinux.org` host key is present in `known_hosts`.
## 3) SSH dry-run authentication
```bash ```bash
ssh -i /tmp/aur-debug/aur_key \ ssh -i /tmp/aur-debug/aur_key \
-o IdentitiesOnly=yes \ -o IdentitiesOnly=yes \
-o StrictHostKeyChecking=yes \ -o StrictHostKeyChecking=yes \
${AUR_USERNAME}@aur.archlinux.org "${AUR_USERNAME}@aur.archlinux.org"
``` ```
Expected success signature: An immediate disconnect after auth is still acceptable. It proves the key is valid.
- authentication accepted (AUR may close session after auth; that still proves key acceptance).
Expected failure signatures: ## Repo Check
- `Permission denied (publickey)` means wrong key/user pairing.
- `Host key verification failed` means known_hosts mismatch/missing.
## 4) Repo-level publish dry run
For package repo:
```bash ```bash
git ls-remote ssh://${AUR_USERNAME}@aur.archlinux.org/openbitdo-bin.git git ls-remote "ssh://${AUR_USERNAME}@aur.archlinux.org/openbitdo-bin.git"
``` ```
Expected: If this fails, the AUR account or key pairing is still wrong.
- command returns refs without auth failures.
## 5) CI secret update checklist ## After The Fix
- Store private key in `AUR_SSH_PRIVATE_KEY` exactly as multiline PEM/OpenSSH block.
- Store account name in `AUR_USERNAME`.
- Re-run release workflow preflight job.
## 6) Post-fix validation - rerun the release workflow
- Confirm release preflight no longer fails on SSH auth. - confirm `publish-aur` succeeds
- Confirm `publish-aur` job pushes `openbitdo-bin` metadata repo. - confirm `openbitdo-bin` points at the new release tag

View File

@@ -1,16 +1,20 @@
# Branch and Merge Policy # Branch Policy
Because this workspace currently has no active Git repository metadata, this policy is documented for use when repository control is re-enabled. ## Defaults
## Branches - default branch: `main`
- `codex/dirtyroom-spec`: sanitize findings into `cleanroom/spec` and `cleanroom/process` - automation/worktree branches: `codex/*`
- `codex/cleanroom-sdk`: implement SDK and CLI from sanitized artifacts only - release tags: `v*`
## Merge Strategy ## Merge Expectations
- Cherry-pick sanitized spec commits from dirtyroom branch into cleanroom branch.
- Never merge dirty-room evidence paths into cleanroom implementation branch. - clean-room implementation stays in `cleanroom/`
- dirty-room or decompiler material never lands in runtime, tests, docs, or workflows inside this tree
- release tags are created from commits that are already on `main`
## Review Checklist ## Review Checklist
- Guard script passes.
- No forbidden path references in code/tests. - clean-room guard passes
- Requirement IDs are traceable from implementation and tests. - no forbidden path references were introduced
- docs and release metadata are consistent with the current RC
- required CI checks stay green

View File

@@ -1,23 +1,24 @@
# Clean-Room Rules # Clean-Room Rules
## Allowed Inputs During Clean Implementation ## Allowed Inputs
- `cleanroom/spec/**`
- `cleanroom/process/cleanroom_rules.md`
- `cleanroom/harness/golden/**`
## Forbidden Inputs During Clean Implementation - `cleanroom/spec/**`
- `decompiled/**` - `cleanroom/process/**`
- `decompiled_*/*` - approved harness fixtures and generated release artifacts
- `bundle_extract/**`
- `extracted/**` ## Forbidden Inputs
- `extracted_net/**`
- `session-ses_35e4.md` - decompiled vendor code
- copied proprietary snippets
- direct references to dirty-room paths from clean implementation or user-facing docs
## Enforcement ## Enforcement
- `cleanroom/sdk/scripts/cleanroom_guard.sh` checks for forbidden path and token references.
- CI runs the guard before test jobs. - `cleanroom/sdk/scripts/cleanroom_guard.sh` scans for forbidden references
- CI runs the guard before packaging and test jobs
## Commit Hygiene ## Commit Hygiene
- No copied decompiled code snippets.
- No direct references to dirty-room files in SDK implementation/tests. - no copied decompiled code
- Any new protocol fact must be added to sanitized spec artifacts first. - no raw vendor-source excerpts
- new protocol facts must arrive through sanitized spec or evidence updates first

View File

@@ -1,17 +1,20 @@
# OpenBitdo Commenting Standard # Commenting Standard
This project prefers concise, high-context comments. OpenBitdo prefers sparse, high-value comments.
## Required Comment Zones ## Add Comments When
- Command gating order and rationale (`bitdo_proto::session`).
- Support-tier decisions and promotion boundaries (`candidate-readonly` vs `full`).
- Unsafe/firmware blocking rules and brick-risk protections.
- Retry/fallback behavior where multiple command paths exist.
- State-machine transitions in TUI/app-core flows when transitions are non-obvious.
## Avoid - safety or brick-risk behavior is non-obvious
- Trivial comments that restate code syntax. - support-tier gating would be easy to misread
- Comment blocks that drift from behavior and are not maintained. - retries, fallbacks, or validator behavior need rationale
- a state transition matters more than the literal code line
## Rule of Thumb ## Avoid Comments When
If someone adding a new device could misread a policy or safety boundary, comment it.
- the code already says the same thing clearly
- the comment would become stale as soon as names or branches change
- the comment explains syntax instead of intent
## Rule Of Thumb
If a future contributor could accidentally weaken a safety boundary, the surrounding code deserves a short comment.

View File

@@ -1,30 +1,25 @@
# Community Evidence Intake # Community Evidence Intake
## Purpose This process collects safe, sanitized device evidence from users and testers.
Collect hardware and protocol evidence from the community in a clean-room-safe format.
## Submission Requirements ## Required Submission Data
Every report must include:
- Device name - device name
- VID/PID (`0xVVVV:0xPPPP`) - VID/PID in `0xVVVV:0xPPPP` form
- Firmware version shown by official software/device - firmware version
- Operation attempted - operation attempted
- Sanitized request/response shape description - sanitized request or response description
- Reproducibility notes (steps, OS, transport mode) - OS, transport mode, and reproducibility notes
## Prohibited Content ## Prohibited Content
- Raw copied decompiled code.
- Vendor source snippets.
- Binary dumps with proprietary content not required for protocol structure.
## Acceptance Levels - raw decompiled code
- `intake`: report received, unverified. - copied vendor source snippets
- `triaged`: mapped to a PID/operation group and requirement IDs. - proprietary dumps that are not sanitized into structure-level notes
- `accepted`: converted into sanitized dossier/spec updates.
## Maintainer Processing ## Maintainer Flow
1. Validate report format.
2. Cross-reference PID with `spec/pid_matrix.csv`. 1. validate the report format
3. Create/update `spec/dossiers/<pid_hex>/*.toml`. 2. map it to a known PID or create a new sanitized record
4. Update `spec/evidence_index.csv` and command/pid matrices. 3. update the relevant spec or dossier artifacts
5. Keep device as `candidate-readonly` until full 3-signal promotion gate is met. 4. keep the device read-only until runtime and hardware confirmation justify promotion

View File

@@ -1,33 +1,38 @@
# Device Name Sources # Device Name Sources
This index lists sanitized naming sources used to build `/Users/brooklyn/data/8bitdo/cleanroom/spec/device_name_catalog.md`. This index explains where canonical device names came from and how confident the project is in them.
## Primary dirty-room references ## Source Classes
- `DR-1`: Decompiled PID constants table (`VIDPID`) in `/Users/brooklyn/data/8bitdo/decompiled_dll/8BitDo_Ultimate_Software_V2.decompiled.cs` around line 194289.
- `DR-2`: Decompiled device name resolver (`getName()`) in `/Users/brooklyn/data/8bitdo/decompiled_dll/8BitDo_Ultimate_Software_V2.decompiled.cs` around line 12249.
- `DR-3`: Decompiled language map (`LanguageTools`) in `/Users/brooklyn/data/8bitdo/decompiled_dll/8BitDo_Ultimate_Software_V2.decompiled.cs` around line 206277.
## Official 8BitDo web cross-check references - sanitized dirty-room references from internal naming tables
- `WEB-1`: [8BitDo product catalog](https://www.8bitdo.com/#Products) - official 8BitDo product pages
- `WEB-2`: [Ultimate 2 Wireless Controller](https://www.8bitdo.com/ultimate-2-wireless-controller/) - project-maintained fallback names when neither source is strong enough for a public label
- `WEB-3`: [Ultimate 2 Bluetooth Controller](https://www.8bitdo.com/ultimate-2-bluetooth-controller/)
- `WEB-4`: [Ultimate 2C Wireless Controller](https://www.8bitdo.com/ultimate-2c-wireless-controller/)
- `WEB-5`: [Ultimate 2C Bluetooth Controller](https://www.8bitdo.com/ultimate-2c-bluetooth-controller/)
- `WEB-6`: [Pro 2 Bluetooth Controller](https://www.8bitdo.com/pro2/)
- `WEB-7`: [Retro 108 Mechanical Keyboard](https://www.8bitdo.com/retro-108-mechanical-keyboard/)
- `WEB-8`: [Retro 87 Mechanical Keyboard - Xbox Edition](https://www.8bitdo.com/retro-87-mechanical-keyboard-xbox/)
- `WEB-9`: [Retro R8 Mouse - Xbox Edition](https://www.8bitdo.com/retro-r8-mouse-xbox/)
- `WEB-10`: [Arcade Controller](https://www.8bitdo.com/arcade-controller/)
- `WEB-11`: [64 Bluetooth Controller](https://www.8bitdo.com/64-controller/)
- `WEB-12`: [Retro Mechanical Keyboard N Edition](https://www.8bitdo.com/retro-mechanical-keyboard/)
## Confidence policy ## Confidence Policy
- `high`: direct match in `DR-2/DR-3` and/or product page exact-name match.
- `medium`: strong inferred match from product family naming with at least one source anchor.
- `low`: internal fallback name because no confident public marketing name was found.
## Low-confidence naming convention - `high`: exact or near-exact public confirmation
- Canonical wording for low-confidence rows is: - `medium`: strong inferred match from family and naming context
- `Unconfirmed Internal Device (PID_*)` - `low`: fallback wording kept intentionally conservative
- `Unconfirmed Variant Name (PID_*)`
- `Unconfirmed Interface Name (PID_*)` ## Low-Confidence Naming Convention
Use conservative labels such as:
- `Unconfirmed Internal Device (...)`
- `Unconfirmed Variant Name (...)`
- `Unconfirmed Interface Name (...)`
## Current Official Cross-Checks
- [8BitDo product catalog](https://www.8bitdo.com/#Products)
- [Ultimate 2 Wireless Controller](https://www.8bitdo.com/ultimate-2-wireless-controller/)
- [Ultimate 2 Bluetooth Controller](https://www.8bitdo.com/ultimate-2-bluetooth-controller/)
- [Ultimate 2C Wireless Controller](https://www.8bitdo.com/ultimate-2c-wireless-controller/)
- [Ultimate 2C Bluetooth Controller](https://www.8bitdo.com/ultimate-2c-bluetooth-controller/)
- [Pro 2 Bluetooth Controller](https://www.8bitdo.com/pro2/)
- [Retro 108 Mechanical Keyboard](https://www.8bitdo.com/retro-108-mechanical-keyboard/)
- [Retro 87 Mechanical Keyboard - Xbox Edition](https://www.8bitdo.com/retro-87-mechanical-keyboard-xbox/)
- [Retro R8 Mouse - Xbox Edition](https://www.8bitdo.com/retro-r8-mouse-xbox/)
- [Arcade Controller](https://www.8bitdo.com/arcade-controller/)
- [64 Bluetooth Controller](https://www.8bitdo.com/64-controller/)
- [Retro Mechanical Keyboard N Edition](https://www.8bitdo.com/retro-mechanical-keyboard/)

View File

@@ -1,60 +1,40 @@
# Dirty-Room Collection Playbook (Decompiler-First Expansion) # Dirty-Room Collection Playbook
This playbook describes how dirty-room evidence is gathered and sanitized before the clean-room implementation consumes it.
## Goal ## Goal
Create sanitized, requirement-linked evidence that expands device detect/diagnostics support without contaminating clean-room implementation.
## Scope of This Wave Produce sanitized, requirement-linked evidence that can expand detect, diagnostics, mapping, or firmware understanding without copying vendor material into the runtime.
- Evidence source: decompiler/static-only.
- Target: Wave 2 +12 popularity cohort (plus previously tracked candidate-readonly set).
- Promotion policy: no new `full` promotions in this wave.
- Output artifacts: `spec/dossiers/**`, `spec/evidence_index.csv`, updated `spec/*.csv`, updated `requirements.yaml`.
## Allowed Dirty-Room Inputs ## Allowed Inputs
- `/Users/brooklyn/data/8bitdo/decompiled_dll/8BitDo_Ultimate_Software_V2.decompiled.cs`
- `/Users/brooklyn/data/8bitdo/decompiled/*.cs`
- `/Users/brooklyn/data/8bitdo/decompiled_autoupdate/*.cs`
- Existing dirty-room transcript files under `/Users/brooklyn/data/8bitdo/`
## Required Sanitization Rules - approved decompiler outputs and existing dirty-room transcripts
- Do not copy raw vendor/decompiled code snippets into clean artifacts. - official public web pages used for naming or marketing confirmation
- Record only sanitized structure-level findings:
- command intent ## Required Sanitization
- request/response byte-shape
- validator expectations Record only structure-level findings:
- gating/policy notes
- Use requirement IDs only (`REQ-DR-*`, `REQ-PROM-*`, `REQ-COMM-*`, `REQ-GH-*`). - command intent
- request and response shape
- validator expectations
- retry or failure behavior
- promotion or safety notes
Do not copy vendor code or raw proprietary snippets.
## Dossier Workflow ## Dossier Workflow
1. Pick PID and operation group.
2. Collect static evidence anchors (class/function names and behavior summaries).
3. Derive sanitized command mapping and validation expectations.
4. Write TOML dossier in `spec/dossiers/<pid_hex>/<operation_group>.toml`.
5. Link dossier ID into `spec/command_matrix.csv` (`dossier_id` column).
6. Update `spec/evidence_index.csv`.
7. Ensure each Wave 2 PID has all three required dossier files:
- `core_diag.toml`
- `mode_or_profile_read.toml`
- `firmware_preflight.toml`
## Authoring Approach (No Helper Scripts) 1. choose a PID and operation group
- Dossiers and matrix updates are maintained directly in repository source files. 2. collect anchors and summarize them
- `spec/evidence_index.csv` is updated manually with deterministic ordering. 3. create or update the sanitized dossier
- Validation is performed through normal repository review plus workspace tests. 4. link the dossier from the relevant matrix rows
5. update evidence indexes and notes
## Confidence Rules ## Promotion Rule
- `confirmed`: requires static + runtime + hardware confirmation (not achievable in this wave).
- `inferred`: static-only or partial confidence.
- For this wave, new entries should remain `inferred` unless already confirmed historically.
## Promotion Gate Moving from `read-only candidate` to `supported` requires:
A device can move from `candidate-readonly` to `full` only when all three are true:
1. static evidence complete
2. runtime trace evidence complete
3. hardware read/write/readback complete
## Review Checklist 1. static evidence
- Dossier contains required fields from schema. 2. runtime traces
- Requirement linkage is explicit. 3. hardware confirmation
- No raw decompiled text/snippets are present.
- `support_tier` remains `candidate-readonly` for new no-hardware devices.
- Runtime and hardware placeholders are populated with concrete promotion evidence tasks.

View File

@@ -1,56 +1,30 @@
# Dirty-Room Dossier Schema # Dirty-Room Dossier Schema
Each dossier file is TOML and must include these fields. Each dossier is a TOML file that captures sanitized protocol evidence for one PID and one operation group.
## Required Fields ## Required Fields
- `dossier_id`: stable identifier, e.g. `DOS-5200-CORE`.
- `pid_hex`: target PID in hex (`0xNNNN`). - `dossier_id`
- `operation_group`: logical grouping (`CoreDiag`, `ModeProfileRead`, `FirmwarePreflight`, etc). - `pid_hex`
- `command_id`: array of command IDs scoped by this dossier. - `operation_group`
- `request_shape`: sanitized request structure summary. - `command_id`
- `response_shape`: sanitized response structure summary. - `request_shape`
- `validator_rules`: array of response validation constraints. - `response_shape`
- `retry_behavior`: retry and timeout behavior summary. - `validator_rules`
- `failure_signatures`: array of known failure signatures. - `retry_behavior`
- `evidence_source`: `static` for this wave. - `failure_signatures`
- `confidence`: `inferred` or `confirmed`. - `evidence_source`
- `requirement_ids`: array of linked requirement IDs. - `confidence`
- `state_machine`: table with `pre_state`, `action`, `post_state`, and `invalid_transitions`. - `requirement_ids`
- `runtime_placeholder`: table with `required` and `evidence_needed`. - `state_machine`
- `hardware_placeholder`: table with `required` and `evidence_needed`. - `runtime_placeholder`
- `hardware_placeholder`
## Optional Fields ## Optional Fields
- `class_family`: static class-family grouping hints.
- `notes`: additional sanitized context.
## Example - `class_family`
```toml - `notes`
dossier_id = "DOS-5200-CORE"
pid_hex = "0x5200"
operation_group = "CoreDiag"
command_id = ["GetPid", "GetReportRevision", "GetControllerVersion", "Version", "Idle"]
request_shape = "64-byte HID report, command byte in report[1], PID-specific gating outside payload"
response_shape = "short status header plus optional payload bytes"
validator_rules = ["byte0 == 0x02", "response length >= 4"]
retry_behavior = "retry up to configured max attempts on timeout/malformed response"
failure_signatures = ["timeout", "malformed response", "unsupported command for pid"]
evidence_source = "static"
confidence = "inferred"
requirement_ids = ["REQ-DR-001", "REQ-PROM-001", "REQ-PID-002"]
class_family = "JP/Handshake path"
notes = "candidate-readonly in this wave"
[state_machine] ## Authoring Rule
pre_state = "DeviceConnected"
action = "Run core diagnostics reads"
post_state = "DeviceIdentified"
invalid_transitions = ["NoDevice", "TransportClosed", "BootloaderOnly"]
[runtime_placeholder] Prefer short, structure-level descriptions over long prose. The dossier should be good enough to guide clean implementation and testing without embedding dirty-room source text.
required = true
evidence_needed = ["runtime request/response captures", "error signature examples"]
[hardware_placeholder]
required = true
evidence_needed = ["physical read validation", "repeatability checks"]
```

View File

@@ -1,50 +1,18 @@
# Dirty-Room Evidence Backlog # Dirty-Room Evidence Backlog
## Purpose This backlog tracks the next protocol-evidence areas that would most improve runtime confidence.
Track future dirty-room evidence work for protocol expansion in a structured way, so new functionality can be translated into sanitized clean-room specs without contaminating implementation code. ## Priority Areas
## Clean-Room Boundaries 1. read-only candidate expansion for additional controller families
2. deeper JP108 mapping confirmation
3. deeper Ultimate 2 profile and slot behavior confirmation
4. firmware trace and recovery evidence across supported devices
5. runtime and hardware evidence needed to promote candidate devices
- Dirty-room analysis may use approved evidence sources. ## Expected Outputs
- Clean implementation must consume only sanitized artifacts in `spec/` and approved harness data.
- No raw dirty-room snippets, copied code, or direct decompiled fragments may be carried into clean implementation files.
## Prioritized Backlog - updated spec and requirement references
- refreshed command and PID matrices
1. Wave-2 candidate-readonly expansion (decompiler-first): - sanitized dossier updates
- Popularity +12 PIDs: - optional harness fixtures where they improve regression coverage
- `0x3100`, `0x3105`, `0x2100`, `0x2101`, `0x901a`, `0x6006`
- `0x5203`, `0x5204`, `0x301a`, `0x9028`, `0x3026`, `0x3027`
- Deliverable posture: detect/diag-only (`candidate-readonly`), no firmware transfer/write promotion.
2. Wave-1 candidate-readonly follow-through:
- Primary 14 PIDs:
- `0x6002`, `0x6003`, `0x3010`, `0x3011`, `0x3012`, `0x3013`
- `0x5200`, `0x5201`, `0x203a`, `0x2049`, `0x2028`, `0x202e`
- `0x3004`, `0x3019`
- Stretch PIDs:
- `0x3021`, `0x2039`, `0x2056`, `0x5205`, `0x5206`
- Deliverable posture: stay candidate-readonly until runtime and hardware evidence is accepted.
3. JP108 deeper mapping coverage:
- Expand dedicated key mapping confirmation beyond the current A/B/K1-K8 baseline.
- Confirm feature and voice command behavior with stronger request/response confidence.
4. Ultimate2 advanced paths:
- Expand confidence for advanced slot/config interactions and additional profile behaviors.
- Confirm edge cases for mode transitions and per-slot persistence.
5. Firmware trace confidence:
- Increase confidence for bootloader enter/chunk/commit/exit behavior across supported target variants.
- Capture and sanitize additional failure and recovery traces.
## Required Sanitized Outputs
- Update `spec/protocol_spec.md` for any newly confirmed operation groups or behavior rules.
- Update `spec/requirements.yaml` with new stable requirement IDs.
- Update `spec/command_matrix.csv` and `spec/pid_matrix.csv` as evidence confidence changes.
- Add or refresh sanitized harness fixtures under `harness/golden/` for replay and regression tests.
## Review Checklist Before Clean Implementation
- Sanitized evidence is traceable to requirement IDs.
- Command confidence levels are explicit (`confirmed` vs `inferred`).
- PID capability changes are reflected in matrices.
- No raw-source text is present in clean implementation artifacts.

View File

@@ -1,23 +1,15 @@
# Wave 1 Baseline Snapshot # Wave 1 Baseline Snapshot
Generated: 2026-02-28 Generated on 2026-02-28.
## Hardware Access Baseline ## Baseline
- Available hardware lines: JP108 + Ultimate2.
- Exact attached PID variants: pending local identify run on connected hardware.
- Temporary lab fixture defaults remain:
- JP108: `0x5209`
- Ultimate2: `0x6012`
## Required Next Verification Step - owned fixture families: JP108 and Ultimate 2
Run identify flow with connected hardware and confirm fixture PIDs: - existing supported paths were limited to hardware-confirmed devices
1. `cargo test --workspace --test hardware_smoke -- --ignored --exact hardware_smoke_detect_devices` - newly expanded devices were intentionally kept read-only
2. `./scripts/run_hardware_smoke.sh` with `BITDO_REQUIRED_SUITE=108jp`
3. `./scripts/run_hardware_smoke.sh` with `BITDO_REQUIRED_SUITE=ultimate2`
If detected variants differ, update `harness/lab/device_lab.yaml` fixture PIDs immediately. ## Expected Follow-Up
## Support Baseline - capture runtime traces
- Existing `full` paths: JP108/Ultimate2 and previously confirmed families. - confirm real hardware behavior
- New expansion wave devices remain `candidate-readonly` (detect/diag only). - promote devices only after static, runtime, and hardware evidence align
- No new firmware/write enablement for no-hardware targets.

View File

@@ -1,23 +1,9 @@
# Wave 1 Results (Template) # Wave 1 Results
Generated: 2026-02-28 Generated on 2026-02-28.
## Summary ## Outcome
- Primary target PIDs processed: 14
- Stretch target PIDs processed: TBD
- New `full` promotions: 0 (expected in decompiler-only wave)
## Deliverables - Wave 1 produced sanitized evidence and candidate-readonly expansion work.
- Dossiers created: `spec/dossiers/**` - No new device families were promoted directly to full support.
- Evidence index updated: `spec/evidence_index.csv` - Follow-up work remained runtime traces and hardware confirmation.
- Matrices updated: `spec/pid_matrix.csv`, `spec/command_matrix.csv`
- Requirements updated: `spec/requirements.yaml`
## Validation
- `cargo test --workspace --all-targets`: pending
- `./scripts/cleanroom_guard.sh`: pending
- Detect/diag targeted tests: pending
## Follow-Up
- Collect runtime traces for candidate-readonly devices.
- Run hardware confirmation on each candidate before promotion to `full`.

View File

@@ -1,32 +1,17 @@
# Wave 2 Baseline (Frozen) # Wave 2 Baseline
## Snapshot Date Snapshot date: 2026-03-01.
- 2026-03-01
## Pre-Wave Counts (Frozen) ## Baseline Assumptions
- `spec/pid_matrix.csv` rows: 59
- Support tier counts (pre-wave):
- `full`: 14
- `candidate-readonly`: 15
- `detect-only`: 30
- `spec/command_matrix.csv` rows (pre-wave): 37
## Hardware Reality (Current) - hardware ownership still covered only the JP108 and Ultimate 2 lines
- Available fixtures: JP108 line and Ultimate2 line only. - newly researched PIDs had to remain read-only until confirmation improved
- Non-owned devices must remain `candidate-readonly` until strict promotion signals are complete. - release gates stayed anchored on `guard`, `aur-validate`, `tui-smoke-test`, `build-macos-arm64`, and `test`
## Required Checks Baseline
Branch protection for `main` must require:
- `guard`
- `aur-validate`
- `tui-smoke-test`
- `build-macos-arm64`
- `test`
- `hardware-108jp`
- `hardware-ultimate2`
## Promotion Policy ## Promotion Policy
Promotion from `candidate-readonly` to `full` requires all 3 signals:
1. static dossier evidence, Promotion from `read-only candidate` to `supported` requires:
2. runtime sanitized traces,
3. hardware read/write/readback confirmation. 1. static evidence
2. runtime evidence
3. hardware evidence

View File

@@ -1,22 +1,23 @@
# Wave 2 PID Scorecard # Wave 2 PID Scorecard
Legend: Legend:
- Static: dossier + matrix linkage complete.
- Runtime: sanitized runtime traces accepted. - `Static`: dossier and matrix linkage complete
- Hardware: read/write/readback confirmed on owned fixture. - `Runtime`: sanitized runtime traces accepted
- Gate: promotion blocker status. - `Hardware`: real-device confirmation accepted
- `Gate`: reason promotion remains blocked
| PID | Device | Tier | Static | Runtime | Hardware | Gate | | PID | Device | Tier | Static | Runtime | Hardware | Gate |
|---|---|---|---|---|---|---| | --- | --- | --- | --- | --- | --- | --- |
| `0x3100` | PID_USB_Ultimate | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x3100` | `PID_USB_Ultimate` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x3105` | PID_USB_Ultimate2 | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x3105` | `PID_USB_Ultimate2` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x2100` | PID_Xcloud | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x2100` | `PID_Xcloud` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x2101` | PID_Xcloud2 | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x2101` | `PID_Xcloud2` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x901a` | PID_ArcadeStick | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x901a` | `PID_ArcadeStick` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x6006` | PID_Pro2_CY | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x6006` | `PID_Pro2_CY` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x5203` | PID_NUMPAD | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x5203` | `PID_NUMPAD` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x5204` | PID_NUMPADRR | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x5204` | `PID_NUMPADRR` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x301a` | PID_UltimateBT2C | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x301a` | `PID_UltimateBT2C` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x9028` | PID_N64RR | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x9028` | `PID_N64RR` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x3026` | PID_XBOXUK | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x3026` | `PID_XBOXUK` | read-only candidate | yes | no | no | blocked/no_runtime |
| `0x3027` | PID_XBOXUKUSB | candidate-readonly | yes | no | no | blocked/no_runtime | | `0x3027` | `PID_XBOXUKUSB` | read-only candidate | yes | no | no | blocked/no_runtime |

View File

@@ -1,23 +1,19 @@
# Wave 2 Results # Wave 2 Results
## Scope ## Outcome
- Expansion cohort: 12 additional popularity-first PIDs.
- Evidence mode: static/decompiler-only.
- Support result: all 12 moved to `candidate-readonly` with detect/diag-only behavior.
## Delivered - twelve additional PIDs were expanded through sanitized static evidence
1. Manual, source-controlled dossier and matrix updates (no script-generated artifacts). - all twelve remained read-only candidates
2. Wave 2 dossier set (`core_diag`, `mode_or_profile_read`, `firmware_preflight`) for each of 12 PIDs. - no new family was promoted without runtime and hardware confirmation
3. `pid_matrix.csv` updated with Wave 2 candidate-readonly tiering.
4. `command_matrix.csv` updated with Wave 2 dossier-linked rows and explicit promotion gates.
5. `evidence_index.csv` updated from current candidate-readonly set.
6. Governance verification completed for variables, labels, and required checks.
## Deferred ## Deliverables
- Runtime trace evidence for Wave 2 cohort.
- Hardware read/write/readback confirmation for Wave 2 cohort.
- Any promotion to `full` for Wave 2 cohort.
## Exit Status - updated dossiers and matrices
- Wave 2 static-only deliverables: complete. - refreshed evidence index
- Promotion status: blocked pending runtime + hardware signals. - governance and release-gate verification
## Deferred Work
- runtime traces
- hardware confirmation
- any promotion to full support

View File

@@ -1,38 +1,22 @@
# Wave 2 Runtime/Hardware Intake (Prepared, Deferred) # Wave 2 Runtime Intake
## Purpose This note describes the evidence still needed to move Wave 2 devices beyond static-only confidence.
Define exactly what sanitized runtime/hardware evidence is needed to move Wave 2 devices beyond static-only dossiers.
## Required Submission Data ## Required Submission Data
Every submission must include:
1. VID/PID in hex.
2. Firmware version.
3. Operation attempted.
4. Sanitized request structure.
5. Sanitized response structure.
6. Reproducibility notes (OS, transport, retries, success/failure rate).
## Sanitization Rules 1. VID/PID
Allowed content: 2. firmware version
- byte-layout summaries, 3. operation attempted
- command/response shape descriptions, 4. sanitized request structure
- validation predicates, 5. sanitized response structure
- timing/retry observations. 6. reproducibility notes
Forbidden content: ## Acceptance Rules
- raw decompiled code snippets,
- copied vendor constants blocks,
- copied source fragments from official binaries/tools.
## Evidence Acceptance Checklist - no copied vendor code or decompiled snippets
1. VID/PID and firmware fields are present. - failure signatures must map to stable categories
2. Request/response structure is sanitized and technically complete. - the report must be repeatable enough for an independent rerun
3. Failure signatures are mapped to stable categories (`timeout`, `malformed`, `unsupported`, `invalid_signature`).
4. Repro steps are clear enough for independent rerun.
5. No forbidden raw-source content appears.
## Promotion Readiness Mapping ## Promotion Readiness
A PID is promotion-eligible only when all are true:
1. Static dossiers complete. A PID is promotion-ready only when static, runtime, and hardware evidence all exist together.
2. Runtime traces accepted from at least 2 independent runs.
3. Hardware read/write/readback validation passes on owned fixture(s).

View File

@@ -9,7 +9,7 @@ resolver = "2"
[workspace.package] [workspace.package]
edition = "2021" edition = "2021"
version = "0.0.1-rc.2" version = "0.0.1-rc.4"
license = "BSD-3-Clause" license = "BSD-3-Clause"
[workspace.dependencies] [workspace.dependencies]

View File

@@ -1,135 +1,90 @@
# OpenBitdo SDK # OpenBitdo SDK
OpenBitdo SDK includes: This workspace contains the OpenBitdo runtime, protocol layer, and release packaging scripts.
- `bitdo_proto`: protocol/transport/session library
- `bitdo_app_core`: shared firmware-first workflow and policy layer ## Crates
- `bitdo_tui`: Ratatui/Crossterm terminal app
- `openbitdo`: beginner-first launcher (`openbitdo` starts guided TUI) - `bitdo_proto`: command registry, transport, session, and diagnostics behavior
- `bitdo_app_core`: firmware policy, device workflows, and support-tier gating
- `bitdo_tui`: terminal UI, app state, runtime loop, persistence, and headless API
- `openbitdo`: beginner-first launcher binary
## Build And Test
From `cleanroom/sdk`:
## Build
```bash ```bash
cargo build --workspace cargo build --workspace
``` cargo clippy --workspace --all-targets -- -D warnings
## Test
```bash
cargo test --workspace --all-targets cargo test --workspace --all-targets
```
## Guard
```bash
./scripts/cleanroom_guard.sh ./scripts/cleanroom_guard.sh
``` ```
## Hardware smoke report ## Local Run
```bash
./scripts/run_hardware_smoke.sh
```
## TUI app examples (`openbitdo`)
```bash ```bash
cargo run -p openbitdo --
cargo run -p openbitdo -- --mock cargo run -p openbitdo -- --mock
``` ```
## CLI surface `openbitdo` intentionally exposes a single interactive CLI surface.
- `openbitdo [--mock]`: interactive dashboard flow (mouse-primary, minimal keyboard). Headless automation remains available through the Rust API in `bitdo_tui`.
## Interactive behavior (`openbitdo`)
- dashboard starts with:
- searchable device list (left)
- quick actions (center)
- persistent event panel (right)
- primary quick actions:
- `Refresh`
- `Diagnose`
- `Recommended Update`
- `Edit Mapping` (capability-gated)
- `Settings`
- `Quit`
- firmware transfer path:
- preflight generation
- explicit confirm/cancel action
- updating progress and final result screen
- mapping editors are draft-first with:
- apply
- undo
- reset
- restore backup
- recovery lock behavior is preserved when rollback fails.
## Headless library API
- headless automation remains available as a Rust API in `bitdo_tui`:
- `run_headless`
- `RunLaunchOptions`
- `HeadlessOutputMode`
- `openbitdo` CLI does not expose a headless command surface.
## Config schema (v2)
- persisted fields:
- `schema_version`
- `advanced_mode`
- `report_save_mode`
- `device_filter_text`
- `dashboard_layout_mode`
- `last_panel_focus`
- v1 files are read with compatibility defaults and normalized to v2 fields at load time.
## Packaging ## Packaging
```bash ```bash
./scripts/package-linux.sh v0.0.1-rc.2 x86_64 ./scripts/package-linux.sh v0.0.0-local x86_64
./scripts/package-linux.sh v0.0.1-rc.2 aarch64 ./scripts/package-linux.sh v0.0.0-local aarch64
./scripts/package-macos.sh v0.0.1-rc.2 arm64 aarch64-apple-darwin ./scripts/package-macos.sh v0.0.0-local arm64 aarch64-apple-darwin
``` ```
Packaging outputs use: Outputs:
- `openbitdo-<version>-<os>-<arch>.tar.gz`
- `openbitdo-<version>-<os>-<arch>` standalone binary
- `.sha256` checksum file for each artifact
- macOS arm64 additionally emits `.pkg` (unsigned/ad-hoc for RC)
## Release Workflow - `openbitdo-<version>-linux-x86_64.tar.gz`
- CI checks remain in `.github/workflows/ci.yml`. - `openbitdo-<version>-linux-aarch64.tar.gz`
- Tag-based release workflow is in `.github/workflows/release.yml`. - `openbitdo-<version>-macos-arm64.tar.gz`
- Release tags must originate from `main`. - standalone binaries for each packaged target
- `v0.0.1-rc.2` style tags publish GitHub pre-releases. - `.sha256` files for every artifact
- Release notes are sourced from `/Users/brooklyn/data/8bitdo/cleanroom/CHANGELOG.md`. - macOS `.pkg` from `pkgbuild`
- Package-manager publish runs only after release assets are published.
## Public RC Gate Current macOS packaging remains unsigned and non-notarized by design.
- No open GitHub issues with label `release-blocker`.
- Scope-completeness gate:
- JP108 RC scope is dedicated mapping only (`A/B/K1-K8`).
- Ultimate2 RC scope is expanded mapping for required fields only.
- Clean-tree requirement from `/Users/brooklyn/data/8bitdo/cleanroom/RC_CHECKLIST.md` must be satisfied before tagging.
## Distribution Prep ## Release Flow
- Homebrew install path for public RC:
- `brew tap bybrooklyn/openbitdo`
- `brew install openbitdo`
- Homebrew Core inclusion is not required for `v0.0.1-rc.2`.
- Homebrew formula scaffold: `/Users/brooklyn/data/8bitdo/cleanroom/packaging/homebrew/Formula/openbitdo.rb`
- Homebrew tap sync script (disabled by default): `/Users/brooklyn/data/8bitdo/cleanroom/packaging/homebrew/sync_tap.sh`
- Tap repository: `bybrooklyn/homebrew-openbitdo`
- AUR package sources:
- `/Users/brooklyn/data/8bitdo/cleanroom/packaging/aur/openbitdo-bin`
- AUR package names:
- `openbitdo-bin`
- Release metadata renderer:
- `/Users/brooklyn/data/8bitdo/cleanroom/packaging/scripts/render_release_metadata.sh`
- AUR publish workflow:
- `/Users/brooklyn/data/8bitdo/cleanroom/.github/workflows/aur-publish.yml`
- gated by `AUR_PUBLISH_ENABLED=1`
- Homebrew publish path:
- `release.yml` renders checksum-pinned formula and runs `sync_tap.sh`
- gated by `HOMEBREW_PUBLISH_ENABLED=1`
- macOS `.pkg` caveat:
- unsigned/ad-hoc is accepted for `v0.0.1-rc.2`
- notarization required for `v0.1.0`
## CI Gates 1. Tag from `main` using a `v*` tag.
- required: 2. `release.yml` verifies CI, secrets, and release blockers.
- `guard` 3. Linux and macOS artifacts are built and uploaded.
- `test` 4. GitHub prerelease assets are published from those artifacts.
- `tui-smoke-test` 5. AUR and Homebrew metadata are rendered from published release assets.
- `aur-validate` 6. AUR and Homebrew publication run only when their repo-variable gates are enabled.
- `build-macos-arm64`
## Package Manager Publishing
- AUR workflow: `.github/workflows/aur-publish.yml`
- Homebrew workflow: `.github/workflows/homebrew-publish.yml`
- Release metadata renderer: `packaging/scripts/render_release_metadata.sh`
- AUR source of truth:
- tracked package metadata in `packaging/aur/openbitdo-bin`
- template in `packaging/aur/openbitdo-bin/PKGBUILD.tmpl`
- Homebrew source of truth:
- template in `packaging/homebrew/Formula/openbitdo.rb.tmpl`
- published tap repo `bybrooklyn/homebrew-openbitdo`
Current repo-variable contract:
- `AUR_PUBLISH_ENABLED=1`
- `HOMEBREW_PUBLISH_ENABLED=1` when Homebrew publication is enabled
- `HOMEBREW_TAP_REPO=bybrooklyn/homebrew-openbitdo`
Required secrets:
- `AUR_USERNAME`
- `AUR_SSH_PRIVATE_KEY`
- `HOMEBREW_TAP_TOKEN`
## Docs Map
- Public project overview: [`../README.md`](../README.md)
- RC checklist: [`../RC_CHECKLIST.md`](../RC_CHECKLIST.md)
- Process docs: [`../process`](../process)
- Spec docs: [`../spec`](../spec)

View File

@@ -1,23 +1,22 @@
--- ---
source: crates/bitdo_tui/src/tests.rs source: crates/bitdo_tui/src/tests.rs
assertion_line: 196
expression: rendered expression: rendered
--- ---
╭Session───────────────────────────────────────────────────────────────────────╮ ╭Session───────────────────────────────────────────────────────────────────────╮
│OpenBitDo Dashboard • 3 devices • reports fail-only • safe │ │OpenBitDo Dashboard • 3 devices • reports fail-only • safe │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
╭Search filter────────────────╮╭Device full──────────╮╭Actions Enter/click──╮ ╭Search filter────────────────╮╭Device supported─────╮╭Actions Enter/click──╮
│Search active ││Ultimate2 2dc8:5209 ││› Refresh • scan │Search active ││Ultimate2 2dc8:5209 ││› Refresh • look for
╰──────────────────────────────╯│Support: supported ││ Diagnose • probe ╰──────────────────────────────╯│Support: Supported ││ Diagnose • run saf
╭Controllers detected─────────╮│Protocol: Standard64 ││ Recommended Update │ ╭Controllers detected─────────╮│Protocol: Standard64 ││ Recommended Update │
│› 2dc8:5209 Ultimate2 ││Evidence: Confirmed ││ Edit Mapping • map │› 2dc8:5209 Ultimate2 ││Evidence: Confirmed ││ Edit Mapping • cha
full • S64 • conf ││ ││ Settings • prefs supported • standard64 • confi││ ││ Settings • report
│ 2dc8:6009 Ultimate ││Capabilities ││ Quit • exit │ 2dc8:6009 Ultimate ││Capabilities ││ Quit • close OpenB
│ro • S64 • infer ││• firmware ││ │ │read-only • standard64 • infer││• firmware updates ││ │
│ 2dc8:901a Candidate ││• profile rw │╰──────────────────────╯ │ 2dc8:901a Candidate ││• profile read and wri│╰──────────────────────╯
│ro • unknown • untest ││• mode switch │╭Activity events──────╮ │read-only • unknown • untested││• mode switching │╭Activity events──────╮
│ ││• JP108 mapping ││ │ │ ││• JP108 dedicated mapp││ │
│ ││• U2 slot + map ││ │ │ ││• Ultimate 2 slot and ││ │
│ ││ ││ │ │ ││ ││ │
│ ││ ││ │ │ ││ ││ │
│ ││ ││ │ │ ││ ││ │
@@ -25,5 +24,5 @@ expression: rendered
╰──────────────────────────────╯╰──────────────────────╯╰──────────────────────╯ ╰──────────────────────────────╯╰──────────────────────╯╰──────────────────────╯
╭Status────────────────────────────────────────────────────────────────────────╮ ╭Status────────────────────────────────────────────────────────────────────────╮
│Ready │ │Ready │
│Ultimate2 • click • arrows Enter Esc/q │Ultimate2 • click a device or action • arrows, Enter, Esc, and q still work
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯

View File

@@ -1,6 +1,5 @@
--- ---
source: crates/bitdo_tui/src/tests.rs source: crates/bitdo_tui/src/tests.rs
assertion_line: 317
expression: rendered expression: rendered
--- ---
╭Session───────────────────────────────────────────────────────────────────────────────────────────╮ ╭Session───────────────────────────────────────────────────────────────────────────────────────────╮
@@ -8,7 +7,7 @@ expression: rendered
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭Diagnostics summary──────────────────────────────────────────────────────────────────────────────╮ ╭Diagnostics summary──────────────────────────────────────────────────────────────────────────────╮
│3/5 passed • 2 issues • 2 experimental │ │3/5 passed • 2 issues • 2 experimental │
│Tier: full • Family: Standard64 • Transport: ready │Tier: supported • Family: Standard64 • Transport: ready │
│ │ │ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭Filter All──╮╭Filter Issu╮╭Filter Exper╮╭Selected Check detail────────────────────────────────╮ ╭Filter All──╮╭Filter Issu╮╭Filter Exper╮╭Selected Check detail────────────────────────────────╮
@@ -22,7 +21,7 @@ expression: rendered
│ ATTN Version invalid response… ││Validator: test:GetPid │ │ ATTN Version invalid response… ││Validator: test:GetPid │
│ │╰──────────────────────────────────────────────────────╯ │ │╰──────────────────────────────────────────────────────╯
│ │╭Next Steps guidance──────────────────────────────────╮ │ │╭Next Steps guidance──────────────────────────────────╮
│ ││Action: Return to the dashboard and choose Recomme… │ │ ││Action: Return to the dashboard for update or mapp… │
│ ││Summary: 3/5 checks passed. Experimental checks: 1… │ │ ││Summary: 3/5 checks passed. Experimental checks: 1… │
│ ││Saved report: not yet saved in this screen │ │ ││Saved report: not yet saved in this screen │
│ ││ │ │ ││ │
@@ -31,5 +30,5 @@ expression: rendered
╰──────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯
╭Run Again──────────────────────╮╭Save Report────────────────────╮╭Back───────────────────────────╮ ╭Run Again──────────────────────╮╭Save Report────────────────────╮╭Back───────────────────────────╮
│Run Again ││Save Report ││Back │ │Run Again ││Save Report ││Back │
rerun safe-read probe ││write support report ││return to dashboard │ │run the safe checks again ││save a shareable support re… ││return to dashboard │
╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯ ╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯

View File

@@ -1,6 +1,5 @@
--- ---
source: crates/bitdo_tui/src/tests.rs source: crates/bitdo_tui/src/tests.rs
assertion_line: 327
expression: rendered expression: rendered
--- ---
╭Session───────────────────────────────────────────────────────────────────────╮ ╭Session───────────────────────────────────────────────────────────────────────╮
@@ -8,7 +7,7 @@ expression: rendered
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
╭Diagnostics summary──────────────────────────────────────────────────────────╮ ╭Diagnostics summary──────────────────────────────────────────────────────────╮
│3/5 passed • 2 issues • 2 experimental │ │3/5 passed • 2 issues • 2 experimental │
│Tier: full • Family: Standard64 • Transport: ready │Tier: supported • Family: Standard64 • Transport: ready │
│ │ │ │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
╭Checks tab cycles filter─────────────────────────────────────────────────────╮ ╭Checks tab cycles filter─────────────────────────────────────────────────────╮
@@ -21,9 +20,9 @@ expression: rendered
│Severity: Ok │ │Severity: Ok │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
╭Next Steps guidance──────────────────────────────────────────────────────────╮ ╭Next Steps guidance──────────────────────────────────────────────────────────╮
│Action: Return to the dashboard and choose Recommended Update or Edit Mapp… │ │Action: Return to the dashboard for update or mapping if this device still… │
╰──────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────╯
╭Run Again───────────────╮╭Save Report──────────────╮╭Back────────────────────╮ ╭Run Again───────────────╮╭Save Report──────────────╮╭Back────────────────────╮
│Run Again ││Save Report ││Back │ │Run Again ││Save Report ││Back │
rerun safe-read probe ││write support report ││return to dashboard │ │run the safe checks … ││save a shareable supp… ││return to dashboard │
╰────────────────────────╯╰─────────────────────────╯╰────────────────────────╯ ╰────────────────────────╯╰─────────────────────────╯╰────────────────────────╯

View File

@@ -1,6 +1,5 @@
--- ---
source: crates/bitdo_tui/src/tests.rs source: crates/bitdo_tui/src/tests.rs
assertion_line: 343
expression: rendered expression: rendered
--- ---
╭Session───────────────────────────────────────────────────────────────────────────────────────────╮ ╭Session───────────────────────────────────────────────────────────────────────────────────────────╮
@@ -8,7 +7,7 @@ expression: rendered
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭Diagnostics summary──────────────────────────────────────────────────────────────────────────────╮ ╭Diagnostics summary──────────────────────────────────────────────────────────────────────────────╮
│3/5 passed • 2 issues • 2 experimental │ │3/5 passed • 2 issues • 2 experimental │
│Tier: full • Family: Standard64 • Transport: ready │Tier: supported • Family: Standard64 • Transport: ready │
│ │ │ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭Filter All──╮╭Filter Issu╮╭Filter Exper╮╭Selected Check detail────────────────────────────────╮ ╭Filter All──╮╭Filter Issu╮╭Filter Exper╮╭Selected Check detail────────────────────────────────╮
@@ -22,7 +21,7 @@ expression: rendered
│ ││Validator: test:Version │ │ ││Validator: test:Version │
│ │╰──────────────────────────────────────────────────────╯ │ │╰──────────────────────────────────────────────────────╯
│ │╭Next Steps guidance──────────────────────────────────╮ │ │╭Next Steps guidance──────────────────────────────────╮
│ ││Action: Return to the dashboard and choose Recomme… │ │ ││Action: Return to the dashboard for update or mapp… │
│ ││Summary: 3/5 checks passed. Experimental checks: 1… │ │ ││Summary: 3/5 checks passed. Experimental checks: 1… │
│ ││Saved report: /tmp/openbitdo-diag-report.toml │ │ ││Saved report: /tmp/openbitdo-diag-report.toml │
│ ││ │ │ ││ │
@@ -31,5 +30,5 @@ expression: rendered
╰──────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────╯╰──────────────────────────────────────────────────────╯
╭Run Again──────────────────────╮╭Save Report────────────────────╮╭Back───────────────────────────╮ ╭Run Again──────────────────────╮╭Save Report────────────────────╮╭Back───────────────────────────╮
│Run Again ││Save Report ││Back │ │Run Again ││Save Report ││Back │
rerun safe-read probe ││write support report ││return to dashboard │ │run the safe checks again ││save a shareable support re… ││return to dashboard │
╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯ ╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯

View File

@@ -1,13 +1,12 @@
--- ---
source: crates/bitdo_tui/src/tests.rs source: crates/bitdo_tui/src/tests.rs
assertion_line: 212
expression: rendered expression: rendered
--- ---
╭Session───────────────────────────────────────────────────────────────────────────────────────────╮ ╭Session───────────────────────────────────────────────────────────────────────────────────────────╮
│OpenBitDo Workflow • Ready • reports fail-only • safe │ │OpenBitDo Workflow • Ready • reports fail-only • safe │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯ ╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
Preflight status and intent────────────────────────────────────────────────────────────────────── Safety Check status and intent───────────────────────────────────────────────────────────────────╮
Preflight Workflow preflight safety check Safety Check Workflow reviewing update safety
│ │ │ │
│Ready to confirm transfer │ │Ready to confirm transfer │
│ │ │ │
@@ -17,9 +16,9 @@ expression: rendered
│ ││█████ 12% │ │ ││█████ 12% │
│ │╰────────────────────────────────────────╯ │ │╰────────────────────────────────────────╯
│ │╭Context current session────────────────╮ │ │╭Context current session────────────────╮
│ ││Stage: preflight safety check │ ││Current stage: reviewing update safety
│ ││Progress: 12% │ │ ││Progress: 12% │
│ ││Reports: failure_only │ ││Report policy: failure_only │
│ ││Ready │ │ ││Ready │
│ ││ │ │ ││ │
│ ││ │ │ ││ │
@@ -31,5 +30,5 @@ expression: rendered
╰────────────────────────────────────────────────────────╯╰────────────────────────────────────────╯ ╰────────────────────────────────────────────────────────╯╰────────────────────────────────────────╯
╭Confirm────────────────────────╮╭Cancel─────────────────────────╮╭Back───────────────────────────╮ ╭Confirm────────────────────────╮╭Cancel─────────────────────────╮╭Back───────────────────────────╮
│Confirm ││Cancel ││Back │ │Confirm ││Cancel ││Back │
│acknowledge risk + start ││stop this workflow ││return to dashboard │acknowledge risk and start ││stop and discard this step ││leave this screen
╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯ ╰───────────────────────────────╯╰───────────────────────────────╯╰───────────────────────────────╯

View File

@@ -15,8 +15,12 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
.split(area); .split(area);
let status_hint = match state.dashboard_layout_mode { let status_hint = match state.dashboard_layout_mode {
DashboardLayoutMode::Compact => "compact layout • resize for full three-panel view", DashboardLayoutMode::Compact => {
DashboardLayoutMode::Wide => "click arrows Enter • Esc/q", "compact layout • resize for three panels or keep using click, arrows, and Enter"
}
DashboardLayoutMode::Wide => {
"click a device or action • arrows, Enter, Esc, and q still work"
}
}; };
let selected_summary = state let selected_summary = state
.selected_device() .selected_device()
@@ -94,7 +98,7 @@ fn render_devices(frame: &mut Frame<'_>, state: &AppState, area: Rect, map: &mut
let filter = Paragraph::new(Line::from(vec![ let filter = Paragraph::new(Line::from(vec![
Span::styled("Search ", crate::ui::theme::title_style()), Span::styled("Search ", crate::ui::theme::title_style()),
Span::raw(if filter_label.is_empty() { Span::raw(if filter_label.is_empty() {
"type a model, VID, or PID".to_owned() "type a model name or USB ID".to_owned()
} else { } else {
filter_label filter_label
}), }),
@@ -194,7 +198,7 @@ fn render_selected_device(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
if device.support_tier != bitdo_proto::SupportTier::Full { if device.support_tier != bitdo_proto::SupportTier::Full {
details.push(Line::from("")); details.push(Line::from(""));
details.push(Line::from(Span::styled( details.push(Line::from(Span::styled(
"Write actions stay blocked until hardware confirmation lands.", "This device is still read-only here. Safe diagnostics work, but mapping and update stay blocked until hardware confirmation lands.",
crate::ui::theme::warning_style(), crate::ui::theme::warning_style(),
))); )));
} }
@@ -333,17 +337,31 @@ fn truncate_reason(reason: &str) -> String {
fn action_caption(action: crate::app::action::QuickAction) -> &'static str { fn action_caption(action: crate::app::action::QuickAction) -> &'static str {
match action { match action {
crate::app::action::QuickAction::Refresh => "scan", crate::app::action::QuickAction::Refresh => "look for connected controllers",
crate::app::action::QuickAction::Diagnose => "probe", crate::app::action::QuickAction::Diagnose => {
crate::app::action::QuickAction::RecommendedUpdate => "safe update", "run safe diagnostics and build a support summary"
crate::app::action::QuickAction::EditMappings => "mapping", }
crate::app::action::QuickAction::Settings => "prefs", crate::app::action::QuickAction::RecommendedUpdate => {
crate::app::action::QuickAction::Quit => "exit", "download and stage a verified firmware update"
}
crate::app::action::QuickAction::EditMappings => {
"change supported buttons on supported devices"
}
crate::app::action::QuickAction::Settings => "report saving and interface preferences",
crate::app::action::QuickAction::Quit => "close OpenBitdo",
_ => "available", _ => "available",
} }
} }
fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str { fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str {
match tier {
bitdo_proto::SupportTier::Full => "Supported",
bitdo_proto::SupportTier::CandidateReadOnly => "Read-only candidate",
bitdo_proto::SupportTier::DetectOnly => "Detection only",
}
}
fn support_tier_short(tier: bitdo_proto::SupportTier) -> &'static str {
match tier { match tier {
bitdo_proto::SupportTier::Full => "supported", bitdo_proto::SupportTier::Full => "supported",
bitdo_proto::SupportTier::CandidateReadOnly => "read-only", bitdo_proto::SupportTier::CandidateReadOnly => "read-only",
@@ -351,34 +369,26 @@ fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str {
} }
} }
fn support_tier_short(tier: bitdo_proto::SupportTier) -> &'static str {
match tier {
bitdo_proto::SupportTier::Full => "full",
bitdo_proto::SupportTier::CandidateReadOnly => "ro",
bitdo_proto::SupportTier::DetectOnly => "detect",
}
}
fn capability_lines(device: &bitdo_app_core::AppDevice) -> Vec<String> { fn capability_lines(device: &bitdo_app_core::AppDevice) -> Vec<String> {
let mut lines = Vec::new(); let mut lines = Vec::new();
if device.capability.supports_firmware { if device.capability.supports_firmware {
lines.push("• firmware".to_owned()); lines.push("• firmware updates".to_owned());
} }
if device.capability.supports_profile_rw { if device.capability.supports_profile_rw {
lines.push("• profile rw".to_owned()); lines.push("• profile read and write".to_owned());
} }
if device.capability.supports_mode { if device.capability.supports_mode {
lines.push("• mode switch".to_owned()); lines.push("• mode switching".to_owned());
} }
if device.capability.supports_jp108_dedicated_map { if device.capability.supports_jp108_dedicated_map {
lines.push("• JP108 mapping".to_owned()); lines.push("• JP108 dedicated mapping".to_owned());
} }
if device.capability.supports_u2_button_map || device.capability.supports_u2_slot_config { if device.capability.supports_u2_button_map || device.capability.supports_u2_slot_config {
lines.push("• U2 slot + map".to_owned()); lines.push("• Ultimate 2 slot and mapping".to_owned());
} }
if lines.is_empty() { if lines.is_empty() {
lines.push("• detect only".to_owned()); lines.push("• detection only".to_owned());
} }
lines lines
@@ -396,7 +406,9 @@ fn compact_reason(reason: &str) -> String {
fn protocol_short(protocol: bitdo_proto::ProtocolFamily) -> &'static str { fn protocol_short(protocol: bitdo_proto::ProtocolFamily) -> &'static str {
match protocol { match protocol {
bitdo_proto::ProtocolFamily::Standard64 => "S64", bitdo_proto::ProtocolFamily::Standard64 => "standard64",
bitdo_proto::ProtocolFamily::DInput => "dinput",
bitdo_proto::ProtocolFamily::JpHandshake => "jp",
bitdo_proto::ProtocolFamily::Unknown => "unknown", bitdo_proto::ProtocolFamily::Unknown => "unknown",
_ => "other", _ => "other",
} }
@@ -404,8 +416,8 @@ fn protocol_short(protocol: bitdo_proto::ProtocolFamily) -> &'static str {
fn evidence_short(evidence: bitdo_proto::SupportEvidence) -> &'static str { fn evidence_short(evidence: bitdo_proto::SupportEvidence) -> &'static str {
match evidence { match evidence {
bitdo_proto::SupportEvidence::Confirmed => "conf", bitdo_proto::SupportEvidence::Confirmed => "confirmed",
bitdo_proto::SupportEvidence::Inferred => "infer", bitdo_proto::SupportEvidence::Inferred => "inferred",
bitdo_proto::SupportEvidence::Untested => "untest", bitdo_proto::SupportEvidence::Untested => "untested",
} }
} }

View File

@@ -467,8 +467,8 @@ fn render_next_steps(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
fn diagnostics_action_caption(action: QuickAction) -> &'static str { fn diagnostics_action_caption(action: QuickAction) -> &'static str {
match action { match action {
QuickAction::RunAgain => "rerun safe-read probe", QuickAction::RunAgain => "run the safe checks again",
QuickAction::SaveReport => "write support report", QuickAction::SaveReport => "save a shareable support report",
QuickAction::Back => "return to dashboard", QuickAction::Back => "return to dashboard",
_ => "available", _ => "available",
} }
@@ -477,13 +477,13 @@ fn diagnostics_action_caption(action: QuickAction) -> &'static str {
fn recommended_next_action(diagnostics: &crate::app::state::DiagnosticsState) -> &'static str { fn recommended_next_action(diagnostics: &crate::app::state::DiagnosticsState) -> &'static str {
match diagnostics.result.support_tier { match diagnostics.result.support_tier {
bitdo_proto::SupportTier::Full => { bitdo_proto::SupportTier::Full => {
"Return to the dashboard and choose Recommended Update or Edit Mapping if needed." "Return to the dashboard for update or mapping if this device still needs work."
} }
bitdo_proto::SupportTier::CandidateReadOnly => { bitdo_proto::SupportTier::CandidateReadOnly => {
"Save or share the report. Update and mapping remain blocked until confirmation lands." "Save or share the report. Update and mapping stay blocked until this device family is hardware-confirmed."
} }
bitdo_proto::SupportTier::DetectOnly => { bitdo_proto::SupportTier::DetectOnly => {
"Diagnostics only. Do not attempt update or mapping for this device." "Use diagnostics only. This device is not ready for update or mapping flows."
} }
} }
} }
@@ -514,8 +514,8 @@ fn severity_style(has_issues: bool) -> Style {
fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str { fn support_tier_label(tier: bitdo_proto::SupportTier) -> &'static str {
match tier { match tier {
bitdo_proto::SupportTier::Full => "full", bitdo_proto::SupportTier::Full => "supported",
bitdo_proto::SupportTier::CandidateReadOnly => "candidate-readonly", bitdo_proto::SupportTier::CandidateReadOnly => "read-only candidate",
bitdo_proto::SupportTier::DetectOnly => "detect-only", bitdo_proto::SupportTier::DetectOnly => "detect-only",
} }
} }

View File

@@ -24,18 +24,18 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
let adv = Paragraph::new(vec![ let adv = Paragraph::new(vec![
Line::from(Span::styled( Line::from(Span::styled(
if state.advanced_mode { if state.advanced_mode {
"Advanced mode is on" "Advanced controls are on"
} else { } else {
"Advanced mode is off" "Advanced controls are off"
}, },
crate::ui::theme::screen_title_style(), crate::ui::theme::screen_title_style(),
)), )),
Line::from(Span::styled( Line::from(Span::styled(
"Toggle to expose expert-only report and workflow options.", "Turn this on only if you want expert labels and extra workflow options.",
crate::ui::theme::subtle_style(), crate::ui::theme::subtle_style(),
)), )),
]) ])
.block(panel_block("Advanced", Some("press t or click"), true)); .block(panel_block("Advanced", Some("toggle"), true));
frame.render_widget(adv, rows[0]); frame.render_widget(adv, rows[0]);
let report = Paragraph::new(vec![ let report = Paragraph::new(vec![
@@ -44,11 +44,11 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
crate::ui::theme::screen_title_style(), crate::ui::theme::screen_title_style(),
)), )),
Line::from(Span::styled( Line::from(Span::styled(
"Cycle report persistence policy with r or mouse.", "Choose whether support reports save automatically after diagnostics or firmware work.",
crate::ui::theme::subtle_style(), crate::ui::theme::subtle_style(),
)), )),
]) ])
.block(panel_block("Reports", Some("press r or click"), true)); .block(panel_block("Reports", Some("save policy"), true));
frame.render_widget(report, rows[1]); frame.render_widget(report, rows[1]);
let settings_path = state let settings_path = state
@@ -61,11 +61,11 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
Line::from(""), Line::from(""),
Line::from(format!("Config path: {settings_path}")), Line::from(format!("Config path: {settings_path}")),
Line::from(Span::styled( Line::from(Span::styled(
"Dashboard layout and filter state persist when a settings path is configured.", "Dashboard layout, filters, and report preferences persist when this path is available.",
crate::ui::theme::subtle_style(), crate::ui::theme::subtle_style(),
)), )),
]) ])
.block(panel_block("Status", Some("saved preferences"), true)); .block(panel_block("Status", Some("persistence"), true));
frame.render_widget(status, rows[2]); frame.render_widget(status, rows[2]);
let actions = state let actions = state
@@ -95,7 +95,7 @@ fn inner_click_rect(rect: Rect) -> Rect {
fn settings_action_caption(action: crate::app::action::QuickAction) -> &'static str { fn settings_action_caption(action: crate::app::action::QuickAction) -> &'static str {
match action { match action {
crate::app::action::QuickAction::Back => "return to dashboard", crate::app::action::QuickAction::Back => "return to dashboard",
crate::app::action::QuickAction::Quit => "exit openbitdo", crate::app::action::QuickAction::Quit => "close OpenBitdo",
_ => "available", _ => "available",
} }
} }

View File

@@ -22,8 +22,8 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
let task = state.task_state.as_ref(); let task = state.task_state.as_ref();
let title = match task.map(|t| t.mode) { let title = match task.map(|t| t.mode) {
Some(TaskMode::Diagnostics) => "Diagnostics", Some(TaskMode::Diagnostics) => "Diagnostics",
Some(TaskMode::Preflight) => "Preflight", Some(TaskMode::Preflight) => "Safety Check",
Some(TaskMode::Updating) => "Updating", Some(TaskMode::Updating) => "Update In Progress",
Some(TaskMode::Final) => "Result", Some(TaskMode::Final) => "Result",
None => "Task", None => "Task",
}; };
@@ -51,7 +51,7 @@ pub fn render(frame: &mut Frame<'_>, state: &AppState, area: Rect) -> HitMap {
crate::ui::theme::screen_title_style(), crate::ui::theme::screen_title_style(),
)), )),
Line::from(""), Line::from(""),
Line::from("Select a device action from the dashboard to begin."), Line::from("Choose a controller action from the dashboard to begin."),
] ]
}; };
@@ -96,14 +96,20 @@ fn render_task_details(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
let mut lines = vec![Line::from(task.status.clone())]; let mut lines = vec![Line::from(task.status.clone())];
if let Some(plan) = task.plan.as_ref() { if let Some(plan) = task.plan.as_ref() {
lines.push(Line::from("")); lines.push(Line::from(""));
lines.push(Line::from(format!("Session: {:?}", plan.session_id))); lines.push(Line::from(format!(
"Transfer session: {:?}",
plan.session_id
)));
lines.push(Line::from(format!("Chunk size: {} bytes", plan.chunk_size))); lines.push(Line::from(format!("Chunk size: {} bytes", plan.chunk_size)));
lines.push(Line::from(format!("Chunks: {}", plan.chunks_total))); lines.push(Line::from(format!("Total chunks: {}", plan.chunks_total)));
lines.push(Line::from(format!("Estimated: {}s", plan.expected_seconds))); lines.push(Line::from(format!(
"Estimated transfer time: {}s",
plan.expected_seconds
)));
if !plan.warnings.is_empty() { if !plan.warnings.is_empty() {
lines.push(Line::from("")); lines.push(Line::from(""));
lines.push(Line::from(Span::styled( lines.push(Line::from(Span::styled(
"Warnings", "Safety notes",
crate::ui::theme::warning_style(), crate::ui::theme::warning_style(),
))); )));
for warning in &plan.warnings { for warning in &plan.warnings {
@@ -145,16 +151,19 @@ fn render_task_details(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
let summary_lines = if let Some(task) = task { let summary_lines = if let Some(task) = task {
vec![ vec![
Line::from(format!("Stage: {}", task_mode_caption(task.mode))), Line::from(format!("Current stage: {}", task_mode_caption(task.mode))),
Line::from(format!("Progress: {progress}%")), Line::from(format!("Progress: {progress}%")),
Line::from(format!("Reports: {}", state.report_save_mode.as_str())), Line::from(format!(
"Report policy: {}",
state.report_save_mode.as_str()
)),
Line::from(Span::styled( Line::from(Span::styled(
state.status_line.clone(), state.status_line.clone(),
crate::ui::theme::subtle_style(), crate::ui::theme::subtle_style(),
)), )),
] ]
} else { } else {
vec![Line::from("Select an action to see task details.")] vec![Line::from("Choose an action to see its workflow details.")]
}; };
let summary = let summary =
Paragraph::new(summary_lines).block(panel_block("Context", Some("current session"), true)); Paragraph::new(summary_lines).block(panel_block("Context", Some("current session"), true));
@@ -163,18 +172,18 @@ fn render_task_details(frame: &mut Frame<'_>, state: &AppState, area: Rect) {
fn task_mode_caption(mode: TaskMode) -> &'static str { fn task_mode_caption(mode: TaskMode) -> &'static str {
match mode { match mode {
TaskMode::Diagnostics => "diagnostic probe", TaskMode::Diagnostics => "running safe diagnostics",
TaskMode::Preflight => "preflight safety check", TaskMode::Preflight => "reviewing update safety",
TaskMode::Updating => "firmware transfer", TaskMode::Updating => "sending verified firmware",
TaskMode::Final => "final outcome", TaskMode::Final => "showing the final result",
} }
} }
fn task_action_caption(action: crate::app::action::QuickAction) -> &'static str { fn task_action_caption(action: crate::app::action::QuickAction) -> &'static str {
match action { match action {
crate::app::action::QuickAction::Confirm => "acknowledge risk + start", crate::app::action::QuickAction::Confirm => "acknowledge risk and start the update",
crate::app::action::QuickAction::Cancel => "stop this workflow", crate::app::action::QuickAction::Cancel => "stop and discard this step",
crate::app::action::QuickAction::Back => "return to dashboard", crate::app::action::QuickAction::Back => "leave this screen",
_ => "available", _ => "available",
} }
} }

View File

@@ -4,9 +4,25 @@ use bitdo_tui::{run_ui, UiLaunchOptions};
use clap::Parser; use clap::Parser;
use openbitdo::{load_user_settings, user_settings_path, BuildInfo, UserSettings}; use openbitdo::{load_user_settings, user_settings_path, BuildInfo, UserSettings};
const CLI_AFTER_HELP: &str = "\
Examples:
openbitdo
openbitdo --mock
Install:
Homebrew: brew tap bybrooklyn/openbitdo && brew install openbitdo
AUR: paru -S openbitdo-bin
Releases: download a tarball, then run bin/openbitdo
Notes:
--mock starts the app without real hardware.
macOS packages are currently unsigned and non-notarized.
";
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(name = "openbitdo")] #[command(name = "openbitdo")]
#[command(about = "OpenBitdo beginner-first launcher")] #[command(about = "Beginner-first 8BitDo controller utility")]
#[command(after_help = CLI_AFTER_HELP)]
struct Cli { struct Cli {
#[arg(long, help = "Use mock transport/devices")] #[arg(long, help = "Use mock transport/devices")]
mock: bool, mock: bool,

View File

@@ -9,8 +9,16 @@ fn help_mentions_single_command_surface() {
.success() .success()
.stdout(predicate::str::contains("Usage: openbitdo [OPTIONS]")) .stdout(predicate::str::contains("Usage: openbitdo [OPTIONS]"))
.stdout(predicate::str::contains("--mock")) .stdout(predicate::str::contains("--mock"))
.stdout(predicate::str::contains("Examples:"))
.stdout(predicate::str::contains(
"Homebrew: brew tap bybrooklyn/openbitdo && brew install openbitdo",
))
.stdout(predicate::str::contains(
"macOS packages are currently unsigned and non-notarized.",
))
.stdout(predicate::str::contains("Commands:").not())
.stdout(predicate::str::contains("ui").not()) .stdout(predicate::str::contains("ui").not())
.stdout(predicate::str::contains("run").not()); .stdout(predicate::str::contains("run [OPTIONS]").not());
} }
#[test] #[test]

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT"
if rg -n \
--glob '*.md' \
--glob '*.yml' \
--glob '*.sh' \
--glob '*.rb' \
--glob 'PKGBUILD' \
--glob '.SRCINFO' \
-g '!CHANGELOG.md' \
'v0\.0\.1-rc\.1|v0\.0\.1-rc\.2|0\.0\.1-rc\.1|0\.0\.1-rc\.2|0\.0\.1rc1|0\.0\.1rc2' \
.github \
README.md \
MIGRATION.md \
RC_CHECKLIST.md \
packaging \
process \
sdk \
spec; then
echo "stale rc.1/rc.2 references remain outside CHANGELOG.md" >&2
exit 1
fi

View File

@@ -3,7 +3,7 @@ set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(cd "$ROOT/.." && pwd)" REPO_ROOT="$(cd "$ROOT/.." && pwd)"
VERSION="${1:-v0.0.1-rc.1}" VERSION="${1:-v0.0.0-local}"
ARCH_LABEL="${2:-$(uname -m)}" ARCH_LABEL="${2:-$(uname -m)}"
TARGET_TRIPLE="${3:-}" TARGET_TRIPLE="${3:-}"

View File

@@ -3,7 +3,7 @@ set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(cd "$ROOT/.." && pwd)" REPO_ROOT="$(cd "$ROOT/.." && pwd)"
VERSION="${1:-v0.0.1-rc.1}" VERSION="${1:-v0.0.0-local}"
ARCH_LABEL="${2:-arm64}" ARCH_LABEL="${2:-arm64}"
TARGET_TRIPLE="${3:-aarch64-apple-darwin}" TARGET_TRIPLE="${3:-aarch64-apple-darwin}"
INSTALL_PREFIX="${4:-/opt/homebrew/bin}" INSTALL_PREFIX="${4:-/opt/homebrew/bin}"

View File

@@ -1,9 +1,8 @@
# Alias Index # Alias Index
OpenBitdo uses a strict no-duplicate PID model in runtime and canonical spec tables. OpenBitdo keeps one canonical row per PID. Historical duplicate names are tracked here as aliases only.
These legacy names are preserved here as aliases only.
| Alias PID Name | Canonical PID Name | PID (hex) | Note | | Alias PID Name | Canonical PID Name | PID (hex) | Note |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `PID_Pro2_OLD` | `PID_Pro2` | `0x6003` | Legacy constant alias in 8BitDo source; runtime/spec use only `PID_Pro2`. | | `PID_Pro2_OLD` | `PID_Pro2` | `0x6003` | Historical constant alias; runtime and specs use `PID_Pro2`. |
| `PID_ASLGMouse` | `PID_Mouse` | `0x5205` | Alias constant maps to the same PID as `PID_Mouse`; runtime/spec use only `PID_Mouse`. | | `PID_ASLGMouse` | `PID_Mouse` | `0x5205` | Historical alias for the same canonical mouse PID. |

View File

@@ -1,7 +1,14 @@
# Device Name Catalog # Device Name Catalog
This catalog is the sanitized naming source of truth for OpenBitdo runtime/docs. This catalog is the canonical PID-to-name reference for OpenBitdo.
Canonical rows are unique by PID (no duplicates in this table). Use it when you need a stable display name for runtime UI, docs, packaging copy, or evidence review.
## How To Use This Catalog
- Match devices by `pid_hex` first.
- Treat `display_name_en` as the preferred user-facing label.
- Keep aliases out of new canonical rows; add them to the `aliases` column and the alias index instead.
- When confidence is low or the source is `internal-fallback`, treat the name as provisional until better evidence is collected.
| canonical_pid_name | pid_hex | display_name_en | protocol_family | name_source | source_confidence | aliases | | canonical_pid_name | pid_hex | display_name_en | protocol_family | name_source | source_confidence | aliases |
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
@@ -64,5 +71,7 @@ Canonical rows are unique by PID (no duplicates in this table).
| PID_ASLGJP | 0x205a | Riviera Keyboard | JpHandshake | vendor-language-map | high | | | PID_ASLGJP | 0x205a | Riviera Keyboard | JpHandshake | vendor-language-map | high | |
## Notes ## Notes
- Name-source references are indexed in `/Users/brooklyn/data/8bitdo/cleanroom/process/device_name_sources.md`.
- Alias names are documented in `/Users/brooklyn/data/8bitdo/cleanroom/spec/alias_index.md` and intentionally excluded from canonical PID rows. - Canonical rows are unique by PID. Do not duplicate a PID to reflect a marketing alias.
- Name-source evidence is indexed in `/Users/brooklyn/data/8bitdo/cleanroom/process/device_name_sources.md`.
- Alias names live in `/Users/brooklyn/data/8bitdo/cleanroom/spec/alias_index.md` and stay out of the primary PID rows unless they become the canonical public name.

View File

@@ -1,98 +1,93 @@
# 8BitDo Clean-Room Protocol Specification (Sanitized) # OpenBitdo Protocol Overview
## Scope This document summarizes the sanitized protocol model used by the clean-room runtime.
This document defines a sanitized command and transport contract for a clean-room Rust implementation.
It is intentionally independent from reverse-engineered source code details and uses stable requirement IDs.
## Wire Model ## Wire Model
- Transport: HID-like reports
- Primary report width: 64 bytes (`Standard64`, `DInput`, `JpHandshake` families) - HID-like command transport
- Variable-length reports: allowed for boot/firmware phases - primary 64-byte reports for `Standard64`, `DInput`, and `JpHandshake`
- Byte order: little-endian for multi-byte numeric fields - variable-length reports only where firmware or boot phases require them
- little-endian multi-byte numbers
## Protocol Families ## Protocol Families
- `Standard64`: standard 64-byte command and response flow
- `JpHandshake`: alternate handshake and version probing workflow - `Standard64`
- `DInput`: command family used for mode and runtime profile operations - `JpHandshake`
- `DS4Boot`: reserved boot mode for DS4-style update path - `DInput`
- `Unknown`: fallback for unknown devices - `DS4Boot`
- `Unknown`
## Safety Classes ## Safety Classes
- `SafeRead`: read-only operations
- `SafeWrite`: runtime settings/profile writes
- `UnsafeBoot`: bootloader transitions with brick risk
- `UnsafeFirmware`: firmware transfer/commit operations with brick risk
## Response Validation Contract - `SafeRead`: diagnostics and metadata reads
- Responses are validated per command against byte-pattern expectations from `command_matrix.csv` - `SafeWrite`: profile, setting, or mapping writes
- Validation outcomes: `Ok`, `Invalid`, `Malformed` - `UnsafeBoot`: bootloader transitions
- Retry policy applies on `Malformed` or timeout responses - `UnsafeFirmware`: firmware transfer and commit operations
## Response Validation
- every command validates against the registry table
- outcomes are `Ok`, `Invalid`, or `Malformed`
- retry logic applies on timeout or malformed data according to session policy
## Operation Groups ## Operation Groups
- `Core`: generic identify/mode/profile/boot/fallback commands
- `JP108Dedicated`: 108-key dedicated-button mapping + feature/voice operations
- `Ultimate2Core`: Ultimate2 mode/slot/core-map operations
- `Firmware`: device-scoped firmware enter/chunk/commit/exit operations
- `CoreDiag`: decompiler-first detect/diagnostic command subset for candidate-readonly PIDs
- `ModeProfileRead`: decompiler-first read-only mode/profile snapshot group for candidate-readonly PIDs
- `FirmwarePreflight`: decompiler-first firmware readiness metadata reads (no transfer enablement)
## JP108 Dedicated Support - `Core`
- Supported targets: `0x5209` (`PID_108JP`), `0x520a` (`PID_108JPUSB`) - `JP108Dedicated`
- First milestone mapping scope: `A`, `B`, `K1`-`K8` - `Ultimate2Core`
- Additional controls in this group: - `Firmware`
- feature flags read/write - `CoreDiag`
- voice setting read/write - `ModeProfileRead`
- Full 111-key matrix remap is explicitly out of scope for this milestone. - `FirmwarePreflight`
## Ultimate2 Core Support ## Support Model
- Supported targets: `0x6012` (`PID_Ultimate2`), `0x6013` (`PID_Ultimate2RR`)
- First milestone editable scope:
- current mode read/set
- current slot read
- slot config read/write
- core button map read/write
- Advanced subsystems (theme/sixaxis/deep macro editing) are intentionally hidden in this milestone.
## PID-Aware Command Gating ### Support Levels
- Command availability is gated by:
1. safety class and runtime unsafe acknowledgements
2. capability flags
3. explicit PID allowlist from `command_matrix.csv:applies_to`
- `applies_to="*"` means globally available within existing safety/capability constraints.
## Device Support Levels - `full`
- `full`: command execution permitted for safe and unsafe operations (with user gates) - `detect-only`
- `detect-only`: identification allowed; unsupported operations return `UnsupportedForPid`
## Support Tiers ### Support Tiers
- `full`: read/write/unsafe operations available according to existing safety gates.
- `candidate-readonly`: detect/diag safe reads are allowed per PID allowlist; safe writes and unsafe flows are blocked.
- `detect-only`: identify-only posture for unsupported or unknown PIDs.
## Candidate Read-Only Wave Policy - `full`: normal read, write, and gated unsafe paths
- Wave-1 and Wave-2 expansion PIDs are classified as `candidate-readonly`. - `candidate-readonly`: safe-read diagnostics only
- Command policy for this tier: - `detect-only`: identify-only posture
- allow: detect/diag safe-read subset.
- allow: read-only mode/profile snapshot reads when family-appropriate.
- allow: firmware metadata/preflight reads only.
- deny: all safe-write operations.
- deny: all unsafe boot/firmware operations.
- Promotion from `candidate-readonly` to `full` requires 3-signal evidence:
1. static dossier coverage
2. runtime trace evidence
3. hardware read/write/readback confirmation
## Dossier Linkage ## Candidate Read-Only Policy
- Per-PID operation evidence is tracked in `spec/dossiers/**`.
- `command_matrix.csv:dossier_id` links command rows to sanitized dossier artifacts.
- `evidence_index.csv` maps PID to class-family anchors and operation groups.
## Required Runtime Gating Read-only candidates may:
Unsafe commands execute only when both conditions are true:
1. `--unsafe`
2. `--i-understand-brick-risk`
## Clean-Room Requirements Linkage - identify themselves
Implementation and tests must trace to IDs in `requirements.yaml`. - run allowed safe-read diagnostics
All public APIs and behavior are governed by `REQ-PROT-*`, `REQ-PID-*`, `REQ-SAFE-*`, and `REQ-TEST-*` IDs. - perform family-appropriate read-only metadata checks
Read-only candidates may not:
- write mappings or profiles
- enter unsafe boot paths
- transfer firmware
Promotion to full support requires:
1. static evidence
2. runtime evidence
3. hardware evidence
## Feature Scopes
### JP108
- supported targets: `0x5209`, `0x520a`
- current mapping scope: `A`, `B`, `K1`-`K8`
### Ultimate 2
- supported targets: `0x6012`, `0x6013`
- current scope: mode, slot, slot config, core button map, and required analog handling
## Runtime Safety Rule
Unsafe commands are only allowed when the runtime has both:
1. unsafe mode enabled
2. explicit brick-risk acknowledgment