bug(stage3): Multi-pass averaging overwrites the same .ti3 (v0.3.3) #109

Closed
opened 2026-08-26 14:36:41 +01:00 by gronod · 1 comment
Owner

bug(stage3): Multi-pass averaging overwrites the same .ti3 file

Field Value
Labels Kind/Bug, Priority/Critical, Reviewed/Confirmed
Priority Critical
Milestone v0.3.3 hotfix
Related #87 (closed, incomplete)
Branch fix/averaging-unique-ti3 (from development)
Pair with 02-stage4-unlock.md — same PR

Description

Issue #87 shipped a multi-pass averaging UI, but every chartread invocation still writes {basename}.ti3. Pass 2 overwrites pass 1 on disk. run_average is then invoked with duplicate identical filenames (["foo.ti3", "foo.ti3"]foo.ti3), so Argyll average never sees two distinct measurement sets.

This is a functional failure of the closed #87 acceptance criteria. The average binary is bundled under src-tauri/argyll/. The defect is exclusively file identity.

Current behaviour

On process:exit code 0 in src/js/chartread.js:

recordedPasses.push({
  index: currentPassIndex,
  filename: `${basename}.ti3`,
  time: new Date().toLocaleTimeString(),
});
  • chartread process id is always chartread_${basename}.
  • run_chartread always uses config.basename as the Argyll inoutfile.
  • #btnMeasureAnotherSheet immediately re-clicks Start Measurement against the same basename.

Backend build_average_args is already correct:

-v infile1.ti3 infile2.ti3 outfile.ti3

Proposed solution

Do not change the chartread inoutfile to _passN during the read. printtarg / .ti2 still use basename. Always read as basename, then snapshot the .ti3 after a successful exit.

After each successful chartread exit (code 0):

  1. Copy {cwd}/{basename}.ti3 to {cwd}/{basename}_pass{N}.ti3 where N is 1-based and never reused in the session.
  2. Record that unique filename in recordedPasses.
  3. Keep {basename}.ti3 as the canonical Stage 4 input:
    • Single pass: copy basename_pass1.ti3basename.ti3 (or keep the original and also keep a pass copy).
    • Multi-pass: average -v basename_pass1.ti3 basename_pass2.ti3 … basename.ti3.
  4. Guard against a second chartread_${basename} spawn while the previous child is still in the process map. Measure Another Sheet must wait until the previous process has exited and the pass file has been snapshotted.

Preferred helper (Rust, atomic, cross-platform):

snapshot_ti3(cwd, basename, pass_index) -> Result<String>

Copies {cwd}/{basename}.ti3{cwd}/{basename}_pass{N}.ti3 and returns the new filename (relative, so average args stay relative to cwd).

Do not implement this via invoke('read_file_base64') plus a rewrite. It is a filesystem copy.

Files

  • src/js/chartread.js — pass snapshot, average inputs, button enablement
  • src-tauri/src/commands.rs — optional snapshot_ti3 command and unit test
  • src-tauri/src/lib.rs — register the command if added

Acceptance criteria

  • Two successive sheet measurements produce two distinct files on disk (*_pass1.ti3 and *_pass2.ti3) whose contents differ if the readings differ.
  • average -v {basename}_pass1.ti3 {basename}_pass2.ti3 {basename}.ti3 is the actual argv (unit test on build_average_args plus a UI log line).
  • After a successful average, {basename}.ti3 exists and is the file Stage 4 / verify_stage_artefacts uses.
  • A single-pass Finish still yields {basename}.ti3 and does not invoke average.
  • Re-running pass 2 does not destroy pass 1.
  • Manual test note on the PR: Windows and Linux, two dummy or mock passes (chartread.mock if present).

Dependencies

None. Do this before any other Stage 3 work. Implement with issue 02 in the same PR.

