Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ src/morphobricks_preprocessing/
description_file.py read_description(path): symlink refusal (R_FILE_SYMLINK), bytes -> Description
run/description_file.py publish_description: lock, base SHA-256, strict re-read, transitions,
atomic write, append-only morphobricks.records.jsonl (Spec experiment-v1 4.6, 10)
draft_ids.py proposed IDs: the folder label or raw header name only when the reader would
accept it as written, else none (never repaired); draft.py the draft
(IdSlot proposed/confirmed, open questions, unit_rows with condition_id,
repeat_group, technical_repeat_id) and migrate_legacy_design
image_type.py image type (P4): FLUORESCENCE/RGB, review_image_type (suggestion from
TiffMetadata.rgb_samples and the confirmed roles, whether RGB is possible via the
brick's check_rgb), image_type_issues (rgb_not_possible)
Expand Down
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,24 @@ are in [docs/plan.md](docs/plan.md) §12. Upgrading from v0.3: see the
a changed image count alone is refused (new FOVs do not reopen a confirmation, section 10); the
Spec's validator accepts it. Copying the records into the run manifest is a later pull request.
Not used by any run, notebook or CLI command yet.
- **Draft description, proposed IDs and legacy design migration (Stage 1, PR 7).** New
modules `draft_ids` and `draft`, and `design.parse_design_bytes` (the
former private `_parse_strict`, now public: the strict parse, no confirmation required). A folder label is proposed as a condition,
technical-repeat or biological-repeat ID only when the reader would accept it as written
(Spec 4.6a; the same rule for repeat IDs): `control`, `files` or `z` get no proposal, nothing is
repaired, derived or renamed. A raw header name is proposed as a channel ID only when it is a
valid ID as it stands (never trimmed or repaired; `R`, `G`, `B` never). A draft keeps IDs as
*proposed* until `confirm_id`, lists its open questions, and offers the added `condition_id`,
`repeat_group` and `technical_repeat_id` beside the unchanged source labels.
`migrate_legacy_design` reads `experiment_design.csv` strictly (`yes`/`no`/empty refused),
carries `repeat_group` as the proposed repeat ID, takes the latest `confirmed_on` of a group
with several dates and lists the original dates in a note (never the clock), maps 0, 1 or 2+
marked controls to no reference, one reference per condition or an open question, and refuses a
design that breaks a Spec rule with the reader's code. A legacy `repeat_group` that is not an
allowed repeat ID (`z`, `files`) is not refused: it migrates with no proposed ID and an open
question, so the user names the repeat (Spec 4.6a; owner decision of 7 November 2026). Where the Spec says "another allowed
ID" for a forbidden folder there is no proposal: no rule for making one was given. Nothing is
written and no run, notebook or CLI command uses it yet.
- **Experiment-description model, canonical writer and section digests (Stage 1, PR 4).** New
modules `description` (the `Description` model; `description_from_bytes` reads with the strict
reader and raises `DescriptionError` with every issue of the first failing phase) and
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ baseline = "tools/code_rules_baseline.json"
"morphobricks_preprocessing.design" = "io"
"morphobricks_preprocessing.design_values" = "pure"
"morphobricks_preprocessing.description_identity" = "pure"
"morphobricks_preprocessing.draft_ids" = "pure"
"morphobricks_preprocessing.draft" = "io"
"morphobricks_preprocessing.physical_check" = "io"
"morphobricks_preprocessing.description" = "pure"
"morphobricks_preprocessing.description_write" = "pure"
Expand Down
6 changes: 3 additions & 3 deletions src/morphobricks_preprocessing/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ def read_confirmed_design(
)
try:
data = path.read_bytes()
design = _parse_strict(data, path.name)
design = parse_design_bytes(data, path.name)
except (OSError, DesignFormatError) as exc:
raise _unreadable(path, exc, rerun) from exc
issues = design_issues(design)
Expand Down Expand Up @@ -740,8 +740,8 @@ def _unreadable(path: Path, exc: Exception, action: str) -> DesignCheckError:
)


def _parse_strict(data: bytes, name: str) -> ExperimentDesign:
"""Parse a design as :func:`write_experiment_design` writes it, refusing anything else."""
def parse_design_bytes(data: bytes, name: str = DESIGN_FILENAME) -> ExperimentDesign:
"""Parse a design as :func:`write_experiment_design` writes it; confirmation not required."""
if data.startswith(b"\xef\xbb\xbf"):
raise DesignFormatError(
f"{name} starts with a byte-order mark: it was saved by another program, not "
Expand Down
Loading
Loading