Skip to content

feat!: broaden the continuum step at absorption edges by the detector by default - #65

Merged
Paullo9 merged 22 commits into
mainfrom
issue-8-broadened-default
Nov 1, 2026
Merged

Paullo9 merged 22 commits into
mainfrom
issue-8-broadened-default

Conversation

@Paullo9

@Paullo9 Paullo9 commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Paul · project thread

Part of #8

Based on main, which now includes #64.

What changes

The continuum step at absorption edges now defaults to .broadened. #64 added it as an opt-in: the step is blurred by the detector resolution, as a detector records it. .sharp stays available and gives the earlier default value for value. exSpy has no edge in its background, so no parity path changes.

  1. test: the synthetic generators blur their continuum with the detector resolution.
    • tools/edx-sim/detector_blur.py computes expected - C + blur(C). Its rebuilt continuum matches forward.py to 5e-16. forward.py itself is unchanged.
    • demo_pools.py rebuilds the demo continuum from the truth arrays and checks every channel against the generator in 9.5-19 keV (within 1e-9).
    • The 3 % Si step in realistic_l_sim.py is now a normal-CDF step.
    • Fixtures moved: absorption-truth, weakline, proposer, realistic-L and demo pools. Only the expected spectra changed; planted areas and counts did not.
  2. feat!: the broadened step becomes the default. Every registered synthetic result was re-measured; the numbers are in the commit and below. The in-test generators (SpectroTestSupport/DetectorBlur) are blurred the same way. Both blurs keep the input within one kernel reach of an axis end.
  3. test: the spectro goldens were re-recorded, then recorded again after the merge with main.

Numbers

Synthetic truth is planted, not measured.

Leeds pure-Al wedge: Snelson, Collins, MacArthur, doi 10.5518/1826, CC BY 4.0.

continuum data − model, 1.53-1.65 keV model / data − 1, 1.65-2.2 keV χ²/n, 0.8-2.6 keV
sharp (old default) +1677 +39.1 % 6.63
broadened (new default) +907 +19.1 % 3.10

Synthetic Al film, Si K-alpha bias, sharp → broadened:

film step sharp broadened
11 % −15.7 % −11.3 %
30 % −38.7 % −25.4 %

Demo pools (blurred continuum, noise-free, default sum peaks), Si K-alpha bias, sharp → broadened:

pool sharp broadened
recipe A −4.1 % −1.3 %
matrix map −4.3 % −1.6 %
L5 −8.4 % −2.4 %
L6 −1.2 % −1.1 %
L7 −0.03 % −0.04 %

Registered results re-measured:

  • Weak-line note (Mg counts: bias ± standard error):

    planted Mg generator bias
    900 A −270 ± 31
    882 S −272 ± 23
    3000 A −325 ± 38
    2899 S −226 ± 22

    The registered selection still picks Kramers (9,5).

  • Absorption-truth Si pin: −1.67 % (was −6.7 %).

  • Realistic-L Ti: pins re-measured; the range-statement bands are widened to the new measurements.

  • Proposer: the null-variance pins are re-pinned.

  • Demo L5 Mg with sum peaks: moves −24.5 → −15.6 %.

  • Registered bar lowered: the proposer's 1 % Mg ×100 cell on the Kramers continuum is now a candidate in 5 of 6 draws, not 6. In seed 2 the loop finds no residual peak at Mg. Either change alone, the blurred generator or the broadened step, also loses that draw.

  • ProposerMgDiagnosisTests: set M is the sharp model's own family, so its control and the +3 eV comparison run on .sharp.

The remaining misfit above the edge

On Leeds, data exceed the broadened model by +718 counts in 1.56-1.65 keV. The cause is the Al K-beta line: eXSpy ties it at 0.0132 of K-alpha.

  • Fitted free, K-beta reads 0.028 of K-alpha. The excess then drops to −121 counts and χ² to 2.35.
  • A free Gaussian scanned across 1.54-1.63 keV has its χ² minimum at 1.56-1.58 keV, which is the K-beta energy.
  • An extra continuum split at 1.65-1.70 keV fixes the Leeds excess but worsens Si on the synthetic film.
  • A low-energy tail for incomplete charge collection makes both worse.

