Skip to content

fix: respect user numTargets and dimensions in IED morphobes task - #1

Merged
iandol merged 1 commit into
mainfrom
fix/ied-morphobes-dimensions
Aug 3, 2026
Merged

fix: respect user numTargets and dimensions in IED morphobes task#1
iandol merged 1 commit into
mainfrom
fix/ied-morphobes-dimensions

Conversation

@iandol

@iandol iandol commented Aug 2, 2026

Copy link
Copy Markdown
Member

Bug Description

Running cltasks.startIEDmorphobes with numTargets=4 and edDimension='appendages' still produced two targets using colour+shape dimensions.

Root Cause

Two bugs in the input pipeline:

  1. clutil.checkInput unconditionally overwrote user fields. For task='ied' (which the CageLab GUI always sends), checkInput forced numTargets=2, idDimension='colour', edDimension='shape', plus criterion/maxIncorrect/taskType. Any caller-supplied values were silently discarded before the task ran.
  2. Dimension validation was singular-only. validDims = {'shape','colour','appendage','texture'} rejected the plural 'appendages' (and mixed case), falling back to 'shape'.

A third latent bug: the GUI's Task Order field uses a MATLAB array-literal format '[ "sd" "sr" ... ]' that the old stage parser would have collapsed.

Fix

  • +clutil/checkInput.m — capture userFields before applying defaults; a new applyIedDefaults helper only fills fields the caller didn't supply. numTargets=4 now survives (with 4D sizing 8/12), numTargets=2 keeps 2D sizing (10/15); criterion/maxIncorrect/taskType overrides are respected too.
  • +clutil/normaliseDimension.m (new) — maps plural/case/whitespace variants to canonical names ('appendages'→'appendage'), returns '' for invalid dimensions.
  • +cltasks/startIEDmorphobes.m — uses normaliseDimension; robust stage parser that strips [ ] " ' , ; from GUI-style taskType; warns (ConstantEDDimension) when the chosen ED dimension has no variance in set 3 (e.g. appendage ED with numTargets=2), pointing the user to 4D.
  • +cltasks/startIEDmorphobes4D.m — deleted (unused; 4D behaviour lives in the unified startIEDmorphobes.m via numTargets=4).
  • tests/ClutilTest.m — fixed pre-existing failure: checkInput default is 'train' (changed in cf8a245), test expected 'generic'.
  • tests/StartIEDMorphobesTest.m — 8 new regression tests (user overrides preserved, normaliseDimension edge cases, ED-dimension shift usage, GUI taskType parsing, constant-ED warning).

How to Verify

  1. clutil.checkInput(struct('task','ied','numTargets',4))numTargets=4, objectSize=8, objectSep=12
  2. clutil.checkInput(struct('task','ied','numTargets',4,'edDimension','appendages')) → preserved
  3. Task EDS/EDR stage now switches to the configured ED dimension (relDim = in.edDimension)

Test Plan

  • Added regression tests for this bug
  • Existing tests still pass — full CI suite: 55 passed, 0 failed
  • Manual verification of the fix (MATLAB batch checks above)

Risk Assessment

Low — input-default handling and dimension validation only; no changes to trial loop, stimulus selection, or data logging. The checkInput behaviour change means previously-stomped user overrides now take effect, which is the intended fix.

Summary by CodeRabbit

  • New Features

    • Added more flexible task configuration, including GUI-formatted stage definitions and case-insensitive dimension names.
    • Added support for preserving custom target counts, dimensions, and criteria.
    • Added warnings when the selected extra-dimensional feature is constant in a 2D task.
  • Bug Fixes

    • Improved handling of empty task stages and missing stage definitions.
    • Updated default task behavior to use training settings.
    • Removed the legacy four-dimensional morphobes task.

checkInput was unconditionally overwriting task-specific defaults for
task='ied', so a user's numTargets=4 became 2 and edDimension='appendage'
became 'shape'. Only apply IED defaults to fields the caller did not
explicitly supply, and let 4D sizing follow numTargets.

- add clutil.normaliseDimension to accept plural/case variants
  (appendages -> appendage) and reject invalid dimensions
- robust stage parsing for the GUI array-literal taskType format
- warn when the ED dimension has constant levels in set 3 (EDS/EDR)
- delete unused startIEDmorphobes4D.m; behaviour now lives in the
  unified startIEDmorphobes.m with numTargets=4
- fix ClutilTest to expect checkInput default task='train'
- add regression tests for overrides, normalisation and stage parsing
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

IED input handling now preserves caller values, normalizes dimensions, parses GUI task stages, and warns about constant ED dimensions. The 4D morphobes task file was removed. Tests cover the updated defaults and task behavior.

Changes

IED task configuration

