Repository navigation
Parent-label (grouped) masks: re-pin Spec 69a58b3, resolver contract v2 - #289
Merged
Merged
Conversation
MorphoBricks-Spec PR #28 (merge 69a58b3, ADR 0001 PL1; experiment-v1 4.5, 4.5a-4.5c, 7, 8; ADR 0002 resolver contract version 2). - Re-vendor the Spec at 69a58b3 with its tools/vendor.py (--check identical); SPEC_COMMIT follows. Conformance counts follow (39 valid, 138 invalid, 69 phase 1-3); v38 and v39 join the oracle mutations; new module test_spec_parent_labels (v38/v39, i136-i139, i111 retired). - representation = "parent_labels": reader enum, mask answers ("grouped labels"), the overlay (each group in its own colour). Never pre-filled from the scan's grouped kind. The mask step records such a file checked once read (4.5a, no other condition). - Resolver contract v2: Capabilities.parent_labels_support; as objects A_MASK_NOT_INSTANCES with or without it, its message no longer suggests binary_mask_policy; a policy on it is a ValueError saying it is never converted; as a region the groups with the capability, else MaskSelection.conversion = "parent_labels_as_area" (PARENT_LABELS_AS_AREA). - Mask step pieces counted 8-connected (CellPatcher's BINARY_MASK_CONNECTIVITY = 2 structure, not imported); mask_relationships.json report version 4. - Notebook (minimal): Your masks offers "grouped labels (one value per parent, e.g. mitochondria by cell)"; question texts name the third answer. - Docs: contract, user guide, plan question 80, conformance record, AGENTS map, CHANGELOG. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
The PR read the three flags before the isinstance check, so a request whose
capabilities were None, a dict or a bool raised AttributeError instead of the
contract's ValueError ("capabilities must be Capabilities of bool"). On main the
check short-circuited. Restore the order; regression test in
tests/test_spec_parent_labels.py fails before the fix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
The section heading said report version 4 but the key table still said `report_version` is 3. A test now ties the heading, the row and MASK_REPORT_VERSION together; it fails before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Contributor
Author
Independent reviewVerdict: correct against Spec Fixes
Checked independently
Gate (Linux, Python 3.13,
|
guijacquemet
marked this pull request as ready for review
November 12, 2026 02:11
guijacquemet
pushed a commit
that referenced
this pull request
Nov 12, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
guijacquemet
pushed a commit
that referenced
this pull request
Nov 12, 2026
682e14e) Not for merging: RELEASE_REF points at main as merged (#284-#287, with #289) so the owner can test it in Colab. Only RELEASE_REF changes; cell 3 calls PreprocessingNotebook(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements MorphoBricks-Spec PR #28 (merge
69a58b3e2f89b318364c4c1252c54caf676fb6bb, ADR 0001 PL1):representation = "parent_labels"in experiment-description v1, and resolver contract version 2 (ADR 0002). Branch frommainata775ebf.Summary (by module)
tests/spec_fixtures/,draft_format.SPEC_COMMIT): re-vendored at69a58b3with the Spec's owntools/vendor.py.vendor.py --checksays the folder is identical. The new fixtures arev38,v39,i136toi139, andi111is removed. The conformance counts are now 39 valid, 138 invalid and 69 in phases 1 to 3.v38andv39were added to the oracle mutation set. The new Spec moduletests/test_spec_parent_labels.pyis registered inspec_gate.EXPECTED_MODULES. It coversv38/v39accepted,i136/i137E_ENUM,i138/i139E_UNKNOWN_FIELD, andi111retired with its number not reused.description_rules.REPRESENTATIONS,mask_answers):parent_labelsis now an accepted value (§4.5, §4.5b). In the notebook's words it is "grouped labels". The scan'sgroupedandParent_Labelsare stillE_ENUM.check_representationalready reads distinct values forbinaryonly, so aparent_labelsfile is recordedcheckedonce it has been read, with no other condition. Tests show this on av38run with three values per file. They also show that the file isA_MASK_UNCHECKEDbefore the mask step.run_inputs_request,run_inputs_resolve; ADR 0002 "Resolver contract version 2"):RESOLVER_VERSION = 2.Capabilities.parent_labels_support(bool, False by default). A value that is not a bool is aValueError.A_MASK_NOT_INSTANCESwith or without the capability. The message was rewritten: it no longer suggestsbinary_mask_policy(the old text atrun_inputs_request.py:~426). It now says the mask is never split, relabelled or converted, and to use it as a region.binary_mask_policyon aparent_labelsmask, in either role, is aValueErrorwhose message says the same.MaskSelection(representation="parent_labels", conversion="parent_labels_as_area"). The marker is exported asPARENT_LABELS_AS_AREA.instancesandbinaryselections are unchanged.mask_scan.piece_counts,mask_pairs.PIECE_STRUCTURE): pieces are now counted 8-connected, withgenerate_binary_structure(2, 2). This is the structure of CellPatcher'sBINARY_MASK_CONNECTIVITY = 2(checked at CellPatcher2b98fa1,object_geometry.py:40). CellPatcher is not imported because preprocessing does not depend on it.mask_relationships.jsongoes to report version 4: this follows the repository's precedent of bumping the version when the meaning of a count changes (2 for the matching, 3 for ties). The constant lives inmask_pairs.pyso thatmask_scan.pystays within the 600-line code rule.preview_render): aparent_labelsmask is drawn as outlines coloured by value, so all pieces of one group share a colour.testing_described._write_mask): aparent_labelsmask is two groups of two separate squares each. Other representations are unchanged.R_MASK_CONTRADICTS_REPRESENTATIONnow namesparent_labelsbesideinstances(§4.5).masksrow), user guide, plan question 80, a conformance record, the AGENTS map and the CHANGELOG (Breaking: API resolver v2).Notebook files touched (kept minimal, for the
claude/redesign3-*merge)src/morphobricks_preprocessing/notebook_mask_question.py: a third option, "grouped labels (one value per parent, e.g. mitochondria by cell)", the caption for it, and the docstring. There is still no default.src/morphobricks_preprocessing/notebook_masks_screen.py: the intro text, the purpose line and docstrings.src/morphobricks_preprocessing/notebook_check_save.py: one line ("separate objects, regions or grouped labels? (Masks)").The question stays one column with no inner scroll box. Its only disabled control (made from) already shows its reason, and a test asserts all three.
Spec citations
experiment-v1 §4.5 (value, user-confirmed, never inferred), §4.5a (checked once read), §4.5b (identity, not instances, capability, use as region), §4.5c (no conversion for
parent_labels), §7 (amendment of v1), §8 (A_MASK_NOT_INSTANCES). Also ADR 0001 PL1, ADR 0002 "Resolver contract version 2", and the conformance plan §2 "Mask fields" and §4 "Parent labels" rows.Evidence
main: the new tests were run againstmain's code with the new pin. 19 failed. They cover the pin,v38/v39,i138/i139, the answer, the mask check (two tests), resolver v2, objects with and without the capability, the message, the policy in both roles, the region with and without the capability, the bool check, and 8-connected pieces (test_pieces_are_8_connected_and_counted_per_label: 3 pieces become 1). Five tests pass onmainbecause they guard existing behaviour:i136/i137were alreadyE_ENUM,grouped/Parent_Labelswere already refused as answers, andi111is absent once re-vendored. The notebook test fails onmainbecause the option does not exist there.make_described_runwas run onv07(twoinstancesmasks),v08(instances+binary) andv13(no masks) withmain's and this branch's code, on the same fixture bytes. Every input TIFF,plane_histograms.csv,morphobricks.tomlandexperiment_design.csvis byte-identical.run_manifest.json,discovery_report.*andmask_representation.jsondiffer only inmtime_ns,written_at, the absolute folder and the manifest SHA-256 derived from them. Two runs ofmaindiffer in exactly the same files and fields. After normalising those fields, the only difference ismask_relationships.jsonwith"report_version": "3"→"4", from the 8-connected counting. Its counts and kinds are identical for these masks. No output records the Spec pin; only the draft file'sspec_commitdoes, and no draft is written here.Tests
python tools/check.py(Linux, Python 3.13.18, fresh venv.[dev,notebook,zarr]): Ruff clean, 443 files formatted, pytest 5396 passed, 4 skipped, 0 failed, code rules passed, exit 0.The 4 skips are environment skips outside the Spec modules:
test_cli_log.py:166,test_folder_rules.py:199andtest_folder_rules.py:230: the file system is case-sensitive.test_discovery.py:665: the tests run as root, which ignores file modes.Spec modules
tests/test_spec_*.py: 1796 passed, 0 skipped (25 modules).Notes for review
report_versionbump for the mask scan, following the repository's precedent. The task did not ask for it. Nothing reads the report back (plan Q74 checked the consumers on 3 November).docs/pins.mdrow for preprocessing is not updated here, because the Spec is another repository.describe(CLI) asks nothing about masks, so it has nothing to pre-fill and is unchanged.Follow-ups
parent_labels_supportand move the parity, HPMEC and JUMP-mito datasets back to described runs (and remove the in-memory route of Re-pin Spec 1bed024; read_records follows §4.6 (R_RECORDS_FILE_INVALID) #242/Described runs: pixel-type and dimension checks per unit (#239, narrowed) #243).parent_labels_supportfrom provider manifests (rules ofrgb_support; a non-bool value is a manifest error) and pass it inCapabilities.parent_labelsmasks in region roles as an area when they getconversion = "parent_labels_as_area", record the marker with the mask ID and show it.docs/pins.md: move preprocessing's row to69a58b3after merge.Generated by Claude Code