None of these is shipped. A tied EPQ weight (0.0315) breaks the synthetic sets, which plant 0.0132.

Migration

A fit with the default policy now gives different numbers wherever an edge (the Al K edge by default) lies in the fitted range. To reproduce an earlier number, set FitPolicy.continuumEdgeStep = .sharp.

  • The default policy's canonical JSON gains "continuumEdgeStep":"broadened".
  • A stored policy without the key reads .sharp and gets the non-default footer line.
  • ContinuumForm.weakLineBiasNote quotes the re-measured numbers.

Tests

Kit gate green: swift test -c release --parallel --num-workers 1 -j 1 --skip SpectroKitParityTests (306 tests, 3 known issues). The full suite including SpectroKitParityTests is also green (83 tests, 2 known issues), on the merged tree.

Reviews

Two independent numerics reviews ran on the diff before the feat! commit. Their findings are fixed in it:

  • the blur no longer cuts the kernel at the axis ends;
  • the policy key is always written, so a .sharp policy's footer reads sharp, not nil;
  • the absorption-truth Si pins are re-measured;
  • stale comments are corrected.

Not done (open on #8)

  • An option for the Al K-beta weight in the quantification fit, tested on a synthetic set that plants the EPQ weight.
  • dead_layer_sim.py (from feat: optional detector Si dead-layer term in the EDX continuum #50) still plants an unblurred continuum. Its tests pass under the new default.
  • The make_planted.py sets (family continuum) are still projected on the sharp model.

🤖 Generated with Claude Code

Paullo9 and others added 9 commits October 31, 2026 14:42
…aks as explained

With the sum/escape model on, the unlisted-line check proposed on the bare spectrum and named the modelled pile-up and escape peaks as elements. SumEscapeResult.componentCounts (the fitted c S(A) + f E(A)) is now carried by the quantification and handed to ElementProposer.propose(explained:), which adds it to every fit as a fixed offset. nil (the default, and the model off) runs the proposer as before.

Planted pools (tools/edx-sim proposer_sim, model on): 100 counts/px no longer names Ar, Ag, Pd; 300 counts/px no longer names Rh, Ar, In, Sn, Pd, Ag, Cd, Ru, Bi, K; a planted Fe escape with the free escape columns off no longer names La, Ce, Cr, Cs. A planted K K-alpha between two sum peaks is still named first. Model off: unchanged.

Done: sum/escape peaks are explained counts for the proposer and the check. Next: docs rows for parity.md and open-items.md item 8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pair is significant

The pooled quantification fitted one Gaussian per line and no sum (pile-up) peaks, exSpy's model. On the public
synthetic AlMgSi demo (planted truth: the simulation recipe of sim_edx.py v2.0, not a measurement) that fit read
noise-free Si K-alpha 15-18 % low on the Al-rich map and fixture pools and 57 % low on the highest-rate pool, held
a planted Cu K-alpha at 0 at high rate, and had a reduced chi2 of 2.1-31 on the Poisson counts. The Al+Al sum peak
(2.97 keV) and its neighbours pull the continuum segment above the Al K edge, and Si K-alpha with it.

FitPolicy.sumPeaks (SumPeakRule, default .whenSignificant) now tests the strongest line's self pair alone with
EDSSumEscapeFit; when its pile-up coefficient is 3 sigma above 0 (sigma scaled by sqrt(max(chi2_red, 1)) of that
fit) the sum peaks of the four strongest lines are fitted and kept, otherwise the result is the old fit bit for
bit. The self pair is the test because the cross pairs absorbed an unlisted Cu K-alpha (Ni K-alpha + O K-alpha) on a
synthetic spectrum with no pile-up. The footer names the decision with its number, and names the alpha lines within
one FWHM of the self pair (Ar K-alpha, Ag L-alpha under Al+Al): a real line there is read as pile-up.
.off (FitPolicy.exspyEquivalent) is the old fit; a caller passing sumEscape keeps full control. The unlisted-line
and fit-range refits repeat the reported decision; the proposer axis refinement runs without sum peaks.

Noise-free Si K-alpha against planted: -0.0 to -4.0 % on five pools, -7.9 % at the highest rate; Cu K-alpha 92-97 %
of planted at high rate (0-42 % before); reduced chi2 on the Poisson counts 0.70-1.08. The absorption-truth Si pin
moves from -0.203 to -0.067 (+- 0.051), and the old pin stays on the .off fit. The Al K-alpha tail stays a detector
calibration: measured once with TailEstimate on a high-count spectrum and typed, it brings Mg K-alpha from -22 to
-32 % to within 5 % (matrix map -15 %). New fixture edx-demo-pools.json from tools/edx-sim/demo_pools.py. The
golden scenarios pin the explicit off model; their numbers are unchanged, only the two new nil fields are added.
Results stay validation none. Reviewed (numerics, two independent reviews): sigma scaling, the coincident-line
caveat, the axis refinement cost and the wording fixed.

BREAKING CHANGE: PooledQuantifier.run fits sum peaks by default when the data support them, so nets, at% and wt%
change on spectra with pile-up. Migration: pass a policy with fit.sumPeaks = .off (or FitPolicy.exspyEquivalent),
or sumEscape: SumEscapeModel(), to keep the old numbers. A stored QuantificationPolicy without the new field
decodes as .off and its footer names the non-default policy.

Done: sum peaks on by default in the pooled fit, with planted-truth tests on the demo pools. Next: the parity and
open-items rows once the open PRs on those files land, a check of the default on real data with published values,
and the sum-peak question for the auto ID possible candidates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The default continuum cuts its Bernstein segments at the Al K edge with a
jump between two channels. A detector cannot record that: every channel is
the incoming spectrum convolved with the resolution (about 75 eV FWHM at
1.56 keV), and the Al K-beta line sits on the edge energy itself.

FitPolicy.continuumEdgeStep = .broadened weights each segment by the
detector Gaussian step at its edges (Phi_a - Phi_b, sigma from the
line-width law at the edge, the line model resolution) and continues each
polynomial past its edge at its end value. The weights telescope to 1 and
stay non-negative. .sharp stays the default and is the earlier form value
for value; the default policy JSON is byte for byte unchanged (the key is
written only when not the default; old stored policies decode to .sharp).

Measured on the public Leeds pure-Al wedge (Snelson, Collins, MacArthur,
doi 10.5518/1826, CC BY 4.0), same refined axis: the model fell 351 counts
more than the data across the edge channel pair (42 broadened), the data
sat 1677 counts above the model in 1.53-1.65 keV (907) and the model 39 %
above the data in 1.65-2.2 keV (19 %). On a generated Al film with a
broadened edge a weak Si K-alpha reads -38.7 % sharp and -25.4 % broadened.

Done: broadened edge step as an option, tests on a generated spectrum.
Next: re-measure the registered synthetic results with a convolved
generator and make .broadened the default; the order-5 segment above the
edge is the remaining Si lever.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both add FitPolicy fields with a tolerant decoder; the resolved policy
keeps sumPeaks and sumPeakSignificance as that branch encodes them and
writes continuumEdgeStep only when it is not the default.

Done: stacked on the pooled sum-peak branch, gate green.
Next: open the PR against that branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or resolution

A detector records every photon with its Gaussian resolution, so an absorption edge in the
continuum reaches the spectrum as a blurred step (about 75 eV FWHM at the Al K edge for
130 eV at Mn K-alpha), never as a jump between two channels. The generators drew their lines
as Gaussians but planted the continuum, and its Al K edge, unblurred. A fit whose step is
broadened by the detector (FitPolicy.continuumEdgeStep = .broadened) was therefore measured on
synthetic spectra that no detector could record.

tools/edx-sim/detector_blur.py rebuilds the forward model continuum of the same pixels and
replaces it by its blurred copy (photon by photon, sigma from the line-width law at each
energy, counts conserved): expected - C + blur(C).

- absorption_truth_sim.py, weakline_sim.py, proposer_sim.py: forward.py itself is unchanged;
  the rebuilt continuum equals forward.py to 5e-16 in 9.5-19 keV.
- demo_pools.py: the demo generator (sim_edx.py v2.0) uses the same continuum; each pool is
  rebuilt from the truth arrays and checked against the generator in 9.5-19 keV (within 1e-9,
  the script stops otherwise). The pools counts stay the demo files Poisson draws: the blur
  moves at most 1.2 counts in a channel, 0.1 sigma or less.
- realistic_l_sim.py: its 3 % Si K step is a normal-CDF step of the detector width.

Fixtures moved: eds-absorption-truth.json, eds-weakline-sim.json, eds-proposer-sim.json,
eds-realistic-l-sim.json, edx-demo-pools.json (expected spectra only; planted areas, truth
and counts unchanged). With the continuum step still sharp, one registered number moved: the
weak-line bias on generator S reads -297 +- 23 at 882 planted Mg K-alpha and -251 +- 21 at
2899 (was -310 +- 23 at both); the badge text quotes the new run. Generator A is unchanged.

Done: generators blur the continuum, fixtures regenerated. Next: make the broadened step the
default and re-measure the registered synthetic results under it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ector by default

FitPolicy.continuumEdgeStep and ContinuumForm.edgeStep now default to .broadened: each
continuum segment is weighted by the detector Gaussian step at its edges (sigma from the
line-width law at the edge, the line model resolution), as a detector records an edge.
.sharp, the cut at the edge channel, stays an option and is the earlier default value for
value. exSpy has no edge in its background (one polynomial), so no parity path changes.

Why: on the public Leeds pure-Al wedge (Snelson, Collins, MacArthur, doi 10.5518/1826,
CC BY 4.0; Titan 200 kV, Super-X, 214 793 px, the refined axis) chi2 per channel in
0.8-2.6 keV falls from 6.63 to 3.10, the data excess in 1.53-1.65 keV from 1677 to 907
counts and the model excess in 1.65-2.2 keV from +39 % to +19 %. The synthetic generators
now blur their continuum the same way (previous commit), so the planted results were
re-measured under the new default (synthetic truth is planted, not measured):

- demo pools, noise-free, with the default sum peaks, Si K-alpha sharp -> broadened:
  recipe A -4.1 -> -1.3 %, matrix map -4.3 -> -1.6 %, L5 -8.4 -> -2.4 %, L6 -1.2 -> -1.1 %,
  L7 -0.03 -> -0.04 %; absorption-truth pool -1.5 % (bounds kept).
- weak-line badge (30 seeds): -270 +- 31 at 900 Mg (A), -272 +- 23 at 882 (S),
  -325 +- 38 at 3000 (A), -226 +- 22 at 2899 (S); the selection still keeps Kramers (9,5).
- absorption-truth Si pin: -1.67 % +- 0.036 with sum peaks (was -6.7 +- 0.051),
  -17.2 % without (was -20.3); the 501-count Mg envelope is kept.
- realistic-L Ti nets 2979/3134/2982/3074/3057 (mean 3045), range statement Ti
  -6.4 ... -11.7 %, -1.8 ... -3.2 sigma (bands widened to -5.5 % and -1.7 sigma).
- proposer null variance re-pinned; demo L5: the sum peaks now take Mg from -24.5 % to
  -15.6 % (bound 0.10 there, 0.03 elsewhere).
- REGISTERED BAR LOWERED: the proposer 1 % Mg x100 cell on the Kramers continuum is a
  candidate in 5 of 6 draws (was 6): seed 2 shows no residual peak at Mg for the loop;
  either change alone loses it.
- ProposerMgDiagnosisTests: set M is the sharp model family, so its control and the
  +3 eV comparison run on .sharp (M 0.70, S+3 0.55); broadened M 0.695, S+3 0.702.

In-test generators blur their continuum too (SpectroTestSupport DetectorBlur): generator A
of SpectroscopyFitTests and the proposer generator. Both blurs (Swift and
tools/edx-sim/detector_blur.py) keep the input within one kernel reach of an axis end,
where counts from beyond the axis are missing (review finding); the forward and demo
fixtures were regenerated for that rule (expected spectra only, a few counts at the ends).

The policy now always writes continuumEdgeStep; a stored policy without it reads .sharp
(the form it was run with) and gets the non-default footer line.

Diagnosis of the remaining misfit above the edge (Leeds, 1.56-1.65 keV, +718 counts
broadened): it is the Al K-beta line, tied at eXSpy 0.0132 of K-alpha. Fitted free it
reads 0.028 (0.030 at 1.5575 keV) and the excess goes to -121, the 1.65-2.2 keV misfit to
+5 %, chi2 to 2.35; a free Gaussian scanned 1.54-1.63 keV has its chi2 minimum at
1.56-1.58 keV, the K-beta energy. Not shipped: tied at EPQ 0.0315 it breaks the planted
synthetic sets (they plant 0.0132), and a free K-beta reads 0.011 of a planted 0.0132 on
the synthetic film. An extra continuum split at 1.65-1.70 keV also removes the excess but
worsens the synthetic film Si (-11.3 -> -16.1 %); a low-energy tail (incomplete charge)
worsens both. Nothing else changed for it.

Migration: a fit with the default policy moves wherever an edge (the Al K edge by
default) lies in the fitted range. To reproduce an earlier number, set
FitPolicy.continuumEdgeStep = .sharp. The default policy canonical JSON gains
"continuumEdgeStep":"broadened".

Done: broadened step is the default, registered synthetic results re-measured.
Next: an Al K-beta weight option for the quantification fit (EPQ or free), measured on a
synthetic set that plants the EPQ weight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The goldens record every output of the six fixture scenarios bit for bit, so they move
with the default continuum step (now broadened by the detector), with the regenerated
synthetic fixtures (their continuum blurred by the detector) and with the new
continuumEdgeStep field in each dump of the fit settings and policy. The base branch had
not re-recorded them for that field. Recorded with SPECTRO_GOLDEN_DIR, the array
companions expanded with SPECTRO_GOLDEN_ARRAYS_DIR; the full suite, the parity target
included, is green afterwards.

Done: goldens re-recorded. Next: CI on the stacked branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…adened-step branch

Conflicts resolved additively: FitPolicy keeps continuumEdgeStep and gains main
continuumDeadLayer, which the custom Codable now encodes and decodes (absent reads nil);
PooledQuantification keeps appliedSumEscape and gains continuumDeadLayerMicrons. The
spectro goldens were re-recorded on the merged tree. Full suite green, the parity target
included (306 + 83 tests).

Done: main merged. Next: CI on the stacked branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paullo9 and others added 4 commits October 31, 2026 21:44
…-peak branch

Conflicts resolved keeping both sides:
- FitPolicy.init takes sumPeaks, sumPeakSignificance and continuumDeadLayer.
- FitPolicy CodingKeys and init(from:) now carry continuumDeadLayer. The branch had a hand-written decoder, so without this the dead-layer term was dropped from the encoded policy, its footer line and canonicalJSON (caught by testPooledQuantifierRunsTheTermTypedAndFittedAndNamesIt).
- PooledQuantification keeps appliedSumEscape and continuumDeadLayerMicrons; the result sets both.
- Spectro goldens: both new nil lines kept. Re-recorded from the merged code: byte-identical to the resolved files, no number moves.

Done: the sum-peak branch is on current main, fast gate and SpectroGoldenTests green.
Next: stack the continuum-edge branch on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the sigma terms) into the edge-step branch

Conflict in QuantificationPolicy.swift resolved keeping both sides:
- FitPolicy.init takes continuumEdgeStep and continuumDeadLayer.
- CodingKeys, the hand-written encode(to:) and init(from:) carry both: continuumEdgeStep written only when not sharp, continuumDeadLayer only when set, so the default canonical JSON is unchanged.

Done: the edge-step branch is on the updated sum-peak branch and main, fast gate green.
Next: re-record the goldens for the edgeStep line this branch adds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…no number moves

The fit-settings dump in each golden scenario gains one line per quantification, background.continuum.edgeStep = .sharp, from the field this branch adds; the branch had not re-recorded for it. Recorded with SPECTRO_GOLDEN_DIR from the merged code: 9 added lines, no other line differs, the array companions are unchanged.

Done: SpectroGoldenTests green on the edge-step branch.
Next: stack the broadened-default branch on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts resolved for this branch: QuantificationPolicy keeps the broadened default and always encodes continuumEdgeStep (the edge-step side carried the sharp default and the omit-when-sharp encoding this branch replaced). The spectro goldens were re-recorded from the merged code: byte-identical to this branch, which already carries the edgeStep lines with the broadened values. The merged tree equals this branch.

Done: the broadened-default branch is on the updated edge-step branch and main, fast gate green.
Next: stack the EPQ line-weight branch on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paullo9 and others added 9 commits October 31, 2026 23:41
Main now holds the sum-peak work as one squash commit whose tree equals the
sum-peak branch this branch was built on. The one conflict, in
QuantificationPolicy.swift, keeps the sum-peak code as on main and adds this
branch's continuumEdgeStep field, its encoder and its decoder default.
No golden moves in the merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SwiftLint trailing_newline and SwiftFormat consecutiveBlankLines flagged line 184. Lint (SwiftLint 0.65.1, SwiftFormat 0.64.4) is now clean on the whole tree.

Done: lint green on this branch. Next: merge it forward into the stacked branches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ns) into issue-8-broadened-default