# bug(stage3): Multi-pass averaging overwrites the same .ti3 file | Field | Value | |---|---| | Labels | `Kind/Bug`, `Priority/Critical`, `Reviewed/Confirmed` | | Priority | Critical | | Milestone | v0.3.3 hotfix | | Related | #87 (closed, incomplete) | | Branch | `fix/averaging-unique-ti3` (from `development`) | | Pair with | [02-stage4-unlock.md](02-stage4-unlock.md) — same PR | ## Description Issue #87 shipped a multi-pass averaging UI, but every `chartread` invocation still writes `{basename}.ti3`. Pass 2 overwrites pass 1 on disk. `run_average` is then invoked with duplicate identical filenames (`["foo.ti3", "foo.ti3"]` → `foo.ti3`), so Argyll `average` never sees two distinct measurement sets. This is a functional failure of the closed #87 acceptance criteria. The `average` binary **is** bundled under `src-tauri/argyll/`. The defect is exclusively file identity. ## Current behaviour On `process:exit` code 0 in `src/js/chartread.js`: ```javascript recordedPasses.push({ index: currentPassIndex, filename: `${basename}.ti3`, time: new Date().toLocaleTimeString(), }); ``` - `chartread` process id is always `chartread_${basename}`. - `run_chartread` always uses `config.basename` as the Argyll inoutfile. - `#btnMeasureAnotherSheet` immediately re-clicks Start Measurement against the same basename. Backend `build_average_args` is already correct: ```text -v infile1.ti3 infile2.ti3 outfile.ti3 ``` ## Proposed solution Do **not** change the `chartread` inoutfile to `_passN` during the read. `printtarg` / `.ti2` still use `basename`. Always read as `basename`, then snapshot the `.ti3` after a successful exit. After each successful `chartread` exit (code 0): 1. Copy `{cwd}/{basename}.ti3` to `{cwd}/{basename}_pass{N}.ti3` where N is 1-based and never reused in the session. 2. Record that unique filename in `recordedPasses`. 3. Keep `{basename}.ti3` as the **canonical** Stage 4 input: - Single pass: copy `basename_pass1.ti3` → `basename.ti3` (or keep the original and also keep a pass copy). - Multi-pass: `average -v basename_pass1.ti3 basename_pass2.ti3 … basename.ti3`. 4. Guard against a second `chartread_${basename}` spawn while the previous child is still in the process map. **Measure Another Sheet** must wait until the previous process has exited and the pass file has been snapshotted. Preferred helper (Rust, atomic, cross-platform): ```text snapshot_ti3(cwd, basename, pass_index) -> Result<String> ``` Copies `{cwd}/{basename}.ti3` → `{cwd}/{basename}_pass{N}.ti3` and returns the new filename (relative, so `average` args stay relative to cwd). Do not implement this via `invoke('read_file_base64')` plus a rewrite. It is a filesystem copy. ## Files - `src/js/chartread.js` — pass snapshot, average inputs, button enablement - `src-tauri/src/commands.rs` — optional `snapshot_ti3` command and unit test - `src-tauri/src/lib.rs` — register the command if added ## Acceptance criteria - [ ] Two successive sheet measurements produce two distinct files on disk (`*_pass1.ti3` and `*_pass2.ti3`) whose contents differ if the readings differ. - [ ] `average -v {basename}_pass1.ti3 {basename}_pass2.ti3 {basename}.ti3` is the actual argv (unit test on `build_average_args` plus a UI log line). - [ ] After a successful average, `{basename}.ti3` exists and is the file Stage 4 / `verify_stage_artefacts` uses. - [ ] A single-pass Finish still yields `{basename}.ti3` and does not invoke `average`. - [ ] Re-running pass 2 does not destroy pass 1. - [ ] Manual test note on the PR: Windows and Linux, two dummy or mock passes (`chartread.mock` if present). ## Dependencies None. Do this before any other Stage 3 work. Implement with issue 02 in the same PR.
gronod added this to the v0.3.3 Hot fixes milestone 2026-08-26 14:36:41 +01:00
gronod added the Kind/Bug
Reviewed
Confirmed
1
Priority
Critical
1
labels 2026-08-26 14:36:41 +01:00
Author
Owner

Resolved and verified in milestone v0.3.3 Hot fixes via PR #118 (Fix/averaging unique ti3).

Resolution Summary:

  • Implemented pass snapshotting logic to ensure each measurement iteration creates a unique {basename}_pass{N}.ti3 file.
  • Prevented premature overwriting of {basename}.ti3.
  • Updated Argyll average invocation args to reference all distinct pass files before generating the final canonical {basename}.ti3 output for Stage 4.
Resolved and verified in milestone `v0.3.3 Hot fixes` via PR #118 (`Fix/averaging unique ti3`). ### Resolution Summary: - Implemented pass snapshotting logic to ensure each measurement iteration creates a unique `{basename}_pass{N}.ti3` file. - Prevented premature overwriting of `{basename}.ti3`. - Updated Argyll `average` invocation args to reference all distinct pass files before generating the final canonical `{basename}.ti3` output for Stage 4.
Sign in to join this conversation.