Skip to content

ENH: Ingest ITKGenericLabelInterpolator into Modules/Filtering#6135

Merged
hjmjohnson merged 43 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:ingest-GenericLabelInterpolator
Apr 27, 2026
Merged

ENH: Ingest ITKGenericLabelInterpolator into Modules/Filtering#6135
hjmjohnson merged 43 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:ingest-GenericLabelInterpolator

Conversation

@hjmjohnson
Copy link
Copy Markdown
Member

@hjmjohnson hjmjohnson commented Apr 25, 2026

Brings the GenericLabelInterpolator remote module in-tree at Modules/Filtering/GenericLabelInterpolator/, following the same pattern used for #6093 (AnisotropicDiffusionLBR) and #6103 (Montage). 4-commit stack on top of upstream/main; the upstream history is squashed into the ingest commit so each commit conforms to ITK's commit-quality rules.

Commit stack (top → bottom)
e6e4dc043f  ENH:  Enable GenericLabelInterpolator in CI via configure-ci
46753d110c  COMP: Remove GenericLabelInterpolator.remote.cmake; now in-tree
0e0fd2ce21  COMP: Drop missing README.rst read in ingested GenericLabelInterpolator
68eeb7d281  ENH:  Ingest ITKGenericLabelInterpolator into Modules/Filtering
upstream/main

The squashed ENH: Ingest snapshot is taken from upstream tag v1.3.1 (commit fc78327939). The upstream history (~46 commits, dating to 2014) is preserved at https://github.com/InsightSoftwareConsortium/ITKGenericLabelInterpolator and is cross-referenced from the ingest commit message.

What lives in-tree now
  • include/ — 4 headers
    • itkLabelImageGenericInterpolateImageFunction.{h,hxx}
    • itkLabelSelectionImageAdaptor.h
    • itkLabelSelectionPixelAccessor.h
  • test/RotateLabels.cxx + 2 .cid content links (already in CID format upstream — no MD5/SHA512 migration needed)
  • wrapping/itkLabelImageGenericInterpolateImageFunction.wrap
  • Module itk-module.cmake rewritten to drop the file(READ README.rst) call (README.rst is intentionally outside the whitelist; description is now inlined)
  • New Modules/Filtering/GenericLabelInterpolator/README.md pointing at the (to-be-archived) upstream
Greptile findings addressed inline in the squashed ingest
  • Doxygen \ingroup: removed the stray leading * so doxygen recognises the group tags.
  • itk-module.cmake: added explicit ITKImageFunction to DEPENDS (the production header #includes itkInterpolateImageFunction.h); removed the redundant ITKImageFunction from TEST_DEPENDS.
  • The "manual int i counter alongside m_Labels iterator" suggestion in the .hxx was deferred — logic is correct, refactor is stylistic, better handled in a follow-up STYLE: PR after this lands.

@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Enhancement Improvement of existing methods or implementation area:Python wrapping Python bindings for a class area:Filtering Issues affecting the Filtering module area:Remotes Issues affecting the Remote module labels Apr 25, 2026
@hjmjohnson hjmjohnson marked this pull request as ready for review April 25, 2026 15:44
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 25, 2026

Greptile Summary

This PR ingests the ITKGenericLabelInterpolator remote module in-tree at Modules/Filtering/GenericLabelInterpolator/, following the same pattern used for AnisotropicDiffusionLBR and Montage. The four-commit stack squashes the upstream history, removes the remote cmake descriptor, enables the module in CI, and applies the targeted correctness fixes surfaced in a prior Greptile pass (Doxygen \ingroup, explicit ITKImageFunction DEPENDS, and a delegating GetRadius() override that correctly propagates higher-order interpolator radii).

Confidence Score: 5/5

Safe to merge; all previously flagged P1 issues are resolved and only minor P2 style nits remain.

No P0 or P1 issues found. The three prior P1 findings (GetRadius(), \ingroup, ITKImageFunction dependency) are all addressed in the squashed ingest commit. Remaining findings are P2: a trailing slash in the test CMakeLists producing a double slash in the written path (benign on all platforms), limited baseline coverage for non-Gaussian interpolator variants, and the acknowledged const_cast on the image adaptor call.

test/CMakeLists.txt (trailing slash on output dir arg) and test/RotateLabels.cxx (only one of seven interpolator paths has a baseline comparison).

Important Files Changed

Filename Overview
Modules/Filtering/GenericLabelInterpolator/include/itkLabelImageGenericInterpolateImageFunction.h Main class header: correctly delegates GetRadius() to internal interpolators (fixing the previous P1), proper Doxygen groups, standard ITK type-alias boilerplate.
Modules/Filtering/GenericLabelInterpolator/include/itkLabelImageGenericInterpolateImageFunction.hxx Implementation: SetInputImage scans labels, builds per-label adaptors/interpolators; EvaluateAtContinuousIndex returns label with highest interpolated weight. Contains const_cast (P2, acknowledged in comment).
Modules/Filtering/GenericLabelInterpolator/itk-module.cmake Module descriptor with correct DEPENDS (ITKSmoothing, ITKImageAdaptors, ITKImageFunction explicit), TEST_DEPENDS, EXCLUDE_FROM_DEFAULT, ENABLE_SHARED — addresses previous ITKImageFunction dependency finding.
Modules/Filtering/GenericLabelInterpolator/test/CMakeLists.txt Test driver setup and single itk_add_test; trailing slash on output dir arg leads to double slash in written path (P2); only one of seven interpolator outputs is baseline-compared.
Modules/Filtering/GenericLabelInterpolator/test/RotateLabels.cxx Rotation torture test for seven interpolator variants; only the Gaussian-with-3-rotations output is validated against a baseline. Core test logic is correct.
Modules/Filtering/GenericLabelInterpolator/wrapping/itkLabelImageGenericInterpolateImageFunction.wrap Wraps Linear and NearestNeighbor variants for all scalar+UC+colour types; vector types intentionally commented out due to upstream operator< limitation.
Modules/Remote/GenericLabelInterpolator.remote.cmake Remote module descriptor correctly removed now that the module is in-tree.
pyproject.toml Adds -DModule_GenericLabelInterpolator:BOOL=ON to the CI configure command, consistent with AnisotropicDiffusionLBR and Montage entries.

Class Diagram

%%{init: {'theme': 'neutral'}}%%
classDiagram
    class InterpolateImageFunction {
        +EvaluateAtContinuousIndex()
        +GetRadius() SizeType
        +SetInputImage()
    }
    class LabelImageGenericInterpolateImageFunction {
        -m_Labels : LabelSetType
        -m_InternalInterpolators : vector
        -m_LabelSelectionAdaptors : vector
        +SetInputImage(image)
        +EvaluateAtContinuousIndex(cindex) OutputType
        +GetRadius() SizeType
    }
    class LabelSelectionImageAdaptor {
        +SetAcceptedValue(value)
    }
    class ImageAdaptor {
        +SetImage(image)
    }
    class LabelSelectionPixelAccessor {
        -m_AcceptedValue : TInternalType
        +Get(input) TExternalType
        +SetAcceptedValue(value)
    }
    class TInterpolator {
        <<template>>
        +EvaluateAtContinuousIndex()
        +GetRadius() SizeType
        +SetInputImage()
    }
    InterpolateImageFunction <|-- LabelImageGenericInterpolateImageFunction
    ImageAdaptor <|-- LabelSelectionImageAdaptor
    LabelSelectionImageAdaptor --> LabelSelectionPixelAccessor : uses accessor
    LabelImageGenericInterpolateImageFunction --> LabelSelectionImageAdaptor : 1 per label
    LabelImageGenericInterpolateImageFunction --> TInterpolator : 1 per label
    TInterpolator --> LabelSelectionImageAdaptor : SetInputImage(adaptor)
Loading

Reviews (2): Last reviewed commit: "BUG: Delegate GetRadius() to the wrapped..." | Re-trigger Greptile

Comment thread Modules/Filtering/GenericLabelInterpolator/itk-module.cmake
@hjmjohnson hjmjohnson force-pushed the ingest-GenericLabelInterpolator branch from ee16b27 to e6e4dc0 Compare April 25, 2026 15:59
@hjmjohnson
Copy link
Copy Markdown
Member Author

@greptileai review

Re-review on new HEAD 5b5cc6c3ec. Adds BUG: Delegate GetRadius() to the wrapped per-label interpolator on top of the previously-reviewed squashed ingest. Earlier P2 findings (Doxygen \ingroup, ITKImageFunction DEPENDS) are addressed in the squashed commit; the range-for refactor was deferred.

@hjmjohnson hjmjohnson force-pushed the ingest-GenericLabelInterpolator branch 2 times, most recently from a66a0ad to eeb4293 Compare April 26, 2026 19:50
@hjmjohnson hjmjohnson requested a review from dzenanz April 27, 2026 11:37
@hjmjohnson
Copy link
Copy Markdown
Member Author

@dzenanz The ghostflow issues would require changing the commit history. I chose not to do that for the ingestions.

@blowekamp
Copy link
Copy Markdown
Member

@hjmjohnson I don't think it's worth changing the commit messages. But I do see there are some white space issues in the history. Extra white space and EOF not where expected.

Do the current file pass these white space tests?

It may be reasonable to automate a fix up the commit history for these whitespace errors.

@dzenanz
Copy link
Copy Markdown
Member

dzenanz commented Apr 27, 2026

We can ignore ghostflow in this case. Brad's idea to remove trailing whitespaces sounds good to me.

@hjmjohnson
Copy link
Copy Markdown
Member Author

@dzenanz @blowekamp, cleaning up the whitespace and cleaning up the commit messages are both really easy and quite safe to do. As I move forward with ingesting other remote modules, it is a really easy thing to add, and it will make reviewing the PR's easier.

The reason I didn't do that was to preserve the original code, but now that I think about it, I think the benefits of byte-for-byte preservation are probably a vanishingly small benefit.

@dzenanz
Copy link
Copy Markdown
Member

dzenanz commented Apr 27, 2026

Did the trailing whitespaces get removed by the merge commit (1ee0cb1)? That is fine, too.

Copy link
Copy Markdown
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

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

Mostly looks good.

Comment thread Modules/Filtering/GenericLabelInterpolator/CMakeLists.txt Outdated
@hjmjohnson hjmjohnson force-pushed the ingest-GenericLabelInterpolator branch from eeb4293 to fc200e3 Compare April 27, 2026 15:27
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 27, 2026
Adds Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py
and documents it in INGESTION_STRATEGY.md as a mandatory pass for
modes A (full-history) and B (filtered-history).

For each commit in <base>..HEAD the driver:

- cherry-picks with -X theirs so an earlier commit's pre-commit
  auto-fix never blocks a later commit's content from replaying;
- runs pre-commit on the touched paths and re-stages auto-fixes
  (whitespace, EOF, gersemi, clang-format);
- normalizes the subject line to ITK conventions (BUG:/COMP:/DOC:/
  ENH:/PERF:/STYLE: prefix, <= 78 chars), preserving the original
  subject as "Original subject: <text>" in the body when rewriting;
- drops commits that become empty after pre-commit -- intermediate
  style-only commits that today's hooks would have prevented;
- preserves GIT_AUTHOR_NAME / GIT_AUTHOR_EMAIL / GIT_AUTHOR_DATE
  verbatim. Only committer + committer date change.

The script is idempotent. The tip tree is byte-identical before
and after the normalization, so CI behavior is unchanged; only
intra-history trees become clean.

Addresses feedback on PR InsightSoftwareConsortium#6135 from @blowekamp ("white space issues
in the history") and @dzenanz ("Brad's idea to remove trailing
whitespaces sounds good to me") and forms the new default for
remote-module ingests.

Assisted-by: Claude Code (claude-opus-4-7) -- script implementation and INGESTION_STRATEGY.md update
@hjmjohnson hjmjohnson force-pushed the ingest-GenericLabelInterpolator branch from fc200e3 to 4db9b1e Compare April 27, 2026 15:35
@hjmjohnson
Copy link
Copy Markdown
Member Author

@blowekamp @dzenanz — applied the per-commit cleanup we discussed. Summary on new HEAD 4db9b1e93e:

  • Rebased onto current upstream/main (was 18 behind).
  • Re-stamped every historical commit through ITK's current pre-commit hook set so git show <sha> reads cleanly all the way back to the 2016 commits. Intermediate trailing-whitespace / EOF / formatting drift is gone.
  • Subject lines that violated ITK conventions (no prefix, or > 78 chars) were rewritten and the original subject preserved verbatim in the body as Original subject: <text>. 4 of 41 commits were affected.
  • 2 intermediate style-only commits (STYLE: Update to match clang-format-19 and STYLE: gersemi formatting) became empty after the replay and were dropped — they would not have existed under today's hook set in the first place.
  • Author name, email, and author-date are preserved verbatim on every commit. All 12 original contributors still appear in git shortlog -sne (unchanged set). Tip tree is byte-identical to the pre-rewrite tip (zero CI behavior delta).

The driver landed as a new commit at the tip (ENH: Per-commit pre-commit replay for remote-module ingestion) and is now documented in Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md as the default pass for modes A/B going forward.

Verification commands
# Tip tree unchanged
git diff pre-normalize-6135..HEAD                         # empty

# Authorship preserved (compare against the pre-rewrite branch)
git log --format='%an <%ae>' upstream/main..HEAD | sort -u   # 12 distinct authors

# Every historical commit passes modern pre-commit
for sha in $(git rev-list upstream/main..HEAD); do
    git stash && git checkout $sha
    pre-commit run --files Modules/Filtering/GenericLabelInterpolator/**/* \
        || echo "DIRTY: $sha"
    git checkout - && git stash pop
done                                                       # no DIRTY lines

hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 27, 2026
Adds Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py
and documents it in INGESTION_STRATEGY.md as a mandatory pass for
modes A (full-history) and B (filtered-history).

For each commit in <base>..HEAD the driver:

- cherry-picks with -X theirs so an earlier commit's pre-commit
  auto-fix never blocks a later commit's content from replaying;
- runs pre-commit on the touched paths and re-stages auto-fixes
  (whitespace, EOF, gersemi, clang-format);
- normalizes the subject line to ITK conventions (BUG:/COMP:/DOC:/
  ENH:/PERF:/STYLE: prefix, <= 78 chars), preserving the original
  subject as "Original subject: <text>" in the body when rewriting;
- drops commits that become empty after pre-commit -- intermediate
  style-only commits that today's hooks would have prevented;
- preserves GIT_AUTHOR_NAME / GIT_AUTHOR_EMAIL / GIT_AUTHOR_DATE
  verbatim. Only committer + committer date change.

The script is idempotent. The tip tree is byte-identical before
and after the normalization, so CI behavior is unchanged; only
intra-history trees become clean.

Addresses feedback on PR InsightSoftwareConsortium#6135 from @blowekamp ("white space issues
in the history") and @dzenanz ("Brad's idea to remove trailing
whitespaces sounds good to me") and forms the new default for
remote-module ingests.

Assisted-by: Claude Code (claude-opus-4-7) -- script implementation and INGESTION_STRATEGY.md update
@hjmjohnson hjmjohnson force-pushed the ingest-GenericLabelInterpolator branch from 4db9b1e to 68a9eb3 Compare April 27, 2026 15:41
@hjmjohnson
Copy link
Copy Markdown
Member Author

@blowekamp @dzenanz — followup on 68a9eb30c3: ghostflow flagged the original first commit (7a7bd8331a, 2016) for trailing whitespace it had added, and the per-commit pre-commit replay didn't catch it on the first pass. Re-ran the normalize script (idempotent), it now correctly cleared all trailing whitespace from every historical commit. Verified with git show <sha> --check across every commit in upstream/main..HEAD — no trailing-whitespace warnings remain. One additional commit (ENH: Add .gitattributes…) became empty after the second pass and was dropped, taking the count from 40 to 39.

@dzenanz
Copy link
Copy Markdown
Member

dzenanz commented Apr 27, 2026

I just took a look. All the commit now live on top of the main branch. Which is different from the other ingested modules, and feels strange. I assume it would be confusing to someone in the future reading the log, unaware of this recent ingestion campaign.

hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 27, 2026
Adds Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py
and documents it in INGESTION_STRATEGY.md as a mandatory pass for
modes A (full-history) and B (filtered-history).

For each commit in <base>..HEAD the driver:

- cherry-picks with -X theirs so an earlier commit's pre-commit
  auto-fix never blocks a later commit's content from replaying;
- runs pre-commit on the touched paths and re-stages auto-fixes
  (whitespace, EOF, gersemi, clang-format);
- normalizes the subject line to ITK conventions (BUG:/COMP:/DOC:/
  ENH:/PERF:/STYLE: prefix, <= 78 chars), preserving the original
  subject as "Original subject: <text>" in the body when rewriting;
- drops commits that become empty after pre-commit -- intermediate
  style-only commits that today's hooks would have prevented;
- preserves GIT_AUTHOR_NAME / GIT_AUTHOR_EMAIL / GIT_AUTHOR_DATE
  verbatim. Only committer + committer date change.

The script is idempotent. The tip tree is byte-identical before
and after the normalization, so CI behavior is unchanged; only
intra-history trees become clean.

Addresses feedback on PR InsightSoftwareConsortium#6135 from @blowekamp ("white space issues
in the history") and @dzenanz ("Brad's idea to remove trailing
whitespaces sounds good to me") and forms the new default for
remote-module ingests.

Assisted-by: Claude Code (claude-opus-4-7) -- script implementation and INGESTION_STRATEGY.md update
Adds a "The root-commit ghostflow error is REQUIRED, not a failure"
subsection to INGESTION_STRATEGY.md.

The orphan root commit on the side branch is the structural
signature of an unrelated-history merge -- git merge
--allow-unrelated-histories --no-ff requires that the second
parent of the merge commit have no common ancestor with main,
which forces the side branch's first commit to be a root commit.
Ghostflow's "no root commits" rule is a sensible default for
normal contributions but is structurally incompatible with
remote-module ingestion.

Ingest acceptance criteria, in priority order:

  1. Exactly one ghostflow error
  2. The error is the "root commit not allowed" form
  3. The flagged SHA equals the side branch's tail commit

Any of these are real failures that must be fixed:

  - More than one ghostflow error
  - A root-commit error pointing at any commit not on the
    side branch
  - Trailing-whitespace or missing-newline errors

For PR InsightSoftwareConsortium#6135 (and future ingests), reviewers should treat the
single "root commit" error as green -- it confirms the merge
topology was built correctly.  Insisting on a fully-green
ghostflow would force re-flattening to a linear rebase, which
destroys the merge join and blame walk that the merge-topology
requirement was added to preserve.
@hjmjohnson
Copy link
Copy Markdown
Member Author

For reviewers: ghostflow on this PR shows exactly one error and that is intentional and required:

- commit f30c6ba6ca50141139c82184dec00bb606449618 not allowed; it is a root commit.

This is the structural signature of the unrelated-history merge — git merge --allow-unrelated-histories --no-ff requires that the second parent of the merge commit have no common ancestor with main, which forces the side branch's tail to be a root commit. Ghostflow's "no root commits" rule is a sensible default for normal contributions but is structurally incompatible with the merge-commit topology required for remote-module ingestion.

Codified in Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md (commit 957dae26f4) under "The root-commit ghostflow error is REQUIRED, not a failure" with explicit acceptance criteria:

  1. Exactly one ghostflow error
  2. The error is the "root commit not allowed" form
  3. The flagged SHA equals the side branch's tail commit (git rev-list --max-parents=0 <merge-commit>^2)

Anything beyond that single root-commit error (e.g., trailing-whitespace or missing-EOF errors) is a real failure that must be fixed before merge — those would indicate either intermediate-commit drift or a side-branch tree that wasn't subtree-only.

f30c6ba6ca here is the side branch's root commit (Francois Budin's 2016 "Converting generic_label_interpolator to an ITK remote module"), exactly as required.

