fix(ia): restore bulk-import Class-column links for legacy imports (#1624)#1625
Open
JasonWildMe wants to merge 2 commits into
Open
fix(ia): restore bulk-import Class-column links for legacy imports (#1624)#1625JasonWildMe wants to merge 2 commits into
JasonWildMe wants to merge 2 commits into
Conversation
…1624) Since 10.2 the bulk-import task page (/react/bulk-import-task) left the Class column empty for imports created before the update. The match-task selector Task.getPreferredMatchResultsTaskForAnnotation restricts candidates to tasks whose parameters.importTaskId matches the import. Pre-10.2 imports' tasks carry no such parameter (and WBIA match tasks are un-stamped in general), so the selector returned null and no Match Results link rendered. Add a fallback: when no task carries this import's id, fall back to the annotation's un-stamped tasks (no importTaskId) instead of returning null. Tasks stamped with a DIFFERENT import's id are never used, so cross-import isolation against stamped tasks is preserved. The change is a strict superset of prior behavior -- the scoped-match path is byte identical; only the previously-null case now yields the legacy task. Also normalize a blank importTaskId to unscoped. Design notes and the no-regression analysis: docs/superpowers/specs/2026-06-17-issue-1624-bulk-import-class-column-fix.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1625 +/- ##
=======================================
Coverage 51.61% 51.61%
=======================================
Files 308 308
Lines 12140 12140
Branches 3816 3816
=======================================
Hits 6266 6266
Misses 5591 5591
Partials 283 283
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… v2 imports
For v2 ml-service bulk imports, getPreferredMatchResultsTaskForAnnotation
returned the detection/umbrella task (stamped with importTaskId but NOT a
renderable match task and owning no MatchResults) instead of the per-annotation
match task (renderable, owns the results, but unstamped). The importTaskId
scoping pre-filtered candidates before renderability was evaluated, so the
stamped-but-resultless detection task won and the selector fell back to its
root. Result: the /react/bulk-import-task "Class" column rendered
"<iaClass>: {}" and every Match Results link opened an empty page, even though
identification completed and candidates exist.
Fix: evaluate renderable match tasks first across all candidates; use
importTaskId only as a preference within that set (this import's stamped task,
else newest unstamped, never a foreign import's). Only when no usable renderable
task exists do we fall back to the prior scoped/legacy root logic, so PR #1625's
legacy-import (#1624) behavior and foreign-import isolation are preserved.
Extracts the pure selection logic into Task.selectPreferredMatchTask(List, String)
and adds TaskSelectPreferredMatchTaskTest (10 cases). Design + analysis in
docs/plans/2026-06-18-bulk-import-match-task-selection-fix.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Issue
Fixes #1624. Since the 10.2 update, the bulk-import task page (
/react/bulk-import-task) shows an empty Class column — no Match Results links — for imports that existed before 10.2. Reported on Whiskerbook and GiraffeSpotter; re-sending the import to ID works around it.Root cause
The Class column is fed by
ImportTask.statsAnnotations(), which selects the task to link viaTask.getPreferredMatchResultsTaskForAnnotation(ann, importTaskId, …), passing the import's id. The C15 selector restricts candidates to tasks whoseparameters.importTaskIdequals that id and returnednullwhen none matched.importTaskIdis stamped onto tasks only by the modern bulk-import path (BulkImport.initiateIA()). Pre-10.2 imports' tasks never carry it, so the filter emptied the candidate list, the selector returnednull,encounterTaskInfogot no entry, and the frontend rendered-. (Re-sending to ID creates freshly-stamped tasks, which is why that works around it.)Fix
A single fallback in
Task.getPreferredMatchResultsTaskForAnnotation: when no task carries this import's id, fall back to the annotation's un-stamped tasks (noimportTaskId) instead of returningnull. Candidates are bucketed three ways:scopedimportTaskId== this importlegacyimportTaskIdat allscopedemptyDropping the third bucket prevents a legacy import's page from linking to an unrelated, newer import's task.
Why it's safe — strict superset, no regression
scopednon-empty →tasks = scoped, byte-identical to the oldtasks = filteredand every downstream decision. Any imperfect selection on this path is pre-existing C15 behavior, unchanged here.scopedempty,legacynon-empty → returns a legacy task where the old code returnednull. The only behavioral delta — the fix.scopedempty,legacyempty →null, same as before.The method never returns a different non-null task than before; it only converts specific
nullresults into the legacy task. The encounter page is unaffected (it calls the 2-arg overload withimportTaskId == nulland never enters this branch).Also normalizes a blank
importTaskIdto unscoped (defensive).Review (Codex, 2 rounds)
Reviewed adversarially with a focus on unexpected fallback behavior. Findings addressed: blank-id edge fixed; doc-ordering wording corrected; the freeze-on-import limitation for the WBIA path (match tasks are created un-stamped in
IBEISIA.processCallback) is pre-existing, not introduced here and documented.Recommended follow-up (separate PR): propagate
importTaskIdinto thetaskParametersbuilt inIBEISIA.processCallbackso future WBIA match tasks are stamped and the freeze holds for them too. It does not repair already-persisted tasks, so this fallback is still required for existing data.Full design notes and the no-regression analysis:
docs/superpowers/specs/2026-06-17-issue-1624-bulk-import-class-column-fix.md.Testing
No schema change, no data migration; repairs existing data on all installs at once.
🤖 Generated with Claude Code