Prepare ph-color for public release - #28
Conversation
- 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.
…age reporting and generated source checks
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>
…rcise linking for all feature combinations
…tatus of repositories
There was a problem hiding this comment.
💡 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".
| 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`. |
There was a problem hiding this comment.
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 👍 / 👎.
Purpose and value
Prepare
ph-colorfor 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
0.1.0forph-colorandph-color-bake.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
b7a08d92cff86df633d289a0cc251d14794b865fcargo xtask generate, then clean diffcargo xtask cion Windows, Rust 1.94.0cargo deny checkthrough canonical gatecargo package -p ph-colorcargo package --list -p ph-color-bakeph-color = 0.1.0from crates.ioHost tests are software evidence. This PR does not claim device, timing, model, or physical evidence.
Documentation, history, and provenance
ciworkflow and repository-specific code of conduct added.Unreleased; no release is claimed.Handoff and remaining work
ciresult, then merge if green.mainprotection with the stablecicheck after the workflow exists on the default branch.