Skip to content

Prepare ph-color for public release - #28

Merged
swgiacomelli merged 10 commits into
mainfrom
swgiacomelli/review
Aug 22, 2026
Merged

swgiacomelli merged 10 commits into
mainfrom
swgiacomelli/review

Conversation

@swgiacomelli

@swgiacomelli swgiacomelli commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Purpose and value

Prepare ph-color for a public repository and a separately authorized first crates.io release. The change completes the fixed-point implementation and evidence gate, replaces the monolithic scaffold contract with focused maintained documentation, and establishes contributor-facing public repository surfaces.

Scope and governing decision

  • Maintainer decision: make the GitHub repository public and begin release preparation.
  • Publication status: not authorized in this task; no crate, tag, or GitHub Release has been published or created.
  • Candidate version: 0.1.0 for ph-color and ph-color-bake.
  • Explicitly outside this PR: registry upload, release tag, GitHub Release, and post-publication badge activation.

Contract and compatibility

The fixed-point numeric output and type-state boundaries are compatibility guarantees owned by docs/NUMERICS.md. The candidate raises the MSRV to Rust 1.94.0, strengthens branch-free/division-free target kernels and feature-combination evidence, and keeps the target/host derivation split intact.

Evidence

Claim or gate Command, artifact, or observation Result
Exact candidate b7a08d92cff86df633d289a0cc251d14794b865f Verified
Generated source cargo xtask generate, then clean diff PASS
Complete repository gate cargo xtask ci on Windows, Rust 1.94.0 PASS; no failures or skips
Target matrix 3 embedded targets × default/f32/oklab/f32+oklab PASS
Thumbv6m limits code size, zero static RAM, panic symbols, wide arithmetic PASS for all 4 feature combinations
Dependency policy cargo deny check through canonical gate PASS
Target package cargo package -p ph-color PASS; 67 files, 1.2 MiB compressed, license included
Baker package contents cargo package --list -p ph-color-bake PASS; license included
Baker package verification requires ph-color = 0.1.0 from crates.io Pending until separately authorized first publish
Local Markdown links repository-wide target check PASS

Host tests are software evidence. This PR does not claim device, timing, model, or physical evidence.

Documentation, history, and provenance

  • Root and package status disclosures say public but unpublished.
  • README, numeric policy, contribution, security, release, agent, and package-evaluation documentation reviewed.
  • Public bounded ci workflow and repository-specific code of conduct added.
  • Changelog remains under Unreleased; no release is claimed.
  • MIT license is present in both package archives.
  • Release procedure records that crates.io/docs.rs badges must be staged before packaging so the versioned crate READMEs contain them, then verified after publication.

Handoff and remaining work

  • Repository visibility is already public.
  • Wait for this PR's bounded hosted ci result, then merge if green.
  • Enable main protection with the stable ci check after the workflow exists on the default branch.
  • A later explicit maintainer instruction is required to close the changelog, stage published-state disclosures and badges, reverify exact packages, publish, tag, and create a GitHub Release.

swgiacomelli and others added 9 commits August 22, 2026 11:16
- Introduced Q4_28 as a signed fixed-point type for matrix and gain coefficients.
- Introduced Q0_16 as an unsigned fixed-point type for color channels and interpolation parameters.
- Updated tests and existing code to utilize the new fixed-point types for improved precision and clarity.
- Refactored color-related tests to ensure compatibility with the new fixed-point representations.
- Adjusted compile_fail tests to use Q0_16 and Q4_28 where appropriate, ensuring type safety and correctness.
- Updated AGENTS.md to emphasize the importance of README.md and NUMERICS.md for contributors.
- Removed CONTRACT.md as it is no longer needed; its contents have been integrated into other documents.
- Enhanced CHANGELOG.md to clarify numeric guarantees and resource constraints.
- Added NUMERICS.md to define numeric and type-state guarantees, ensuring clarity on the API's behavior.
- Revised CONTRIBUTING.md to specify evidence requirements for changes and reinforce the importance of maintaining the frozen contract.
- Updated README.md to reflect the current state of the project and its maintenance documentation.
- Adjusted various comments and documentation throughout the codebase to align with the new structure and clarify numeric rules.
- Ensured all references to the contract are replaced with appropriate documentation links.
- Improved package metadata for `ph-color-bake`, clarifying its role as a host-side generator for ph-color matrices and fixed-point LUTs.
- Introduced a canonical `no-f64` source gate to restrict double-precision references in the target crate.
- Added support for optional test coverage collection using `cargo xtask ci --coverage`, generating LCOV data.
- Refactored Oklab matrices and cube-root LUT to be generated from `ph-color-bake`, ensuring consistency with audited formulas.
- Updated documentation and contributing guidelines to reflect new commands and requirements.
- Implemented a new command in xtask to regenerate checked-in sources and added checks for generated source drift.
- Enhanced the Oklab module generation with detailed comments and structured output.
On a 32-bit target the defensive spelling of the numeric core compiled into
compiler-runtime calls: a thumbv6m probe over the public API linked
__aeabi_uidiv twice (LUT lookup, gradient sample, lerp), __aeabi_lmul
thirteen times (every matrix row and gain channel), and under
feature = "oklab" __aeabi_uldivmod, __udivmoddi4, and __aeabi_llsl -- the
last three named explicitly by the crate's own wide_div_symbols pattern.
They escaped the no-wide-div gate only because that step measures
ph-color-exercise, which is default-features-only.

Division by 65535 now uses the exact reciprocal expansion
(n + (n >> 16) + 1) >> 16, mul_acc assembles its Q4.28 x UQ0.16 product from
two 32-bit multiplies, oklab's cube divides by 65535 three times in u32
instead of once by 65535^2 in u64, round-half-away-from-zero and the UQ0.16
saturation are sign-mask arithmetic, and lerp folds round-half-up into the
quotient -- which also removes its t == 0 / t == 65535 special cases.
InterpLut::lookup and Gradient::sample clamp the segment index rather than
branching on the top knot: at full scale the clamped remainder is exactly
65535, so the general blend already returns the last knot. sat_unit on the
f32 path saturates with max/min, which an FPU lowers to vmaxnm/vminnm; the
trailing + 0.0 pins the one case where f32::max is free to pick either
operand (zeros of different sign).

Every result is bit-identical, including the frozen W7 goldens. New tests
pin the identities: the oklab cube against its u64 reference across all
65536 inputs, div/rem by 65535 against hardware / and % over the whole
proven numerator range, lerp's fused rounding against explicit
divide-then-round, mul_acc against the exact widening product at the
coefficient extremes, and sat_unit against the comparison chain at the
signed zeros and both NaN signs.

thumbv6m .text: exercise binary 1306 -> 716 bytes, oklab round-trip
2224 -> 876; thumbv8m.main oklab 1606 -> 892 and f32 pipeline 996 -> 900.
No compiler-runtime division, remainder, or 64-bit multiply helper is
linked for any color op at any feature combination.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
thumbv6m-code-size, static-ram, panic-free, and no-wide-div measured
ph-color-exercise built with default features only, while feature-powerset
compiled f32 and oklab without ever linking them. Those two features were
gated by nothing.

That is not hypothetical. Until the previous commit, oklab's cube divided a
u64 by 65535^2 and linked __aeabi_uldivmod, __udivmoddi4, and __aeabi_llsl --
three of the symbols the gate's own wide_div_symbols pattern names -- and the
gate passed. Reverting that cube now fails no-wide-div (oklab) and
no-wide-div (f32,oklab) with four hits each while default and f32 still pass.

The exercise binary is now built once per entry in packages.ron's
feature_powerset, each build preserved at its own path under
target/xtask-exercise so four checks can read four distinct binaries from one
build pass. Each of the four checks reports one summary line per combination,
the way publish-lock already reports one per member.

ph-color-exercise gained f32 and oklab features forwarding to ph-color, and
reaches what each adds: the ColorF32 apply/lookup/lerp/to_color path, and the
linear-sRGB <-> Oklab round trip with its cube-root LUT. A feature whose
public surface is unreachable from that binary is a feature these gates do
not cover.

The .text budget stays scoped to the default build, the combination it was
calibrated for. A soft-float or Oklab build legitimately carries more code
(default 716, oklab 1520, f32 4050, f32+oklab 4842), and inventing
per-feature budgets
would assert numbers nobody chose; those combinations are measured and
printed, not failed. static RAM = 0 is asserted everywhere -- zero needs no
per-feature headroom.

CONTRIBUTING.md's Gate section is updated to match, since it described these
assertions as being made against one binary. xtask tests pin the variant
list, the single budgeted combination, and the distinct per-variant binary
paths.

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a1b20ceee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread RELEASING.md Outdated
Comment on lines +33 to +36
3. Run `cargo xtask generate`, review any generated diff, and run the complete
`cargo xtask ci` gate with no failed or unreported skipped checks.
4. Inspect each package with `cargo package --list` and
`cargo publish --dry-run`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Make the release gate compatible with publication

At step 3, the required full gate runs publish-lock, which fails if either workspace package stops using publish = false; if the manifests remain locked, step 4's cargo publish --dry-run rejects both packages as non-publishable. The checked xtask/data/gate.ron and both crate manifests therefore leave no sequence that can complete this newly documented release process; update the publication policy and gate together or retain the no-publication workflow.

AGENTS.md reference: AGENTS.md:L61-L67

Useful? React with 👍 / 👎.

@swgiacomelli swgiacomelli changed the title Swgiacomelli/review Prepare ph-color for public release Aug 22, 2026
@swgiacomelli
swgiacomelli merged commit 1876044 into main Aug 22, 2026
1 check passed
@swgiacomelli
swgiacomelli deleted the swgiacomelli/review branch August 22, 2026 17:34
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