Skip to content

Replace() removes only what a run drew for that output; no invented labels - #48

Merged
guijacquemet merged 1 commit into
mainfrom
claude/stardist-labconstrictor-plan-aizdd6
Nov 12, 2026
Merged

guijacquemet merged 1 commit into
mainfrom
claude/stardist-labconstrictor-plan-aizdd6

Conversation

@guijacquemet

Copy link
Copy Markdown
Contributor

Follow-up to #47, from an independent audit of that PR.

Problems

  • Q1 (high): Replace() removed every annotation whose classification matched <app>:<output>. An annotation the person drew and classified the same way was deleted with the results.
  • Q3: above 50 outlines the results have no name. If the person reclassified one, neither the name nor the class matched any more, so it survived next to the new results.
  • Q2: an outline without a label got a label measurement made from its position, which claims a match with the label image that need not exist. A text label was lost above 50 outlines, where there is no name to carry it.

Changes

  • Ownership tag: LcRun.tag(annotation, output) adds labconstrictor.output to the existing run_id, app and tool metadata of every point or outline annotation a run draws.

  • What Replace() removes: only annotations for which LcRun.ownedBy is true:

    • an annotation with an output tag: its app and output must match;
    • an annotation drawn by an earlier version (run metadata but no output tag): this app, plus its old name or class;
    • an annotation from before run metadata existed: its old name <app>:<output> (points) or <app>:<output> <n> (outlines).

    An annotation without LabConstrictor metadata is never removed because of its class.

  • Labels: a missing label gives the measurement outline_index; a text label is kept as metadata label; a numeric label stays the measurement label.

  • Docs: the README and user guide say what Replace() removes, how labels are stored, and that QuPath reads app:output as a derived class (app: output).

Tests

  • tests/gui_test_shapes_body.groovy (15 checks, was 7). New checks:
    • results carry their output tag;
    • the person's own annotation with the same class survives Replace();
    • a reclassified result is still replaced;
    • exactly 50 outlines are named, and 51 are not;
    • text, numeric and missing labels are stored as described.
  • Local run of tests/run_gui_ci.sh on QuPath 0.7.0 (JDK 25 build, xvfb): shapes 15, identity 35, area 48, parity_results 26, interactions 9, region 7 and conformance 119 checks all pass.

Not changed

  • Q4: keeping the derived class app: output is a design choice, now documented. It groups an app's outputs under one parent class.
  • Q5: the form-label width on narrow or HiDPI screens is untested; it's a separate follow-up.

Generated by Claude Code

…abels

From an independent audit of PR #47:
- Q1/Q3: Replace() matched annotations by classification (or name), so it could delete annotations the
  person classified the same way, and miss a result they reclassified. Every annotation a run draws now
  carries labconstrictor.output beside run_id/app/tool, and Replace() removes only annotations whose
  metadata says they are this app's output (LcRun.ownedBy). Results of earlier versions are recognised by
  their run metadata plus their old name/class; results of versions without run metadata by their name.
  Annotations without LabConstrictor metadata are never removed by class.
- Q2: an outline without a label got a "label" measurement made from its position, which claimed a match
  with the label image; it is now the measurement outline_index. A text label, lost above 50 outlines, is
  kept as metadata "label".
- Tests (gui_test_shapes_body): results carry their output; the person's annotation of the same class
  survives Replace; a reclassified result is still replaced; 50 named / 51 unnamed; text, numeric and
  missing labels. README and user guide say what Replace() removes and that app:output is a derived class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WX6rdRdA72nsUjZvTXFSbP
@guijacquemet
guijacquemet merged commit 065809e into main Nov 12, 2026
2 checks passed
@guijacquemet
guijacquemet deleted the claude/stardist-labconstrictor-plan-aizdd6 branch November 12, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants