Repository navigation
Fixes #35, fixes #39, fixes #23 - #92
Conversation
normalization_method wrote each percentile with :g (six significant digits), so percentile=(1.000001, 99.8) and (1.000002, 99.8) both wrote "percentile 1-99.8" and Parameters.from_columns accepted parameters fitted with one under the other's settings. Each percentile is now the shortest positional decimal that reads back as the same float (normalization.percentile_name, shared by percentile_range and NormalizationSettings.method_name); -0.0 is written 0. Names of percentiles with at most six significant digits and at least 0.0001 (the default "percentile 1-99.8" among them) are unchanged. Rows written earlier with other percentiles carry the short name and are refused by from_columns with the existing message; no backward compatibility. No fitted number and no dump output changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
NormalizationParameters.apply passed clip and dtype through unchecked: clip=(1, 0) gave every pixel the same value, and an integer dtype truncated and wrapped the normalized values. apply now refuses, with a ValueError naming the value and before any pixel is normalized, clip limits that are not two finite numbers with low < high (equal limits too) and every result type but float32 and float64. Valid calls are unchanged bit for bit; no dump output changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
check_rgb accepted every integer type although its message, the contract's, asks for three 8- or 16-bit colour channels, and apply_rgb repeats CSBDeep's float32 arithmetic, which cannot hold every 32- or 64-bit value. check_rgb, and with it fit of RGB pixels and plane rows, now refuses int32, uint32, int64 and uint64 with that message, naming the channel count and type. uint8, uint16, int8 and int16 are accepted as before with bit-identical results; no dump output changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
The #39 check compared the result type with the native float32 and float64, so '>f4' and '>f8', accepted before the fix, were refused with a message naming 'float32'. The check now goes by type name, as check_rgb does. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Independent review: approve, with one small fix pushed (fa4c993)Reviewed #35, percentile names. #39,
#23, RGB dtypes. Output identity, run myself against
New tests fail on Gate at fa4c993. Non-blocking: the Ready to merge once the owner approves the contract §3.1 change (AGENTS.md §2.6). Generated by Claude Code |
The #91 tests for 64-bit integers and overflowing tail squares and the #92 test of exact percentile names build PlaneRecords and Parameters; they now pass channel IDs (PlaneRecord channels=, write_plane_histograms channel_ids=, Parameters channels by ID). The code-rules baseline drops the two entries the merge left behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3qp9AxjpGPw9xfWAUJNqc
Validation batch on
main9db7c14. One commit per issue; each was reproduced with a failing test onmainbefore the fix.Fixes #35, fixes #39, fixes #23.
#35: exact percentiles in the written method name (fb39641)
NormalizationSettings(percentile=(1.000001, 99.8)).method_nameand(1.000002, 99.8)were both'percentile 1-99.8', andParameters.from_columnsread a row fitted with one under the other's settings. 12 new tests failed onmain.normalization.percentile_name, whichpercentile_rangeandNormalizationSettings.method_nameboth use, so the name is built in one place.-0.0is written as0. The name now tells apart any two percentile settings, so the existingfrom_columnscheck onnormalization_methodrefuses rows whose percentiles differ by any amount.normalization_methodtext, and only for percentiles that have more than six significant digits or are below0.0001. For examplepercentile 1-99.8becomespercentile 1.000001-99.8, andpercentile 1e-05-50becomespercentile 0.00001-50. The default namepercentile 1-99.8and every other ordinary name stay the same. No fitted offset or scale changes.from_columnsrefuses it with the existing message, for example "Column normalization_method is 'percentile 1-99.8', but the settings use 'percentile 1.000001-99.8'. Read the parameters with the settings of the run that wrote them." A test covers this. The fix is to fit again. There is no reader or converter for old names.:g. It now gives the exact-decimal rule. This changes a written contract rule, so it needs owner approval (AGENTS §2.6).#39:
NormalizationParameters.applyvalidation (5225fd5)clip=(1, 0)turned every value into the same number, anddtype=np.uint8,bool,complex64,object,float16and'U4'were all accepted. 16 new tests failed onmain.applyraises a namedValueErrorin these cases:clipis not two numbers: "clip must be two numbers, (low, high); got ...";low >= high: "clip must be (low, high) with low < high; got low=1.0, high=0.0 ...". Equal limits are refused too, because they would give every pixel the same value. This is now written down.#23: RGB limited to 8- and 16-bit integers (f25b605)
check_rgbacceptedint32,uint32,int64anduint64with three channels, even though its own message (the contract's §9.1 message) asks for 8- or 16-bit colour channels.fitof such RGB pixels or plane rows went through. 5 new tests failed onmain.check_rgbnow accepts onlyuint8,uint16,int8andint16(newRGB_DTYPES; byte order does not matter) and refuses the others with the existing contract message, which names the count and type. Reason:apply_rgbrepeats CSBDeep's float32 arithmetic, which cannot hold every value above2**24. Contract §5 and §9.1 are updated; plan §5 already said 8- or 16-bit.fluorescence.int8andint16RGB are still accepted, as they were before. They are 8- and 16-bit and exact in float32. Say if they should be refused as well.Output identity
tools/dump_outputs.py:1723cafb4ff21fc92146725f5fdbdf0d8e3589d13569d68169d072d2eaddfff9(1788 lines).--corpus:8bb7c3c1a7e1a4f3f1f19b5b921b3e45e3644258bdc9e771f0cd49314772256c(4764 lines). Both are byte-identical tomain9db7c14 (cmp).tests/test_fit_goldens.py) pass unchanged.Gate
python tools/check.pypasses locally on Python 3.13: ruff format, 1627 passed, 2 skipped, code rules and ruff check. The 2 skips aretests/test_rgb.py:80, because CSBDeep is not installed locally; CI runs them.Overlap with draft PR #90 (Stage 3)
src/morphobricks_normalization/rgb.py: Stage 3 S3.2: plane_histograms v5 wide, fits by channel ID #90 addsRGB_CHANNELSandcheck_rgb_channelsnext toRGB_CHANNEL_COUNT, and this PR addsRGB_DTYPESthere and editscheck_rgb. The edits are next to each other, so a rebase may need a small manual merge.Parameters.from_columnsintoparameters.pybut keeps thesettings.method_namecomparison. The [Sad Catapella N3][Scientific provenance] Distinct percentile settings share the same serialized method identifier #35 fix lives insettings.pyandnormalization.py, which Stage 3 S3.2: plane_histograms v5 wide, fits by channel ID #90 does not touch, so it carries over unchanged.docs/contract.md(§3.1, §1.2.4, §5, §9.1),CHANGELOG.md(Unreleased): both PRs edit these, so expect text conflicts only.tests/test_fitting.py,tests/test_rgb.py: Stage 3 S3.2: plane_histograms v5 wide, fits by channel ID #90 does not change these test files.Follow-ups (not done here)
_rgb_problemusescheck_rgb, so it gets the new refusal, but that wording should become 8- or 16-bit there. I did not modify another repository.checks.pystill uses:gfor percentiles in warning text. This is only display text, not identity.Generated by Claude Code