Layer / File(s) Summary
Input defaults and dimension normalization
+clutil/checkInput.m, +clutil/normaliseDimension.m
IED defaults preserve supplied values and select target counts. Dimension names accept case, whitespace, and plural variants.
Morphobes task flow
+cltasks/startIEDmorphobes.m, +cltasks/startIEDmorphobes4D.m
The task parses GUI-formatted stages, uses configured dimensions, changes dimension defaults, and warns when ED has fewer than two levels. The 4D task implementation was deleted.
Regression coverage
tests/StartIEDMorphobesTest.m, tests/ClutilTest.m
Tests cover IED settings, dimension normalization, task-stage parsing, ED/ID dimension usage, constant ED warnings, and the train default.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant checkInput
  participant startIEDmorphobes
  participant normaliseDimension
  Caller->>checkInput: Provide IED settings
  checkInput->>checkInput: Apply missing defaults
  checkInput-->>startIEDmorphobes: Return configured inputs
  startIEDmorphobes->>normaliseDimension: Normalize ID and ED dimensions
  normaliseDimension-->>startIEDmorphobes: Return canonical dimensions
  startIEDmorphobes->>startIEDmorphobes: Parse task stages and validate ED levels
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: preserving user-supplied numTargets and dimensions in the IED morphobes task.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ied-morphobes-dimensions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @+clutil/checkInput.m:
- Around line 124-141: Constrain IED target counts before applying defaults: in
the fixed-variant branch for task values {'ied-2' 'ied-4'}, assign the computed
n back to in.numTargets before calling applyIedDefaults so each variant always
uses its required count. In the classic 'ied' branch, validate the supplied or
default n and reject any value other than 2 or 4 before applyIedDefaults; add
regression coverage for both fixed variants and an unsupported classic target
count.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5950d3d3-32d2-45bf-9bc5-94b5a7fc708d

📥 Commits

Reviewing files that changed from the base of the PR and between cf8a245 and 52de8cb.

📒 Files selected for processing (6)
  • +cltasks/startIEDmorphobes.m
  • +cltasks/startIEDmorphobes4D.m
  • +clutil/checkInput.m
  • +clutil/normaliseDimension.m
  • tests/ClutilTest.m
  • tests/StartIEDMorphobesTest.m
💤 Files with no reviewable changes (1)
  • +cltasks/startIEDmorphobes4D.m

Comment thread +clutil/checkInput.m
Comment on lines +124 to +141
% Classic 'ied' defaults to 2D, but if the caller explicitly
% sets numTargets=4 then 4D sizing follows.
n = 2;
if isfield(in, 'numTargets') && ~isempty(in.numTargets)
n = in.numTargets;
end
if n == 4
in = applyIedDefaults(in, userFields, 4, 8, 12);
else
in = applyIedDefaults(in, userFields, 2, 10, 15);
end
case {'ied-2' 'ied-4'}
in.taskType = 'sd cd cr ids idr eds edr'; % stages run in sequence
in.idDimension = 'colour'; % 'shape','colour','appendage','texture' — ID dim
in.edDimension = 'shape'; % 'shape','colour','appendage','texture' — ED dim
in.criterion = 6; % consecutive correct to advance
in.maxIncorrect = 50; % incorrect trials on stage before task terminates
in.objectSize = 8; % size of objects in degrees
in.objectSep = 12; % separation of objects in degrees
in.sampleY = 0; % vertical centre of the 2x2 grid in degrees
in.trialTime = 5.0; % max trial time in seconds
in.targetHoldTime = 0.2; % target hold time in seconds
in.morphobesFolder = ''; % morphobes dataset folder (defaults to resources/morphobes)
in.fixSize = 2; % fixation size in degrees
in.fixWindow = 4; % fixation window size in degrees
if strcmp(in.task, 'ied-2')
in.numTargets = 2; % 2D variant: two targets (left/right)
n = 2;
else
in.numTargets = 4; % 4D variant: four targets in 2x2 grid
n = 4;
end
in = applyIedDefaults(in, userFields, n, 8, 12);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Constrain numTargets and enforce fixed IED variants.

applyIedDefaults preserves a supplied numTargets. Therefore, task='ied-2' with numTargets=4 returns four targets, and task='ied-4' with numTargets=2 returns two targets.

Classic ied also preserves unsupported values such as numTargets=3. clutil.iedMorphobesConfig accepts only 2 or 4, so this fails later during task initialization.

Set in.numTargets = n before applyIedDefaults for ied-2 and ied-4. Validate that classic ied accepts only 2 or 4. Add regression tests for both fixed variants and an unsupported target count.

Proposed fix
 		case {'ied-2' 'ied-4'}
 			if strcmp(in.task, 'ied-2')
 				n = 2;
 			else
 				n = 4;
 			end
+			in.numTargets = n;
 			in = applyIedDefaults(in, userFields, n, 8, 12);

Also applies to: 169-170

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @+clutil/checkInput.m around lines 124 - 141, Constrain IED target counts
before applying defaults: in the fixed-variant branch for task values {'ied-2'
'ied-4'}, assign the computed n back to in.numTargets before calling
applyIedDefaults so each variant always uses its required count. In the classic
'ied' branch, validate the supplied or default n and reject any value other than
2 or 4 before applyIedDefaults; add regression coverage for both fixed variants
and an unsupported classic target count.

@iandol
iandol merged commit 5f0246e into main Aug 3, 2026
2 checks passed
@iandol
iandol deleted the fix/ied-morphobes-dimensions branch August 3, 2026 08:26
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.

1 participant