Copy link
Copy Markdown
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

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

Looks great now!

@hjmjohnson hjmjohnson merged commit d1eab72 into InsightSoftwareConsortium:main Apr 27, 2026
11 of 15 checks passed
hjmjohnson added a commit to InsightSoftwareConsortium/ITKGenericLabelInterpolator that referenced this pull request Apr 28, 2026
…is repo

The GenericLabelInterpolator module was ingested into the main ITK
source tree on 2026-04-27 via InsightSoftwareConsortium/ITK#6135
(merge commit d1eab72aa6315d66cbe535a7ca61cf3c4ef60ffa). Per the
ITK ingestion strategy
(Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md),
the one-definition rule requires that any file now living at
Modules/Filtering/GenericLabelInterpolator/ in ITK no longer live at
this upstream repo's tree tip.

This commit:

- Removes the whitelisted files that transferred during ingest:
  include/, test/, wrapping/, CMakeLists.txt, itk-module.cmake,
  CTestConfig.cmake.
- Adds MIGRATION_README.md at the repo root pointing users at the
  authoritative in-tree ITK location and linking the ingest PR.
- Leaves the pre-ingest history intact so blame, paper material,
  the document/ tree, README.rst, LICENSE, and any other
  deliberately-not-migrated artifacts remain reachable.

