Feature: Stage 3 - chartread -u Subprocess State Machine & Keystroke Controller #5

Closed
opened 2026-08-21 10:29:29 +01:00 by gronod · 0 comments
Owner

Description

Implement the interactive measurement controller for Stage 3. This is the most complex stage — the Rust backend spawns chartread -u and maintains a bidirectional pipe. The frontend presents a state-machine-driven UI that reacts to stdout prompts and lets the user inject keystrokes via stdin.

Toolchain Context

  • Backend: Rust (Tauri 2) — uses ProcessManager::spawn() for bidirectional IPC, ProcessManager::send_stdin() for keystroke injection
  • Frontend: Vanilla JS with window.__TAURI__.core.listen() for real-time event streaming
  • Upstream: Uses the custom chartread -u flag from gronod/argyllcms for JSON streaming

Implementation Plan

Backend (Rust)

  1. New Tauri command commands::run_chartread(app, state, config):
    • Accept ChartreadConfig struct: { basename: String, extra_args: Vec<String> }
    • Build args: ["-v", "-u", <basename>]
    • Spawn via ProcessManager; the existing stdout/stderr line readers in process_manager.rs automatically emit process:stdout events
  2. Structured event routing: Add a new event emitter emit_json_row(app, id, json_str) in events.rs that fires process:json_row when a stdout line matches the ROW_COLORS_JSON: prefix. This separates structured data from human-readable prompts.
  3. Stdin relay: The existing commands::send_stdin() command is sufficient — the frontend sends " \n" (space+newline) for calibrate, "s\n" for skip, "q\n" for quit.

Frontend (JavaScript)

  1. Chartread state machine (src/js/chartread.js):
    States: IDLE → CALIBRATING → AWAITING_STRIP → READING → ERROR → FINISHED
    
    • process:stdout lines parsed for prompt keywords to drive state transitions
    • process:json_row events parsed as JSON and dispatched to the swatch grid renderer
    • process:exit transitions to FINISHED
  2. User interaction buttons:
    • "Place instrument on calibration tile & press Calibrate" → send_stdin(" \n")
    • "Retry Strip" → send_stdin(" \n")
    • "Skip Strip" → send_stdin("s\n")
    • "Cancel Reading" → kill_process("chartread")
  3. UI prompt area: Dynamic text area showing the current instruction from chartread's human-readable stdout output.

New/Modified Files

  • [MODIFY] src-tauri/src/commands.rs — add run_chartread command
  • [MODIFY] src-tauri/src/events.rs — add emit_json_row with process:json_row event type
  • [MODIFY] src-tauri/src/process_manager.rs — add ROW_COLORS_JSON prefix detection in stdout reader
  • [MODIFY] src/index.html — expand Stage 3 panel with state-driven UI, button cluster, prompt area
  • [NEW] src/js/chartread.js — state machine, event listeners, stdin commands
  • [MODIFY] src/styles/main.css — state machine panel styles

Acceptance Criteria

  • chartread -u spawns and stdout/stderr lines stream to frontend in real-time
  • ROW_COLORS_JSON lines parsed and emitted as structured process:json_row events
  • UI transitions between states based on stdout prompt keywords
  • Calibrate, Retry, Skip, and Cancel buttons inject correct keystrokes via stdin
  • Process exit produces a .ti3 file and transitions to Stage 4
  • Read errors (too fast/slow) detected and user prompted to retry

References

### Description Implement the interactive measurement controller for Stage 3. This is the most complex stage — the Rust backend spawns `chartread -u` and maintains a bidirectional pipe. The frontend presents a state-machine-driven UI that reacts to stdout prompts and lets the user inject keystrokes via stdin. ### Toolchain Context - **Backend**: Rust (Tauri 2) — uses `ProcessManager::spawn()` for bidirectional IPC, `ProcessManager::send_stdin()` for keystroke injection - **Frontend**: Vanilla JS with `window.__TAURI__.core.listen()` for real-time event streaming - **Upstream**: Uses the custom `chartread -u` flag from [gronod/argyllcms](https://git.i3omb.com/gronod/argyllcms) for JSON streaming ### Implementation Plan #### Backend (Rust) 1. **New Tauri command** `commands::run_chartread(app, state, config)`: - Accept `ChartreadConfig` struct: `{ basename: String, extra_args: Vec<String> }` - Build args: `["-v", "-u", <basename>]` - Spawn via `ProcessManager`; the existing stdout/stderr line readers in `process_manager.rs` automatically emit `process:stdout` events 2. **Structured event routing**: Add a new event emitter `emit_json_row(app, id, json_str)` in `events.rs` that fires `process:json_row` when a stdout line matches the `ROW_COLORS_JSON:` prefix. This separates structured data from human-readable prompts. 3. **Stdin relay**: The existing `commands::send_stdin()` command is sufficient — the frontend sends `" \n"` (space+newline) for calibrate, `"s\n"` for skip, `"q\n"` for quit. #### Frontend (JavaScript) 1. **Chartread state machine** (`src/js/chartread.js`): ``` States: IDLE → CALIBRATING → AWAITING_STRIP → READING → ERROR → FINISHED ``` - `process:stdout` lines parsed for prompt keywords to drive state transitions - `process:json_row` events parsed as JSON and dispatched to the swatch grid renderer - `process:exit` transitions to FINISHED 2. **User interaction buttons**: - "Place instrument on calibration tile & press Calibrate" → `send_stdin(" \n")` - "Retry Strip" → `send_stdin(" \n")` - "Skip Strip" → `send_stdin("s\n")` - "Cancel Reading" → `kill_process("chartread")` 3. **UI prompt area**: Dynamic text area showing the current instruction from chartread's human-readable stdout output. #### New/Modified Files - `[MODIFY]` `src-tauri/src/commands.rs` — add `run_chartread` command - `[MODIFY]` `src-tauri/src/events.rs` — add `emit_json_row` with `process:json_row` event type - `[MODIFY]` `src-tauri/src/process_manager.rs` — add ROW_COLORS_JSON prefix detection in stdout reader - `[MODIFY]` `src/index.html` — expand Stage 3 panel with state-driven UI, button cluster, prompt area - `[NEW]` `src/js/chartread.js` — state machine, event listeners, stdin commands - `[MODIFY]` `src/styles/main.css` — state machine panel styles ### Acceptance Criteria - [ ] chartread -u spawns and stdout/stderr lines stream to frontend in real-time - [ ] ROW_COLORS_JSON lines parsed and emitted as structured `process:json_row` events - [ ] UI transitions between states based on stdout prompt keywords - [ ] Calibrate, Retry, Skip, and Cancel buttons inject correct keystrokes via stdin - [ ] Process exit produces a `.ti3` file and transitions to Stage 4 - [ ] Read errors (too fast/slow) detected and user prompted to retry ### References - [chartread_integration_guide.md](https://git.i3omb.com/gronod/argyllcms/src/branch/feature/chartread-json-output/doc/chartread_integration_guide.md) - [README.md §6 — Stage 3: Interactive Measurement](README.md#6-stage-3-interactive-measurement-chartread)
gronod added this to the Milestone 3: Interactive Reading Engine milestone 2026-08-21 10:29:29 +01:00
Sign in to join this conversation.