Only the spectro goldens conflicted (eds-realistic-l-sim and eds-unlisted-sim, text and array companions). The merge keeps this branch side; the next commit re-records them from the merged code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bound

Recorded from the merged code. Against this branch side, the only change is the one main made: the O+O self-pair sum-peak questions on the Eu and Sm M lines in eds-realistic-l-sim and eds-unlisted-sim drop out (conflicts empty, sumPeakQuestion false, the withholding CSV hash and the conflict energy arrays follow). No other number moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-broadened-default

Main equals the old issue-8-continuum-edge tip tree for tree, and this branch
already carried that tip, so every conflict keeps the branch side:
Continuum.swift, QuantificationPolicy.swift, ContinuumEdgeBroadeningTests.swift,
docs/parity.md and the four conflicted spectro goldens. The goldens were
re-recorded from the merged code (testRecordBaseline, testRecordPortableArrays)
and are byte-identical to the branch side; no re-record commit is needed.

Done: branch is current with main after the #64 squash merge.
Next: CI on the PR, then the broadened default lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Paullo9
Paullo9 enabled auto-merge (squash) November 1, 2026 12:58
@Paullo9
Paullo9 merged commit 1a72013 into main Nov 1, 2026
7 checks passed
@Paullo9
Paullo9 deleted the issue-8-broadened-default branch November 1, 2026 13:26
Paullo9 added a commit that referenced this pull request Nov 1, 2026
Keeps one copy of the #59 sum-peak migration note (it appeared five times) and adds #65's breaking change: the broadened continuum step is the new default, and FitPolicy.continuumEdgeStep = .sharp keeps the old numbers. Collapses the duplicate #46, #47 and CI lines. Notes under #68 that refits on the opt-in fitted dead layer repeat the reported thickness, so their numbers can change. The version is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paullo9 added a commit that referenced this pull request Nov 1, 2026
* chore(main): release 0.13.0

* docs: tidy the 0.13.0 CHANGELOG entry

Keeps one copy of the #59 sum-peak migration note (it appeared five times) and adds #65's breaking change: the broadened continuum step is the new default, and FitPolicy.continuumEdgeStep = .sharp keeps the old numbers. Collapses the duplicate #46, #47 and CI lines. Notes under #68 that refits on the opt-in fitted dead layer repeat the reported thickness, so their numbers can change. The version is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: macem-release[bot] <349909138+macem-release[bot]@users.noreply.github.com>
Co-authored-by: Paullo9 <paullobpreis@icloud.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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