After this PR merges, this repository will be marked ARCHIVED via
GitHub's repository settings (Danger Zone -> Archive this
repository), making it read-only.

Cloning ITK main gets the authoritative module under
Modules/Filtering/GenericLabelInterpolator/. Cloning this repo after
archival gets only the MIGRATION_README pointer plus everything that
was deliberately not migrated.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The upstream remote module's top-level CMakeLists.txt carried a
dual-mode preamble that supports both standalone (find_package(ITK)
+ ITKModuleExternal) and in-tree (itk_module_impl) builds.

Once the module lives under Modules/Filtering/, only the in-tree
branch is reachable -- the standalone branch is dead code, the
cmake_minimum_required and project() lines duplicate what ITK's
root CMake already owns.  Collapse the file to a single
itk_module_impl() call, matching every other in-tree
Modules/<Group>/<Name>/ module.

Per the standalone-build cleanup convention documented in
Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md
under "Standalone-build boilerplate cleanup (modes A/B)" and
applied previously to GenericLabelInterpolator (PR InsightSoftwareConsortium#6135) and
MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The module now lives at Modules/Filtering/FastBilateral/.  The
configure-time fetch declaration in Modules/Remote/ would otherwise
clone the (soon-to-be-archived) upstream and double-define the
module.

Mirrors the in-tree transition completed for GenericLabelInterpolator
(PR InsightSoftwareConsortium#6135) and MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The upstream remote module's top-level CMakeLists.txt carried a
dual-mode preamble that supports both standalone (find_package(ITK)
+ ITKModuleExternal) and in-tree (itk_module_impl) builds.

Once the module lives under Modules/Filtering/, only the in-tree
branch is reachable -- the standalone branch is dead code, the
cmake_minimum_required and project() lines duplicate what ITK's
root CMake already owns.  Collapse the file to a single
itk_module_impl() call, matching every other in-tree
Modules/<Group>/<Name>/ module.

Per the standalone-build cleanup convention documented in
Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md
under "Standalone-build boilerplate cleanup (modes A/B)" and
applied previously to GenericLabelInterpolator (PR InsightSoftwareConsortium#6135) and
MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The module now lives at Modules/Filtering/FastBilateral/.  The
configure-time fetch declaration in Modules/Remote/ would otherwise
clone the (soon-to-be-archived) upstream and double-define the
module.

Mirrors the in-tree transition completed for GenericLabelInterpolator
(PR InsightSoftwareConsortium#6135) and MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The upstream remote module's top-level CMakeLists.txt carried a
dual-mode preamble that supports both standalone (find_package(ITK)
+ ITKModuleExternal) and in-tree (itk_module_impl) builds.

Once the module lives under Modules/Filtering/, only the in-tree
branch is reachable -- the standalone branch is dead code, the
cmake_minimum_required and project() lines duplicate what ITK's
root CMake already owns.  Collapse the file to a single
itk_module_impl() call, matching every other in-tree
Modules/<Group>/<Name>/ module.

Per the standalone-build cleanup convention documented in
Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md
under "Standalone-build boilerplate cleanup (modes A/B)" and
applied previously to GenericLabelInterpolator (PR InsightSoftwareConsortium#6135) and
MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The module now lives at Modules/Filtering/FastBilateral/.  The
configure-time fetch declaration in Modules/Remote/ would otherwise
clone the (soon-to-be-archived) upstream and double-define the
module.

Mirrors the in-tree transition completed for GenericLabelInterpolator
(PR InsightSoftwareConsortium#6135) and MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The normalize-ingest-commits.py script replays each non-merge upstream
commit via cherry-pick and skips merges entirely.  The result loses
the upstream merge topology, which the strategy doc has always
mandated as preserved.  Reviewers flagged this on PRs InsightSoftwareConsortium#6135, InsightSoftwareConsortium#6137,
InsightSoftwareConsortium#6159, and InsightSoftwareConsortium#6161 before it became a rule violation.

This commit:

1. Adds a hard refuse-to-run guard to normalize-ingest-commits.py
   (exit 3 with deprecation notice unless --i-understand-this-linearizes
   is passed).  The guard names the replacement and points at the
   strategy doc.

2. Adds rewrite-history-merge-preserving.py — a git-filter-repo
   driven rewriter that walks every commit (merges included) and
   applies uniform text-blob normalization (trailing-whitespace strip
   + EOF-newline fix).  Implements the user-mandated Phase 1
   reference / Phase 2 traversal / Phase 3 verification architecture.

3. Updates INGESTION_STRATEGY.md with the "Linearization is forbidden"
   subsection, an allowed-tool table for per-commit re-formatting,
   and the new operator check that the merge count satisfies
   1 + UPSTREAM_INTERNAL_MERGES.

Language-specific formatters (clang-format, gersemi) are intentionally
NOT applied per blob — they require the destination's current config,
and applying them retroactively across upstream history would produce
spurious diffs.  The recommended pattern is a single
"STYLE: Apply current formatters" commit at the rewritten tip after
Phase 2 succeeds.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The normalize-ingest-commits.py script replays each non-merge upstream
commit via cherry-pick and skips merges entirely.  The result loses
the upstream merge topology, which the strategy doc has always
mandated as preserved.  Reviewers flagged this on PRs InsightSoftwareConsortium#6135, InsightSoftwareConsortium#6137,
InsightSoftwareConsortium#6159, and InsightSoftwareConsortium#6161 before it became a rule violation.

This commit:

1. Adds a hard refuse-to-run guard to normalize-ingest-commits.py
   (exit 3 with deprecation notice unless --i-understand-this-linearizes
   is passed).  The guard names the replacement and points at the
   strategy doc.

2. Adds rewrite-history-merge-preserving.py — a git-filter-repo
   driven rewriter that walks every commit (merges included) and
   applies uniform text-blob normalization (trailing-whitespace strip
   + EOF-newline fix).  Implements the user-mandated Phase 1
   reference / Phase 2 traversal / Phase 3 verification architecture.

3. Updates INGESTION_STRATEGY.md with the "Linearization is forbidden"
   subsection, an allowed-tool table for per-commit re-formatting,
   and the new operator check that the merge count satisfies
   1 + UPSTREAM_INTERNAL_MERGES.

Language-specific formatters (clang-format, gersemi) are intentionally
NOT applied per blob — they require the destination's current config,
and applying them retroactively across upstream history would produce
spurious diffs.  The recommended pattern is a single
"STYLE: Apply current formatters" commit at the rewritten tip after
Phase 2 succeeds.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The normalize-ingest-commits.py script replays each non-merge upstream
commit via cherry-pick and skips merges entirely.  The result loses
the upstream merge topology, which the strategy doc has always
mandated as preserved.  Reviewers flagged this on PRs InsightSoftwareConsortium#6135, InsightSoftwareConsortium#6137,
InsightSoftwareConsortium#6159, and InsightSoftwareConsortium#6161 before it became a rule violation.

This commit:

1. Adds a hard refuse-to-run guard to normalize-ingest-commits.py
   (exit 3 with deprecation notice unless --i-understand-this-linearizes
   is passed).  The guard names the replacement and points at the
   strategy doc.

2. Adds rewrite-history-merge-preserving.py — a git-filter-repo
   driven rewriter that walks every commit (merges included) and
   applies uniform text-blob normalization (trailing-whitespace strip
   + EOF-newline fix).  Implements the user-mandated Phase 1
   reference / Phase 2 traversal / Phase 3 verification architecture.

3. Updates INGESTION_STRATEGY.md with the "Linearization is forbidden"
   subsection, an allowed-tool table for per-commit re-formatting,
   and the new operator check that the merge count satisfies
   1 + UPSTREAM_INTERNAL_MERGES.

Language-specific formatters (clang-format, gersemi) are intentionally
NOT applied per blob — they require the destination's current config,
and applying them retroactively across upstream history would produce
spurious diffs.  The recommended pattern is a single
"STYLE: Apply current formatters" commit at the rewritten tip after
Phase 2 succeeds.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The normalize-ingest-commits.py script replays each non-merge upstream
commit via cherry-pick and skips merges entirely.  The result loses
the upstream merge topology, which the strategy doc has always
mandated as preserved.  Reviewers flagged this on PRs InsightSoftwareConsortium#6135, InsightSoftwareConsortium#6137,
InsightSoftwareConsortium#6159, and InsightSoftwareConsortium#6161 before it became a rule violation.

This commit:

1. Adds a hard refuse-to-run guard to normalize-ingest-commits.py
   (exit 3 with deprecation notice unless --i-understand-this-linearizes
   is passed).  The guard names the replacement and points at the
   strategy doc.

2. Adds rewrite-history-merge-preserving.py — a git-filter-repo
   driven rewriter that walks every commit (merges included) and
   applies uniform text-blob normalization (trailing-whitespace strip
   + EOF-newline fix).  Implements the user-mandated Phase 1
   reference / Phase 2 traversal / Phase 3 verification architecture.

3. Updates INGESTION_STRATEGY.md with the "Linearization is forbidden"
   subsection, an allowed-tool table for per-commit re-formatting,
   and the new operator check that the merge count satisfies
   1 + UPSTREAM_INTERNAL_MERGES.

Language-specific formatters (clang-format, gersemi) are intentionally
NOT applied per blob — they require the destination's current config,
and applying them retroactively across upstream history would produce
spurious diffs.  The recommended pattern is a single
"STYLE: Apply current formatters" commit at the rewritten tip after
Phase 2 succeeds.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request Apr 28, 2026
The normalize-ingest-commits.py script replays each non-merge upstream
commit via cherry-pick and skips merges entirely.  The result loses
the upstream merge topology, which the strategy doc has always
mandated as preserved.  Reviewers flagged this on PRs InsightSoftwareConsortium#6135, InsightSoftwareConsortium#6137,
InsightSoftwareConsortium#6159, and InsightSoftwareConsortium#6161 before it became a rule violation.

This commit:

1. Adds a hard refuse-to-run guard to normalize-ingest-commits.py
   (exit 3 with deprecation notice unless --i-understand-this-linearizes
   is passed).  The guard names the replacement and points at the
   strategy doc.

2. Adds rewrite-history-merge-preserving.py — a git-filter-repo
   driven rewriter that walks every commit (merges included) and
   applies uniform text-blob normalization (trailing-whitespace strip
   + EOF-newline fix).  Implements the user-mandated Phase 1
   reference / Phase 2 traversal / Phase 3 verification architecture.

3. Updates INGESTION_STRATEGY.md with the "Linearization is forbidden"
   subsection, an allowed-tool table for per-commit re-formatting,
   and the new operator check that the merge count satisfies
   1 + UPSTREAM_INTERNAL_MERGES.

Language-specific formatters (clang-format, gersemi) are intentionally
NOT applied per blob — they require the destination's current config,
and applying them retroactively across upstream history would produce
spurious diffs.  The recommended pattern is a single
"STYLE: Apply current formatters" commit at the rewritten tip after
Phase 2 succeeds.
@hjmjohnson hjmjohnson added this to the ITK 6.0 Release Candidate 1 milestone May 5, 2026
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
Adds Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py
and documents it in INGESTION_STRATEGY.md as a mandatory pass for
modes A (full-history) and B (filtered-history).

For each commit in <base>..HEAD the driver:

- cherry-picks with -X theirs so an earlier commit's pre-commit
  auto-fix never blocks a later commit's content from replaying;
- runs pre-commit on the touched paths and re-stages auto-fixes
  (whitespace, EOF, gersemi, clang-format);
- normalizes the subject line to ITK conventions (BUG:/COMP:/DOC:/
  ENH:/PERF:/STYLE: prefix, <= 78 chars), preserving the original
  subject as "Original subject: <text>" in the body when rewriting;
- drops commits that become empty after pre-commit -- intermediate
  style-only commits that today's hooks would have prevented;
- preserves GIT_AUTHOR_NAME / GIT_AUTHOR_EMAIL / GIT_AUTHOR_DATE
  verbatim. Only committer + committer date change.

The script is idempotent. The tip tree is byte-identical before
and after the normalization, so CI behavior is unchanged; only
intra-history trees become clean.

Addresses feedback on PR InsightSoftwareConsortium#6135 from @blowekamp ("white space issues
in the history") and @dzenanz ("Brad's idea to remove trailing
whitespaces sounds good to me") and forms the new default for
remote-module ingests.

Assisted-by: Claude Code (claude-opus-4-7) -- script implementation and INGESTION_STRATEGY.md update
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
Adds a "Post-merge fixup hazard" subsection to
INGESTION_STRATEGY.md warning that plain `git rebase --autosquash
upstream/main` after the ingest merge silently re-flattens the
merge topology.  Records the second linear-history regression on
PR InsightSoftwareConsortium#6135 (4bc617fb38 → a8f3bc1) as the cautionary tale and
prescribes either discrete on-top commits or `git rebase
--rebase-merges --autosquash <merge>^` as the safe alternatives.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
Adds a "The root-commit ghostflow error is REQUIRED, not a failure"
subsection to INGESTION_STRATEGY.md.

The orphan root commit on the side branch is the structural
signature of an unrelated-history merge -- git merge
--allow-unrelated-histories --no-ff requires that the second
parent of the merge commit have no common ancestor with main,
which forces the side branch's first commit to be a root commit.
Ghostflow's "no root commits" rule is a sensible default for
normal contributions but is structurally incompatible with
remote-module ingestion.

Ingest acceptance criteria, in priority order:

  1. Exactly one ghostflow error
  2. The error is the "root commit not allowed" form
  3. The flagged SHA equals the side branch's tail commit

Any of these are real failures that must be fixed:

  - More than one ghostflow error
  - A root-commit error pointing at any commit not on the
    side branch
  - Trailing-whitespace or missing-newline errors

For PR InsightSoftwareConsortium#6135 (and future ingests), reviewers should treat the
single "root commit" error as green -- it confirms the merge
topology was built correctly.  Insisting on a fully-green
ghostflow would force re-flattening to a linear rebase, which
destroys the merge join and blame walk that the merge-topology
requirement was added to preserve.
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
…est-GenericLabelInterpolator

ENH: Ingest ITKGenericLabelInterpolator into Modules/Filtering
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
The upstream remote module's top-level CMakeLists.txt carried a
dual-mode preamble that supports both standalone (find_package(ITK)
+ ITKModuleExternal) and in-tree (itk_module_impl) builds.

Once the module lives under Modules/Filtering/, only the in-tree
branch is reachable -- the standalone branch is dead code, the
cmake_minimum_required and project() lines duplicate what ITK's
root CMake already owns.  Collapse the file to a single
itk_module_impl() call, matching every other in-tree
Modules/<Group>/<Name>/ module.

Per the standalone-build cleanup convention documented in
Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md
under "Standalone-build boilerplate cleanup (modes A/B)" and
applied previously to GenericLabelInterpolator (PR InsightSoftwareConsortium#6135) and
MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
The module now lives at Modules/Filtering/FastBilateral/.  The
configure-time fetch declaration in Modules/Remote/ would otherwise
clone the (soon-to-be-archived) upstream and double-define the
module.

Mirrors the in-tree transition completed for GenericLabelInterpolator
(PR InsightSoftwareConsortium#6135) and MGHIO (PR InsightSoftwareConsortium#6137).
hjmjohnson added a commit to hjmjohnson/ITK that referenced this pull request May 6, 2026
The normalize-ingest-commits.py script replays each non-merge upstream
commit via cherry-pick and skips merges entirely.  The result loses
the upstream merge topology, which the strategy doc has always
mandated as preserved.  Reviewers flagged this on PRs InsightSoftwareConsortium#6135, InsightSoftwareConsortium#6137,
InsightSoftwareConsortium#6159, and InsightSoftwareConsortium#6161 before it became a rule violation.

This commit:

1. Adds a hard refuse-to-run guard to normalize-ingest-commits.py
   (exit 3 with deprecation notice unless --i-understand-this-linearizes
   is passed).  The guard names the replacement and points at the
   strategy doc.

2. Adds rewrite-history-merge-preserving.py — a git-filter-repo
   driven rewriter that walks every commit (merges included) and
   applies uniform text-blob normalization (trailing-whitespace strip
   + EOF-newline fix).  Implements the user-mandated Phase 1
   reference / Phase 2 traversal / Phase 3 verification architecture.

3. Updates INGESTION_STRATEGY.md with the "Linearization is forbidden"
   subsection, an allowed-tool table for per-commit re-formatting,
   and the new operator check that the merge count satisfies
   1 + UPSTREAM_INTERNAL_MERGES.

Language-specific formatters (clang-format, gersemi) are intentionally
NOT applied per blob — they require the destination's current config,
and applying them retroactively across upstream history would produce
spurious diffs.  The recommended pattern is a single
"STYLE: Apply current formatters" commit at the rewritten tip after
Phase 2 succeeds.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Filtering Issues affecting the Filtering module area:Python wrapping Python bindings for a class area:Remotes Issues affecting the Remote module type:Enhancement Improvement of existing methods or implementation type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants