# DIGIT_UI API AUDIT — actual 407 sources vs our v2.0.1 transport assumptions

All 407 facts taken from the installed sources copied under
`digit_ui/` (sha256-verified copies of the image files):
- `show_widget.py`  `135e3fc0b8d7120afb77a442c7cc3d204a98017b4f0b0d4bb2a0db8512600654`
- `ingen_wrapper.py` `63ce37cb478b6a6b2c3bd18cc29753fd98d04bcc871a8c29ca1490560861db03`
- `pedal_hardware.py` `9b1c26f104b46504ba29da670069a33d792ae64b88706271497b277745656a31`

## 1. Wrapper API — our transport vs the real 407 wrapper

Our `beebo/adapter/digit_ui_transport.py` (`DigitUIIngenTransport`, wrapper
object supplied — **no second Ingen client**; the 407 module-side transport
is used as-is) makes exactly these wrapper calls:

| Our call | Real 407 `ingen_wrapper` function | Signature at 407 | Compatible? | Change required? |
|---|---|---|---|---|
| `w.add_plugin(self._node(node), uri)` | `add_plugin(effect_id, effect_url)` — module-level | `(effect_id, effect_url)` positional | YES | none |
| `w.set_parameter_value(path, value)` (+ `pulse` via 1.0/0.0) | `set_parameter_value(port, value)` — module-level | `(port, value)` positional | YES | none |
| `w.connect_port(self._node(src), self._node(dst))` | `connect_port(src_port, target_port)` — module-level | `(src, tgt)` positional | YES | none |

Key structural agreement — VERIFIED:
- The 407 wrapper is a **module of plain functions** (not a class). Our
  transport takes `wrapper` as a constructor argument and only needs the
  three names callably present — `import ingen_wrapper` (the module
  object) satisfies that.
- Path convention agreement: 407 addresses ports by **full node/port path
  strings** (e.g. `/main/tone/output`) and `show_widget.py` itself calls
  `add_plugin(effect_name, …)` / `connect_port(s_effect, effect_id + "/" + port_name)`
  with full-path strings. Our `_node()` helper produces exactly
  `/main/sub1/<name>[/port]`, i.e. the same shape.

Additional 407 functions available (relevant to the planned FX layer;
PROPOSED usage, not yet exercised): `set_bypass(effect_id, active)`,
`remove_plugin(effect_id)`, `disconnect_plugin(effect_id)`,
`disconnect_port(src, tgt)`, `get_state(path)`, `set_file(effect_id,
file_name, is_cab, effect_type)`, `save_pedalboard(pedal_name, name,
current_sub_graph)`, `load_pedalboard(name, current_sub_graph)`,
`add_sub_graph(effect_id)`, `set_plugin_position`, `midi_learn/set_cc/forget`,
`spotlight_set/remove`, `add_input/add_output/add_midi_*`,
`connect_jack_port(port, x, y, physical_port)`, `set_json(_nam)`.

None of these conflict with our assumptions; none of them were modified
(this pass altered nothing — brief §28).

## 2. show_widget patch seam — our apply tool vs the real file

Checked with the v2.0.1 tree's `check_upstream.py` against the installed
`show_widget.py`: **PASS — all five apply anchors occur exactly once**
(VERIFIED):

| Anchor | Reality in 407 file |
|---|---|
| `import pedal_hardware` | line 51 |
| `current_sub_graph = "/main/sub1/"` | line 65 |
| `def handle_encoder_change(is_left, change):` | line 1729 (body currently `# debug_print(...)`-commented) |
| `current_action_group = 0` | line 1811 |
| `def handle_foot_change(switch_name, timestamp):` | line 1944 (body commented) |

Bootstrap seam (for reference, untouched): lines 2356–2358
(`change_pedal_model(pedal_state["model"], True)` + blank +
`available_effects = [QStringListModel() for i in range(4)]`), callback
registration at 2408–2409. `ingen_wrapper.py` was **never modified** by our
tools and must stay that way (no second client).

## 3. Hardware input layer (`pedal_hardware.py`) — VERIFIED

- Reads `/pedal_state/hardware_info.json` → hardware **revision 10**
  (`PEDAL_VERSION >= 10` branch is the live one).
- Encoder mapping (rev 10): left = `e.code 0`, right = `e.code 1`,
  **inverted sign** (`-e.value`); pre-10 mapping differs (left=1, right=0,
  `+e.value`). Our FX layer consumes deltas via
  `handle_encoder_delta(event_name[:4], change)` and is sign-agnostic in
  direction of travel — but tests/expectations must use rev-10 polarity on
  a 407 unit.
- Footswitches: evdev on `/dev/input/event2`, `initial_press = {30: True,
  48: True, 46: True}`; emits `foot_callback("tap_step_down"/
  "step_bypass_down", …)`. Knobs: `event1` `knob_left`, `event3` `knob_right`.

## 4. Verdict labels

- Wrapper API assumptions: **VERIFIED — COMPATIBLE** for the three transport
  call sites (Q14 of FINAL_407_AUDIT.md).
- show_widget patch seam: **VERIFIED — COMPATIBLE** (Q15).
- Actual behaviour of an applied extension on a real pedal: **TARGET-BLOCKED**.