diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 318c5b2e..6661e4c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -385,6 +385,7 @@ jobs: 46ec939523a9aff4f253c4c74e997dfd95812a694b2507fae885ff60244ade3a crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v3.json 3c257c336bc403eee933990fd7188a3b0a6e89d0cbc983aff18846ef76206275 crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v4.json 6079612797bb28a9fc97c1451efd830e2323ed06e15fbffd70527dddc3fa84c5 crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v5.json + 2e319643e582ca385f988af173b534cd9d1c921f36fcc929f1c56eb8bd978d24 crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v6.json SHA256 historical_artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v1.json" @@ -505,8 +506,9 @@ jobs: cleanup_history trap - EXIT - current_artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v5.json" - current_protocol=( + v5_artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v5.json" + v5_snapshot=9819bbd549ef2347eb133b948ccb5f7a3c5a51fe + v5_protocol=( --admit-rustc-release 1.96.0 --admit-cargo-release 1.96.0 --admit-rustc-binary-sha256 c5922366bfe3d6d028a65d626f4e629b3adad066995cf0b60c8a4b617bba5ffe @@ -519,9 +521,35 @@ jobs: --admit-package-version 0.2.0 --admit-sample-count 5 ) + trap cleanup_history EXIT + git worktree add --detach "$historical_root" "$v5_snapshot" + ( + cd "$historical_root" + python3 scripts/check_wcag22_feasibility_benchmark.py \ + "$v5_artifact" "${v5_protocol[@]}" \ + --artifact-sha256 6079612797bb28a9fc97c1451efd830e2323ed06e15fbffd70527dddc3fa84c5 \ + --self-test + ) + cleanup_history + trap - EXIT + + current_artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v6.json" + current_protocol=( + --admit-rustc-release 1.96.0 + --admit-cargo-release 1.96.0 + --admit-rustc-binary-sha256 c5922366bfe3d6d028a65d626f4e629b3adad066995cf0b60c8a4b617bba5ffe + --admit-cargo-binary-sha256 fec239e6b74df873f54ef52912bfcfcc8d8414bc14a7ae1e0be80460bae72841 + --admit-benchmark-binary-sha256 1e43b4c8418b8f45da3614d9697966874943e034d4275ee2a404f95aa60dbd2a + --admit-target-triple aarch64-apple-darwin + --admit-target-arch aarch64 + --admit-target-os macos + --admit-pointer-width-bits 64 + --admit-package-version 0.2.0 + --admit-sample-count 5 + ) python3 scripts/check_wcag22_feasibility_benchmark.py \ "$current_artifact" "${current_protocol[@]}" \ - --artifact-sha256 6079612797bb28a9fc97c1451efd830e2323ed06e15fbffd70527dddc3fa84c5 \ + --artifact-sha256 2e319643e582ca385f988af173b534cd9d1c921f36fcc929f1c56eb8bd978d24 \ --self-test audit: diff --git a/crates/labcolors-core/benches/wcag22_feasibility_admission.rs b/crates/labcolors-core/benches/wcag22_feasibility_admission.rs index aaffccff..f986b983 100644 --- a/crates/labcolors-core/benches/wcag22_feasibility_admission.rs +++ b/crates/labcolors-core/benches/wcag22_feasibility_admission.rs @@ -13,7 +13,7 @@ //! //! ```text //! python3 scripts/check_wcag22_feasibility_benchmark.py \ -//! /private/tmp/labcolors-wcag22-feasibility-admission-raw-v5.json \ +//! /private/tmp/labcolors-wcag22-feasibility-admission-raw-v6.json \ //! --record --record-toolchain 1.96.0 --record-sample-count 5 //! ``` @@ -39,8 +39,8 @@ use labcolors_core::wcag22_feasibility::{ #[path = "../src/sha256.rs"] mod subject_sha256; -const ARTIFACT_ID: &str = "wcag22-feasibility-admission-raw-v5"; -const DEFAULT_OUTPUT_FILENAME: &str = "labcolors-wcag22-feasibility-admission-raw-v5.json"; +const ARTIFACT_ID: &str = "wcag22-feasibility-admission-raw-v6"; +const DEFAULT_OUTPUT_FILENAME: &str = "labcolors-wcag22-feasibility-admission-raw-v6.json"; const CANDIDATE_COUNT: u64 = 256; const PAGE_BYTES: u64 = 65_536; const DECISION_SLOT_BYTES: u64 = 32; diff --git a/crates/labcolors-core/contracts/solve-characterization-v1-linux-x64.json b/crates/labcolors-core/contracts/solve-characterization-v1-linux-x64.json new file mode 100644 index 00000000..efd8c635 --- /dev/null +++ b/crates/labcolors-core/contracts/solve-characterization-v1-linux-x64.json @@ -0,0 +1,79 @@ +{ + "bg=#000000 contract=range(-20,-12) floor=default hue=200 chroma=relative(0.2)": "ok hex=#4C5859 lc_bits=c033eb2f56d7953a wcag_ratio_bits=4006c7903da3d9f9 floor_override=false jp_bits=4043484774ea7f53 h_ok_bits=4069582eba54d826 s_bits=3fc8040dd55b0ea2", + "bg=#000000 contract=text(-30) floor=default hue=264 chroma=neutral": "ok hex=#757575 lc_bits=c0407bf78d795563 wcag_ratio_bits=40123b279e4ef457 floor_override=true jp_bits=404a01cd7cd18ef1 h_ok_bits=4056780935e40784 s_bits=3f92b3eaf5dd28fb", + "bg=#000000 contract=text(-60) floor=default hue=264 chroma=neutral": "ok hex=#ADADAD lc_bits=c04e206032be5432 wcag_ratio_bits=4022b724a3df2cfd floor_override=false jp_bits=40526a89b1df20eb h_ok_bits=4056780938405de8 s_bits=3f90b66d677d74e9", + "bg=#000000 contract=text(-7.3) floor=none hue=0 chroma=neutral": "err below_contrast_floor target_bits=c01d333333333333", + "bg=#000000 contract=text(-7.35) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.3999999999999995) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.449999999999999) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.499999999999999) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.549999999999999) floor=none hue=0 chroma=neutral": "ok hex=#333333 lc_bits=c01ea8482ca51395 wcag_ratio_bits=3ffa97f146345f78 floor_override=false jp_bits=40379a02890521a3 h_ok_bits=40567809384f18c2 s_bits=3f993b7f9da97591", + "bg=#000000 contract=text(-7.599999999999999) floor=none hue=0 chroma=neutral": "ok hex=#333333 lc_bits=c01ea8482ca51395 wcag_ratio_bits=3ffa97f146345f78 floor_override=false jp_bits=40379a02890521a3 h_ok_bits=40567809384f18c2 s_bits=3f993b7f9da97591", + "bg=#000000 contract=text(-75) floor=default hue=264 chroma=neutral": "ok hex=#C8C8C8 lc_bits=c052c005f67406b8 wcag_ratio_bits=40291a6c78422f5e floor_override=false jp_bits=4054c1f701e27089 h_ok_bits=40567809383d8de9 s_bits=3f902d390e925099", + "bg=#000000 contract=text(-90) floor=default hue=264 chroma=neutral": "ok hex=#E2E2E2 lc_bits=c05685b4a1c4b863 wcag_ratio_bits=403035e2adc3bd56 floor_override=false jp_bits=4056d93b434508db h_ok_bits=405678093b47262a s_bits=3f8f9f3b38f57a7b", + "bg=#000000 contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(30) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=403e000000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=0000000000000000", + "bg=#007AFF contract=text(-30) floor=default hue=264 chroma=neutral": "err floor_unreachable floor_bits=4012000000000000 max_ratio_bits=401011621957ec8b", + "bg=#007AFF contract=text(-60) floor=default hue=264 chroma=neutral": "err floor_unreachable floor_bits=4012000000000000 max_ratio_bits=401011621957ec8b", + "bg=#007AFF contract=text(-75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c052c00000000000 max_achievable_bits=c0517234ae859911", + "bg=#007AFF contract=text(-90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c056800000000000 max_achievable_bits=c0517234ae859911", + "bg=#007AFF contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=4043e4ead7083128", + "bg=#007AFF contract=text(30) floor=default hue=264 chroma=neutral": "ok hex=#161616 lc_bits=40424c97c00ffa8c wcag_ratio_bits=4012050d7f553963 floor_override=true jp_bits=4026af7a61be9dc3 h_ok_bits=405678093a3690f4 s_bits=3fa0a9f5b9b7f5c6", + "bg=#007AFF contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=4043e4ead7083128", + "bg=#007AFF contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=4043e4ead7083128", + "bg=#007AFF contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=4043e4ead7083128", + "bg=#101012 contract=text(-30) floor=default hue=264 chroma=neutral": "ok hex=#7C7C7C lc_bits=c0413aabbf5937d3 wcag_ratio_bits=401236d28e5eb135 floor_override=true jp_bits=404b703ca59c53df h_ok_bits=405678093959f144 s_bits=3f925ba04d130db6", + "bg=#101012 contract=text(-60) floor=default hue=264 chroma=neutral": "ok hex=#B0B0B0 lc_bits=c04e17cd17d4d882 wcag_ratio_bits=4021871cd1e7a8bf floor_override=false jp_bits=4052af5f842a02f0 h_ok_bits=405678093a0624e6 s_bits=3f90a4aec55c3f00", + "bg=#101012 contract=text(-75) floor=default hue=264 chroma=neutral": "ok hex=#CBCBCB lc_bits=c052c29b17b6cafc wcag_ratio_bits=40276e3c28d759ca floor_override=false jp_bits=405501cc74f52e6c h_ok_bits=405678093ab1fa8f s_bits=3f9020bdf8416400", + "bg=#101012 contract=text(-90) floor=default hue=264 chroma=neutral": "ok hex=#E5E5E5 lc_bits=c0568e7f7b53513f wcag_ratio_bits=402e2d302749fa72 floor_override=false jp_bits=4057146c003d4a49 h_ok_bits=405678093a443f87 s_bits=3f8f8d6ff945ddf2", + "bg=#101012 contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(30) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=403e000000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=ui(-45) floor=aa-ui hue=30 chroma=neutral": "ok hex=#929292 lc_bits=c0466d4fc2116bd4 wcag_ratio_bits=40186ec556f960d0 floor_override=false jp_bits=404fcbce5051da8e h_ok_bits=405678093ab1edbb s_bits=3f917ac53b790163", + "bg=#101012 contract=ui(-45) floor=default hue=30 chroma=relative(0.6)": "ok hex=#DA7667 lc_bits=c0467b775ffca0ab wcag_ratio_bits=401880d70a1d09c9 floor_override=false jp_bits=4050528c88ca1229 h_ok_bits=403dba4820849792 s_bits=3fdc3aa9098e6b07", + "bg=#6E6E6E contract=text(20) floor=default hue=145 chroma=relative(0.35)": "err floor_unreachable floor_bits=4012000000000000 max_ratio_bits=4010795fbcf07be5", + "bg=#6E6E6E contract=text(35) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4041800000000000 max_achievable_bits=4040274550888fa0", + "bg=#6E6E6E contract=text(45) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4046800000000000 max_achievable_bits=4040274550888fa0", + "bg=#767676 contract=text(-30) floor=default hue=264 chroma=neutral": "ok hex=#FEFEFE lc_bits=c05247730308def7 wcag_ratio_bits=401203d2a75973ae floor_override=true jp_bits=4058edc95c7d0739 h_ok_bits=4056780938a3dab2 s_bits=3f8f11e24d3c081e", + "bg=#767676 contract=text(-60) floor=default hue=264 chroma=neutral": "ok hex=#FEFEFE lc_bits=c05247730308def7 wcag_ratio_bits=401203d2a75973ae floor_override=true jp_bits=4058edc95c7d0739 h_ok_bits=4056780938a3dab2 s_bits=3f8f11e24d3c081e", + "bg=#767676 contract=text(-75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c052c00000000000 max_achievable_bits=c0526fc4767ff28a", + "bg=#767676 contract=text(-90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c056800000000000 max_achievable_bits=c0526fc4767ff28a", + "bg=#767676 contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#767676 contract=text(30) floor=default hue=264 chroma=neutral": "ok hex=#040404 lc_bits=4041a482ea107a48 wcag_ratio_bits=40120e02e539145b floor_override=true jp_bits=401059092a4614da h_ok_bits=4056780939c7cfcc s_bits=3fa699b120176455", + "bg=#767676 contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#767676 contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#767676 contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#7A7A7A contract=text(20) floor=default hue=145 chroma=relative(0.35)": "ok hex=#090F09 lc_bits=4041ecb761e73567 wcag_ratio_bits=40120e086c9db837 floor_override=true jp_bits=401f949b6fdfe12d h_ok_bits=40621957a9f13595 s_bits=3fe725dc768d9907", + "bg=#7A7A7A contract=text(35) floor=default hue=145 chroma=relative(0.35)": "ok hex=#090F09 lc_bits=4041ecb761e73567 wcag_ratio_bits=40120e086c9db837 floor_override=true jp_bits=401f949b6fdfe12d h_ok_bits=40621957a9f13595 s_bits=3fe725dc768d9907", + "bg=#7A7A7A contract=text(45) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4046800000000000 max_achievable_bits=4042d06c66880d47", + "bg=#828282 contract=text(20) floor=default hue=145 chroma=relative(0.35)": "ok hex=#131D14 lc_bits=404295d3d3b88678 wcag_ratio_bits=4012031326e8a7a2 floor_override=true jp_bits=4029f2303691ef3b h_ok_bits=40626b51de22ae27 s_bits=3fe414765bc2dc88", + "bg=#828282 contract=text(35) floor=default hue=145 chroma=relative(0.35)": "ok hex=#131D14 lc_bits=404295d3d3b88678 wcag_ratio_bits=4012031326e8a7a2 floor_override=true jp_bits=4029f2303691ef3b h_ok_bits=40626b51de22ae27 s_bits=3fe414765bc2dc88", + "bg=#828282 contract=text(45) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4046800000000000 max_achievable_bits=4044a24577876f8d", + "bg=#FFFFFF contract=range(12,20) floor=default hue=200 chroma=relative(0.2)": "ok hex=#D6E9EA lc_bits=4027f6fd10e07bdf wcag_ratio_bits=3ff41dc3fb3e1ca2 floor_override=false jp_bits=405709e6fe6385aa h_ok_bits=40691430e577c563 s_bits=3fb9748c1231e82e", + "bg=#FFFFFF contract=text(-30) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c03e000000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(-60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c04e000000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(-75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c052c00000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(-90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c056800000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=405a829a490ad002", + "bg=#FFFFFF contract=text(3) floor=none hue=0 chroma=neutral": "err below_contrast_floor target_bits=4008000000000000", + "bg=#FFFFFF contract=text(30) floor=default hue=264 chroma=neutral": "ok hex=#767676 lc_bits=40510fca61d5b9ee wcag_ratio_bits=40122b3d05125164 floor_override=true jp_bits=404a3678a8f0c874 h_ok_bits=405678093d6dbcc5 s_bits=3f92a6b801503a78", + "bg=#FFFFFF contract=text(60) floor=default hue=0 chroma=neutral gamut=display-p3": "err gamut_unsupported", + "bg=#FFFFFF contract=text(60) floor=default hue=264 chroma=neutral": "ok hex=#767676 lc_bits=40510fca61d5b9ee wcag_ratio_bits=40122b3d05125164 floor_override=true jp_bits=404a3678a8f0c874 h_ok_bits=405678093d6dbcc5 s_bits=3f92a6b801503a78", + "bg=#FFFFFF contract=text(7.3) floor=none hue=0 chroma=neutral": "err below_contrast_floor target_bits=401d333333333333", + "bg=#FFFFFF contract=text(7.35) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.3999999999999995) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.449999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.499999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.549999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.599999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(75) floor=default hue=264 chroma=neutral": "ok hex=#676767 lc_bits=4052b2df683f84d1 wcag_ratio_bits=4016a01035db8f1f floor_override=false jp_bits=404715e2dbaab4e2 h_ok_bits=4056780936c282c8 s_bits=3f9384586968a014", + "bg=#FFFFFF contract=text(90) floor=default hue=264 chroma=neutral": "ok hex=#414141 lc_bits=40567dc4663d6f83 wcag_ratio_bits=40246a7d157dd3fe floor_override=false jp_bits=403dbb13a4f6a259 h_ok_bits=40567809376d897f s_bits=3f970efa32c221ba", + "bg=#FFFFFF contract=ui(45) floor=aa-ui hue=30 chroma=neutral": "ok hex=#949494 lc_bits=404b2a103b08aa26 wcag_ratio_bits=4008448bd3f798b7 floor_override=true jp_bits=40501730c25c7ca2 h_ok_bits=405678093dcd90a5 s_bits=3f91699d6ed58610", + "bg=#FFFFFF contract=ui(45) floor=default hue=30 chroma=relative(0.6)": "ok hex=#DB796A lc_bits=404b13688ecb8170 wcag_ratio_bits=400827ad86a35ba7 floor_override=true jp_bits=40508499c7c25fa2 h_ok_bits=403dcf871712bc67 s_bits=3fdb57f17946ab92", + "bg=not-a-color contract=text(60) floor=default hue=0 chroma=neutral": "err invalid_input message=\"expected #RRGGBB, got #not-a-color\"" +} diff --git a/crates/labcolors-core/contracts/solve-characterization-v1-macos-aarch64.json b/crates/labcolors-core/contracts/solve-characterization-v1-macos-aarch64.json new file mode 100644 index 00000000..97b61a3b --- /dev/null +++ b/crates/labcolors-core/contracts/solve-characterization-v1-macos-aarch64.json @@ -0,0 +1,79 @@ +{ + "bg=#000000 contract=range(-20,-12) floor=default hue=200 chroma=relative(0.2)": "ok hex=#4C5859 lc_bits=c033eb2f56d7953a wcag_ratio_bits=4006c7903da3d9f9 floor_override=false jp_bits=4043484774ea7f53 h_ok_bits=4069582eba54d826 s_bits=3fc8040dd55b0ea2", + "bg=#000000 contract=text(-30) floor=default hue=264 chroma=neutral": "ok hex=#757575 lc_bits=c0407bf78d795563 wcag_ratio_bits=40123b279e4ef457 floor_override=true jp_bits=404a01cd7cd18ef1 h_ok_bits=4056780935e40784 s_bits=3f92b3eaf5dd28fb", + "bg=#000000 contract=text(-60) floor=default hue=264 chroma=neutral": "ok hex=#ADADAD lc_bits=c04e206032be5432 wcag_ratio_bits=4022b724a3df2cfd floor_override=false jp_bits=40526a89b1df20eb h_ok_bits=4056780938405de8 s_bits=3f90b66d677d74e9", + "bg=#000000 contract=text(-7.3) floor=none hue=0 chroma=neutral": "err below_contrast_floor target_bits=c01d333333333333", + "bg=#000000 contract=text(-7.35) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.3999999999999995) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.449999999999999) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.499999999999999) floor=none hue=0 chroma=neutral": "ok hex=#323232 lc_bits=c01d669a65189e80 wcag_ratio_bits=3ffa34ec4ba6a14b floor_override=false jp_bits=40372a75abaac644 h_ok_bits=40567809399b9177 s_bits=3f996ab47c9e865d", + "bg=#000000 contract=text(-7.549999999999999) floor=none hue=0 chroma=neutral": "ok hex=#333333 lc_bits=c01ea8482ca51395 wcag_ratio_bits=3ffa97f146345f78 floor_override=false jp_bits=40379a02890521a3 h_ok_bits=40567809384f18c2 s_bits=3f993b7f9da97591", + "bg=#000000 contract=text(-7.599999999999999) floor=none hue=0 chroma=neutral": "ok hex=#333333 lc_bits=c01ea8482ca51395 wcag_ratio_bits=3ffa97f146345f78 floor_override=false jp_bits=40379a02890521a3 h_ok_bits=40567809384f18c2 s_bits=3f993b7f9da97591", + "bg=#000000 contract=text(-75) floor=default hue=264 chroma=neutral": "ok hex=#C8C8C8 lc_bits=c052c005f67406b8 wcag_ratio_bits=40291a6c78422f5e floor_override=false jp_bits=4054c1f701e27089 h_ok_bits=40567809383d8de9 s_bits=3f902d390e925099", + "bg=#000000 contract=text(-90) floor=default hue=264 chroma=neutral": "ok hex=#E2E2E2 lc_bits=c05685b4a1c4b863 wcag_ratio_bits=403035e2adc3bd56 floor_override=false jp_bits=4056d93b434508db h_ok_bits=405678093b47262a s_bits=3f8f9f3b38f57a7b", + "bg=#000000 contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(30) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=403e000000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=0000000000000000", + "bg=#000000 contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=0000000000000000", + "bg=#007AFF contract=text(-30) floor=default hue=264 chroma=neutral": "err floor_unreachable floor_bits=4012000000000000 max_ratio_bits=401011621957ec8b", + "bg=#007AFF contract=text(-60) floor=default hue=264 chroma=neutral": "err floor_unreachable floor_bits=4012000000000000 max_ratio_bits=401011621957ec8b", + "bg=#007AFF contract=text(-75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c052c00000000000 max_achievable_bits=c0517234ae859911", + "bg=#007AFF contract=text(-90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c056800000000000 max_achievable_bits=c0517234ae859911", + "bg=#007AFF contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=4043e4ead7083128", + "bg=#007AFF contract=text(30) floor=default hue=264 chroma=neutral": "ok hex=#161616 lc_bits=40424c97c00ffa8c wcag_ratio_bits=4012050d7f553963 floor_override=true jp_bits=4026af7a61be9dc3 h_ok_bits=405678093a3690f4 s_bits=3fa0a9f5b9b7f5c6", + "bg=#007AFF contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=4043e4ead7083128", + "bg=#007AFF contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=4043e4ead7083128", + "bg=#007AFF contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=4043e4ead7083128", + "bg=#101012 contract=text(-30) floor=default hue=264 chroma=neutral": "ok hex=#7C7C7C lc_bits=c0413aabbf5937d3 wcag_ratio_bits=401236d28e5eb135 floor_override=true jp_bits=404b703ca59c53df h_ok_bits=405678093959f144 s_bits=3f925ba04d130db6", + "bg=#101012 contract=text(-60) floor=default hue=264 chroma=neutral": "ok hex=#B0B0B0 lc_bits=c04e17cd17d4d882 wcag_ratio_bits=4021871cd1e7a8bf floor_override=false jp_bits=4052af5f842a02f0 h_ok_bits=405678093a0624e6 s_bits=3f90a4aec55c3f00", + "bg=#101012 contract=text(-75) floor=default hue=264 chroma=neutral": "ok hex=#CBCBCB lc_bits=c052c29b17b6cafc wcag_ratio_bits=40276e3c28d759ca floor_override=false jp_bits=405501cc74f52e6c h_ok_bits=405678093ab1fa8f s_bits=3f9020bdf8416400", + "bg=#101012 contract=text(-90) floor=default hue=264 chroma=neutral": "ok hex=#E5E5E5 lc_bits=c0568e7f7b53513f wcag_ratio_bits=402e2d302749fa72 floor_override=false jp_bits=4057146c003d4a49 h_ok_bits=405678093a443f87 s_bits=3f8f8d6ff945ddf2", + "bg=#101012 contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(30) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=403e000000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=0000000000000000", + "bg=#101012 contract=ui(-45) floor=aa-ui hue=30 chroma=neutral": "ok hex=#929292 lc_bits=c0466d4fc2116bd4 wcag_ratio_bits=40186ec556f960d0 floor_override=false jp_bits=404fcbce5051da8e h_ok_bits=405678093ab1edbb s_bits=3f917ac53b790163", + "bg=#101012 contract=ui(-45) floor=default hue=30 chroma=relative(0.6)": "ok hex=#DA7667 lc_bits=c0467b775ffca0ab wcag_ratio_bits=401880d70a1d09c9 floor_override=false jp_bits=4050528c88ca1229 h_ok_bits=403dba4820849792 s_bits=3fdc3aa9098e6b07", + "bg=#6E6E6E contract=text(20) floor=default hue=145 chroma=relative(0.35)": "err floor_unreachable floor_bits=4012000000000000 max_ratio_bits=4010795fbcf07be5", + "bg=#6E6E6E contract=text(35) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4041800000000000 max_achievable_bits=4040274550888fa0", + "bg=#6E6E6E contract=text(45) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4046800000000000 max_achievable_bits=4040274550888fa0", + "bg=#767676 contract=text(-30) floor=default hue=264 chroma=neutral": "ok hex=#FEFEFE lc_bits=c05247730308def7 wcag_ratio_bits=401203d2a75973ae floor_override=true jp_bits=4058edc95c7d0739 h_ok_bits=4056780938a3dab2 s_bits=3f8f11e24d3c081e", + "bg=#767676 contract=text(-60) floor=default hue=264 chroma=neutral": "ok hex=#FEFEFE lc_bits=c05247730308def7 wcag_ratio_bits=401203d2a75973ae floor_override=true jp_bits=4058edc95c7d0739 h_ok_bits=4056780938a3dab2 s_bits=3f8f11e24d3c081e", + "bg=#767676 contract=text(-75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c052c00000000000 max_achievable_bits=c0526fc4767ff28a", + "bg=#767676 contract=text(-90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c056800000000000 max_achievable_bits=c0526fc4767ff28a", + "bg=#767676 contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#767676 contract=text(30) floor=default hue=264 chroma=neutral": "ok hex=#040404 lc_bits=4041a482ea107a48 wcag_ratio_bits=40120e02e539145b floor_override=true jp_bits=401059092a4614da h_ok_bits=4056780939c7cfcc s_bits=3fa699b120176455", + "bg=#767676 contract=text(60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=404e000000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#767676 contract=text(75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4052c00000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#767676 contract=text(90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4056800000000000 max_achievable_bits=4041eafa25e9ad94", + "bg=#7A7A7A contract=text(20) floor=default hue=145 chroma=relative(0.35)": "ok hex=#090F09 lc_bits=4041ecb761e73567 wcag_ratio_bits=40120e086c9db837 floor_override=true jp_bits=401f949b6fdfe12d h_ok_bits=40621957a9f1359a s_bits=3fe725dc768d9907", + "bg=#7A7A7A contract=text(35) floor=default hue=145 chroma=relative(0.35)": "ok hex=#090F09 lc_bits=4041ecb761e73567 wcag_ratio_bits=40120e086c9db837 floor_override=true jp_bits=401f949b6fdfe12d h_ok_bits=40621957a9f1359a s_bits=3fe725dc768d9907", + "bg=#7A7A7A contract=text(45) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4046800000000000 max_achievable_bits=4042d06c66880d47", + "bg=#828282 contract=text(20) floor=default hue=145 chroma=relative(0.35)": "ok hex=#131D14 lc_bits=404295d3d3b88678 wcag_ratio_bits=4012031326e8a7a2 floor_override=true jp_bits=4029f2303691ef3b h_ok_bits=40626b51de22ae27 s_bits=3fe414765bc2dc88", + "bg=#828282 contract=text(35) floor=default hue=145 chroma=relative(0.35)": "ok hex=#131D14 lc_bits=404295d3d3b88678 wcag_ratio_bits=4012031326e8a7a2 floor_override=true jp_bits=4029f2303691ef3b h_ok_bits=40626b51de22ae27 s_bits=3fe414765bc2dc88", + "bg=#828282 contract=text(45) floor=default hue=145 chroma=relative(0.35)": "err exceeds_range target_bits=4046800000000000 max_achievable_bits=4044a24577876f8d", + "bg=#FFFFFF contract=range(12,20) floor=default hue=200 chroma=relative(0.2)": "ok hex=#D6E9EA lc_bits=4027f6fd10e07bdf wcag_ratio_bits=3ff41dc3fb3e1ca2 floor_override=false jp_bits=405709e6fe6385aa h_ok_bits=40691430e577c563 s_bits=3fb9748c1231e82e", + "bg=#FFFFFF contract=text(-30) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c03e000000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(-60) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c04e000000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(-75) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c052c00000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(-90) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=c056800000000000 max_achievable_bits=0000000000000000", + "bg=#FFFFFF contract=text(150) floor=default hue=264 chroma=neutral": "err exceeds_range target_bits=4062c00000000000 max_achievable_bits=405a829a490ad002", + "bg=#FFFFFF contract=text(3) floor=none hue=0 chroma=neutral": "err below_contrast_floor target_bits=4008000000000000", + "bg=#FFFFFF contract=text(30) floor=default hue=264 chroma=neutral": "ok hex=#767676 lc_bits=40510fca61d5b9ee wcag_ratio_bits=40122b3d05125164 floor_override=true jp_bits=404a3678a8f0c874 h_ok_bits=405678093d6dbcc5 s_bits=3f92a6b801503a78", + "bg=#FFFFFF contract=text(60) floor=default hue=0 chroma=neutral gamut=display-p3": "err gamut_unsupported", + "bg=#FFFFFF contract=text(60) floor=default hue=264 chroma=neutral": "ok hex=#767676 lc_bits=40510fca61d5b9ee wcag_ratio_bits=40122b3d05125164 floor_override=true jp_bits=404a3678a8f0c874 h_ok_bits=405678093d6dbcc5 s_bits=3f92a6b801503a78", + "bg=#FFFFFF contract=text(7.3) floor=none hue=0 chroma=neutral": "err below_contrast_floor target_bits=401d333333333333", + "bg=#FFFFFF contract=text(7.35) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.3999999999999995) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.449999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.499999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.549999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(7.599999999999999) floor=none hue=0 chroma=neutral": "ok hex=#EDEDED lc_bits=401e6aa8625b8742 wcag_ratio_bits=3ff2bb539763a677 floor_override=false jp_bits=4057afba8603b8da h_ok_bits=40567809393247c1 s_bits=3f8f614c4436cac4", + "bg=#FFFFFF contract=text(75) floor=default hue=264 chroma=neutral": "ok hex=#676767 lc_bits=4052b2df683f84d1 wcag_ratio_bits=4016a01035db8f1f floor_override=false jp_bits=404715e2dbaab4e2 h_ok_bits=4056780936c282c8 s_bits=3f9384586968a014", + "bg=#FFFFFF contract=text(90) floor=default hue=264 chroma=neutral": "ok hex=#414141 lc_bits=40567dc4663d6f83 wcag_ratio_bits=40246a7d157dd3fe floor_override=false jp_bits=403dbb13a4f6a259 h_ok_bits=40567809376d897f s_bits=3f970efa32c221ba", + "bg=#FFFFFF contract=ui(45) floor=aa-ui hue=30 chroma=neutral": "ok hex=#949494 lc_bits=404b2a103b08aa26 wcag_ratio_bits=4008448bd3f798b7 floor_override=true jp_bits=40501730c25c7ca2 h_ok_bits=405678093ba724ad s_bits=3f91699d6ed58610", + "bg=#FFFFFF contract=ui(45) floor=default hue=30 chroma=relative(0.6)": "ok hex=#DB796A lc_bits=404b13688ecb8170 wcag_ratio_bits=400827ad86a35ba7 floor_override=true jp_bits=40508499c7c25fa2 h_ok_bits=403dcf871712bc67 s_bits=3fdb57f17946ab92", + "bg=not-a-color contract=text(60) floor=default hue=0 chroma=neutral": "err invalid_input message=\"expected #RRGGBB, got #not-a-color\"" +} diff --git a/crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v6.json b/crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v6.json new file mode 100644 index 00000000..faedd443 --- /dev/null +++ b/crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v6.json @@ -0,0 +1,1072 @@ +{ + "schemaVersion": 1, + "artifactId": "wcag22-feasibility-admission-raw-v6", + "recordProvenance": { + "recipeId": "closed-cargo-bench-v1", + "sourceSnapshotSha256": "5df614fd86c5ec6e96ed1faee100645c185356d9cf0b73caacaa9ece9d3a5cd9", + "benchmarkBinarySha256": "1e43b4c8418b8f45da3614d9697966874943e034d4275ee2a404f95aa60dbd2a" + }, + "claimBoundary": "native-process-observations-and-page-slot-arithmetic-only", + "notMeasured": [ + "webassembly-runtime-memory", + "serialized-output-size", + "client-latency" + ], + "environment": { + "execution": "native-process", + "targetArch": "aarch64", + "targetOs": "macos", + "pointerWidthBits": 64, + "debugAssertions": false, + "packageVersion": "0.2.0", + "allocator": "std::alloc::System", + "allocatorInstrumentationIncludedInElapsedTime": true, + "timer": "std::time::Instant", + "measurementThreads": 1, + "requestConstructionMeasured": false, + "rustcVerbose": "rustc 1.96.0 (ac68faa20 2026-05-25)\nbinary: rustc\ncommit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96\ncommit-date: 2026-05-25\nhost: aarch64-apple-darwin\nrelease: 1.96.0\nLLVM version: 22.1.2", + "cargoVerbose": "cargo 1.96.0 (30a34c682 2026-05-25)\nrelease: 1.96.0\ncommit-hash: 30a34c6821b57de0aaec83a901aca39f88f6778c\ncommit-date: 2026-05-25\nhost: aarch64-apple-darwin\nlibgit2: 1.9.2 (sys:0.20.4 vendored)\nlibcurl: 8.7.1 (sys:0.4.87+curl-8.19.0 system ssl:(SecureTransport) LibreSSL/3.3.6)\nssl: OpenSSL 3.5.4 30 Sep 2025\nos: Mac OS 26.2.0 [64-bit]", + "activeCoreFeatures": [ + "wcag22-feasibility", + "wcag22-explicit-feasibility" + ], + "explicitEmptyBuildInputs": [ + "CARGO_ENCODED_RUSTFLAGS", + "RUSTC_WRAPPER", + "RUSTC_WORKSPACE_WRAPPER" + ], + "rustcBinarySha256": "c5922366bfe3d6d028a65d626f4e629b3adad066995cf0b60c8a4b617bba5ffe", + "cargoBinarySha256": "fec239e6b74df873f54ef52912bfcfcc8d8414bc14a7ae1e0be80460bae72841", + "sourceConeClean": true, + "sampleCountExplicit": true, + "sourceObjects": { + "workspaceCargo": { + "path": "Cargo.toml", + "gitObject": "2864585584e98c8d99802a3eb440a2d2cee85c7f" + }, + "workspaceLock": { + "path": "Cargo.lock", + "gitObject": "8152afa0fb6656fbe0a367880d5f7a3b1122c09b" + }, + "coreCargo": { + "path": "crates/labcolors-core/Cargo.toml", + "gitObject": "96dc3f9f072fbfc8cd34899cbf7303c1eeb803dc" + }, + "coreSourceTree": { + "path": "crates/labcolors-core/src", + "gitObject": "5b9db8c1d9eaa8f13d7fae201e1a6819871f6b74" + }, + "wcag22Srgb8Contract": { + "path": "crates/labcolors-core/contracts/wcag22-srgb8-v1.json", + "gitObject": "7b3932335398bdbc0760136904cb245305749b09" + }, + "wcag22Q55ProofContract": { + "path": "crates/labcolors-core/contracts/wcag22-srgb8-q55-proof-v1.json", + "gitObject": "ddce1912e8e06ce6bd55c9854acf27a28a31b134" + }, + "benchmarkHarness": { + "path": "crates/labcolors-core/benches/wcag22_feasibility_admission.rs", + "gitObject": "f986b983c20f27969cdc36b7e1b3f890e34d4470" + }, + "benchmarkChecker": { + "path": "scripts/check_wcag22_feasibility_benchmark.py", + "gitObject": "0e6d3504559e43a7bf2b412256fc40c8791952aa" + } + } + }, + "warmupSamples": 0, + "scenarioOrder": "as-emitted", + "sampleCount": 5, + "admissionStatus": "measurement-only-unless-admission-check-passes", + "hardSlo": { + "class": "deterministic-work-and-storage", + "logicalAssessmentLaw": "W=256E", + "packedStorageLaw": "B=0 if A=0, otherwise B=32(E+1)", + "partialTerminalAllowed": false, + "timingThresholdNs": null, + "allRequiredShapesMustComplete": true + }, + "boundedEnvelopeModel": { + "scope": "product-policy-capacity-arithmetic-not-total-memory", + "referenceBoundedBytes": 65536, + "candidateCount": 256, + "decisionSlotBytes": 32, + "partitionBytes": 32, + "reservedPartitionSlots": 1, + "maximumCardinality": 2047, + "maximumLogicalAssessments": 524032, + "maximumPackedResultBytes": 65536 + }, + "subjectManifest": [ + { + "path": "Cargo.toml", + "sha256": "fe8cee2f18a9df79d2de8d6ca6ce968237463ae732792114516d13b2c39d6da4" + }, + { + "path": "crates/labcolors-core/src/lib.rs", + "sha256": "a98651f9b4ab45237fbc04bda90cc260b98e6caf6b99fada63407745cdbd3d64" + }, + { + "path": "crates/labcolors-core/src/wcag22_feasibility.rs", + "sha256": "f57f4d2008880911fdb83e99598744c57cbc66286464dc2296ff31b5b495d96e" + }, + { + "path": "crates/labcolors-core/src/wcag22_feasibility/explicit.rs", + "sha256": "be96c7133efe72fb994a9f5dc656186934a3070d57e4541b900d1157bfb1d3c2" + }, + { + "path": "crates/labcolors-core/src/srgb8.rs", + "sha256": "9a37ea3f25f7ab3e2ae064e5a5b5c7d51a880a537c297169d6014fa32e593e17" + }, + { + "path": "crates/labcolors-core/src/sha256.rs", + "sha256": "09827c91997db66ade30ec7b68b422b4204004296e17b2ee6de49af9ea5b002a" + }, + { + "path": "crates/labcolors-core/src/wcag22.rs", + "sha256": "3e648301d01515f221a783625fa18f41859989f00ceda1cfc3360205d29ab852" + }, + { + "path": "crates/labcolors-core/src/wcag22/kernel.rs", + "sha256": "c97980c1ca2c7ea9cabff9c8d2fb7282773cca180ae15948391c29c9d6196040" + }, + { + "path": "crates/labcolors-core/src/wcag22/q55_data.rs", + "sha256": "af4d23d6b70c45ce6efa839e7dda4bb0a61f6aae43cb805af6fa9b29e6c3bae2" + }, + { + "path": "crates/labcolors-core/src/wcag22_evidence.rs", + "sha256": "3c5a75b07254c6071a64700af208a64987d0f0ea9698eadc54a9e74585ce1f72" + }, + { + "path": "crates/labcolors-core/src/numerics.rs", + "sha256": "ef10c32534f8e3af7c895aaf465a142184ed651d11634d6c0bbb60db4ff2304f" + }, + { + "path": "crates/labcolors-core/contracts/wcag22-srgb8-v1.json", + "sha256": "b4bb7e5f17a99f2c911fdbe3da23a48b049277b796291094950f14680cc3cc7b" + }, + { + "path": "crates/labcolors-core/contracts/wcag22-srgb8-q55-proof-v1.json", + "sha256": "d269e9de689009bb955788bf8762fce56680bf616fc0459b6526a367875a6a08" + }, + { + "path": "crates/labcolors-core/Cargo.toml", + "sha256": "a704ebe5db345b16866be848b38d7adc4990b68c9aaee4af8b75cbd5ecb7455a" + }, + { + "path": "Cargo.lock", + "sha256": "2bba351e22e0264fceb3ae9153bd2d7eb465b19d6051fc482a60314483b17e6d" + }, + { + "path": "crates/labcolors-core/benches/wcag22_feasibility_admission.rs", + "sha256": "695496a53642318c04d62522b2ecf366368b836c944595ef44f86fcb8665d3ac" + }, + { + "path": "scripts/check_wcag22_feasibility_benchmark.py", + "sha256": "332b067cd275f6f5ddd6fa879c3bf618440f4d7d8bb86180bf210df6990a6a9a" + } + ], + "profileLimits": { + "profileId": "compile-v1", + "rawRelations": 2047, + "rawAdjacentEntries": 2047, + "opaqueUtf8Bytes": 65536, + "canonicalRelations": 2047, + "applicableEdges": 2047, + "logicalAssessments": 524032, + "packedResultBytes": 65536 + }, + "scenarios": [ + { + "name": "minimum-evaluated", + "shape": { + "rawRelations": 1, + "rawAdjacentEntries": 1, + "opaqueUtf8Bytes": 2, + "canonicalRelations": 1, + "applicableRelations": 1, + "applicableEdges": 1 + }, + "expected": { + "terminal": "feasible", + "logicalAssessments": 256, + "packedResultBytes": 64, + "feasibleCandidates": 7 + }, + "observedIdentity": { + "terminal": "feasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "770f11c7b289f17427541399fa49f4e747a4e84d04a3689e3a7e8f0cea968ecc", + "evaluationIdSha256": "c2ff3ed8394f040a1e01ccf92c07442f8fb06f2e8fcb735412c8a4803a81c5db", + "logicalAssessments": 256, + "assessmentIteratorLen": 256, + "derivedPackedResultBytes": 64, + "feasibleCandidates": 7 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 37542, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 3560, + "endLiveBytes": 3624, + "peakLiveBytes": 3624, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 1, + "elapsedNs": 17667, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 3560, + "endLiveBytes": 3624, + "peakLiveBytes": 3624, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 2, + "elapsedNs": 17417, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 3560, + "endLiveBytes": 3624, + "peakLiveBytes": 3624, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 3, + "elapsedNs": 17541, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 3560, + "endLiveBytes": 3624, + "peakLiveBytes": 3624, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 4, + "elapsedNs": 17334, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 3560, + "endLiveBytes": 3624, + "peakLiveBytes": 3624, + "peakAdditionalLiveBytes": 64 + } + ] + }, + { + "name": "maximum-applicable-edges", + "shape": { + "rawRelations": 1, + "rawAdjacentEntries": 2047, + "opaqueUtf8Bytes": 19, + "canonicalRelations": 1, + "applicableRelations": 1, + "applicableEdges": 2047 + }, + "expected": { + "terminal": "infeasible", + "logicalAssessments": 524032, + "packedResultBytes": 65536, + "feasibleCandidates": 0 + }, + "observedIdentity": { + "terminal": "infeasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "3498263d9b09b28b10b0a76147bff13bef9844f44b4fe70a3585e6404efac947", + "evaluationIdSha256": "b6011501962a5f2eb55817d2ddab783f37d0eef036ace829bec2675511af394d", + "logicalAssessments": 524032, + "assessmentIteratorLen": 524032, + "derivedPackedResultBytes": 65536, + "feasibleCandidates": 0 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 13796209, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10115, + "endLiveBytes": 75651, + "peakLiveBytes": 75651, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 1, + "elapsedNs": 13889708, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10115, + "endLiveBytes": 75651, + "peakLiveBytes": 75651, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 2, + "elapsedNs": 13824125, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10115, + "endLiveBytes": 75651, + "peakLiveBytes": 75651, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 3, + "elapsedNs": 13649083, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10115, + "endLiveBytes": 75651, + "peakLiveBytes": 75651, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 4, + "elapsedNs": 13688084, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10115, + "endLiveBytes": 75651, + "peakLiveBytes": 75651, + "peakAdditionalLiveBytes": 65536 + } + ] + }, + { + "name": "maximum-raw-duplicate-relations", + "shape": { + "rawRelations": 2047, + "rawAdjacentEntries": 2047, + "opaqueUtf8Bytes": 26611, + "canonicalRelations": 1, + "applicableRelations": 1, + "applicableEdges": 1 + }, + "expected": { + "terminal": "feasible", + "logicalAssessments": 256, + "packedResultBytes": 64, + "feasibleCandidates": 7 + }, + "observedIdentity": { + "terminal": "feasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "2d8c3d7dce6f7caee600851331aabbd45692a0cb530f1d58f08afb6f0a9aacc2", + "evaluationIdSha256": "83fa34dd186f1692438b5594fcae93b5d10746891e7e400b62f063b4f459cc1a", + "logicalAssessments": 256, + "assessmentIteratorLen": 256, + "derivedPackedResultBytes": 64, + "feasibleCandidates": 7 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 135500, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 4092, + "deallocatedBytes": 14322, + "baselineLiveBytes": 166005, + "endLiveBytes": 151747, + "peakLiveBytes": 166005, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 1, + "elapsedNs": 134500, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 4092, + "deallocatedBytes": 14322, + "baselineLiveBytes": 166005, + "endLiveBytes": 151747, + "peakLiveBytes": 166005, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 2, + "elapsedNs": 134542, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 4092, + "deallocatedBytes": 14322, + "baselineLiveBytes": 166005, + "endLiveBytes": 151747, + "peakLiveBytes": 166005, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 3, + "elapsedNs": 134375, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 4092, + "deallocatedBytes": 14322, + "baselineLiveBytes": 166005, + "endLiveBytes": 151747, + "peakLiveBytes": 166005, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 4, + "elapsedNs": 134583, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 4092, + "deallocatedBytes": 14322, + "baselineLiveBytes": 166005, + "endLiveBytes": 151747, + "peakLiveBytes": 166005, + "peakAdditionalLiveBytes": 0 + } + ] + }, + { + "name": "maximum-raw-adjacent-duplicates", + "shape": { + "rawRelations": 1, + "rawAdjacentEntries": 2047, + "opaqueUtf8Bytes": 2, + "canonicalRelations": 1, + "applicableRelations": 1, + "applicableEdges": 1 + }, + "expected": { + "terminal": "feasible", + "logicalAssessments": 256, + "packedResultBytes": 64, + "feasibleCandidates": 7 + }, + "observedIdentity": { + "terminal": "feasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "770f11c7b289f17427541399fa49f4e747a4e84d04a3689e3a7e8f0cea968ecc", + "evaluationIdSha256": "c2ff3ed8394f040a1e01ccf92c07442f8fb06f2e8fcb735412c8a4803a81c5db", + "logicalAssessments": 256, + "assessmentIteratorLen": 256, + "derivedPackedResultBytes": 64, + "feasibleCandidates": 7 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 30333, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10898, + "endLiveBytes": 10962, + "peakLiveBytes": 10962, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 1, + "elapsedNs": 30125, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10898, + "endLiveBytes": 10962, + "peakLiveBytes": 10962, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 2, + "elapsedNs": 30041, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10898, + "endLiveBytes": 10962, + "peakLiveBytes": 10962, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 3, + "elapsedNs": 30167, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10898, + "endLiveBytes": 10962, + "peakLiveBytes": 10962, + "peakAdditionalLiveBytes": 64 + }, + { + "index": 4, + "elapsedNs": 30125, + "allocationCalls": 1, + "allocatedBytes": 64, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 10898, + "endLiveBytes": 10962, + "peakLiveBytes": 10962, + "peakAdditionalLiveBytes": 64 + } + ] + }, + { + "name": "maximum-canonical-applicable-relations", + "shape": { + "rawRelations": 2047, + "rawAdjacentEntries": 2047, + "opaqueUtf8Bytes": 20470, + "canonicalRelations": 2047, + "applicableRelations": 2047, + "applicableEdges": 2047 + }, + "expected": { + "terminal": "feasible", + "logicalAssessments": 524032, + "packedResultBytes": 65536, + "feasibleCandidates": 7 + }, + "observedIdentity": { + "terminal": "feasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "2c034157301d1ebd68d207201ff4f18e38400a1bddea7824a77079a0ed96d41c", + "evaluationIdSha256": "db69a53550117574de7167b6f40dcfb8e213f5710dcd6ef16d6487259bd6bdc5", + "logicalAssessments": 524032, + "assessmentIteratorLen": 524032, + "derivedPackedResultBytes": 65536, + "feasibleCandidates": 7 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 15120708, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 224089, + "endLiveBytes": 289625, + "peakLiveBytes": 289625, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 1, + "elapsedNs": 15100959, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 224089, + "endLiveBytes": 289625, + "peakLiveBytes": 289625, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 2, + "elapsedNs": 17449917, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 224089, + "endLiveBytes": 289625, + "peakLiveBytes": 289625, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 3, + "elapsedNs": 15557959, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 224089, + "endLiveBytes": 289625, + "peakLiveBytes": 289625, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 4, + "elapsedNs": 15425000, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 224089, + "endLiveBytes": 289625, + "peakLiveBytes": 289625, + "peakAdditionalLiveBytes": 65536 + } + ] + }, + { + "name": "maximum-combined-applicable-envelope", + "shape": { + "rawRelations": 2047, + "rawAdjacentEntries": 2047, + "opaqueUtf8Bytes": 65536, + "canonicalRelations": 2047, + "applicableRelations": 2047, + "applicableEdges": 2047 + }, + "expected": { + "terminal": "feasible", + "logicalAssessments": 524032, + "packedResultBytes": 65536, + "feasibleCandidates": 7 + }, + "observedIdentity": { + "terminal": "feasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "647fbd1e61b7b10a58a32f00c6f9f2c1fd4deca9e685e6f682f26ec792dc5a84", + "evaluationIdSha256": "1d71ce6dea709b3977c252e814d0981dfeda2d3d1c42e9c2a1ff60848b4c118a", + "logicalAssessments": 524032, + "assessmentIteratorLen": 524032, + "derivedPackedResultBytes": 65536, + "feasibleCandidates": 7 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 15231209, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 263414, + "endLiveBytes": 328950, + "peakLiveBytes": 328950, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 1, + "elapsedNs": 15124708, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 263414, + "endLiveBytes": 328950, + "peakLiveBytes": 328950, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 2, + "elapsedNs": 15261917, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 263414, + "endLiveBytes": 328950, + "peakLiveBytes": 328950, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 3, + "elapsedNs": 15595750, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 263414, + "endLiveBytes": 328950, + "peakLiveBytes": 328950, + "peakAdditionalLiveBytes": 65536 + }, + { + "index": 4, + "elapsedNs": 15671916, + "allocationCalls": 1, + "allocatedBytes": 65536, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 263414, + "endLiveBytes": 328950, + "peakLiveBytes": 328950, + "peakAdditionalLiveBytes": 65536 + } + ] + }, + { + "name": "maximum-canonical-not-applicable-relations", + "shape": { + "rawRelations": 2047, + "rawAdjacentEntries": 0, + "opaqueUtf8Bytes": 36846, + "canonicalRelations": 2047, + "applicableRelations": 0, + "applicableEdges": 0 + }, + "expected": { + "terminal": "not-evaluated", + "logicalAssessments": 0, + "packedResultBytes": 0, + "feasibleCandidates": null + }, + "observedIdentity": { + "terminal": "not-evaluated", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "7e5f031ce0c8ef68c6667d9ae05bcf9818d8d34b1095fdbbc2dd7bc8f8748089", + "evaluationIdSha256": null, + "logicalAssessments": 0, + "assessmentIteratorLen": 0, + "derivedPackedResultBytes": 0, + "feasibleCandidates": null + }, + "samples": [ + { + "index": 0, + "elapsedNs": 606208, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 235124, + "endLiveBytes": 235124, + "peakLiveBytes": 235124, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 1, + "elapsedNs": 605584, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 235124, + "endLiveBytes": 235124, + "peakLiveBytes": 235124, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 2, + "elapsedNs": 606000, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 235124, + "endLiveBytes": 235124, + "peakLiveBytes": 235124, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 3, + "elapsedNs": 606250, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 235124, + "endLiveBytes": 235124, + "peakLiveBytes": 235124, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 4, + "elapsedNs": 606000, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 235124, + "endLiveBytes": 235124, + "peakLiveBytes": 235124, + "peakAdditionalLiveBytes": 0 + } + ] + }, + { + "name": "maximum-combined-not-applicable-envelope", + "shape": { + "rawRelations": 2047, + "rawAdjacentEntries": 0, + "opaqueUtf8Bytes": 65536, + "canonicalRelations": 2047, + "applicableRelations": 0, + "applicableEdges": 0 + }, + "expected": { + "terminal": "not-evaluated", + "logicalAssessments": 0, + "packedResultBytes": 0, + "feasibleCandidates": null + }, + "observedIdentity": { + "terminal": "not-evaluated", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "68d40f750b9e1e7520290ce21a5077b5eb19d44308dd5c44076a080486182bc2", + "evaluationIdSha256": null, + "logicalAssessments": 0, + "assessmentIteratorLen": 0, + "derivedPackedResultBytes": 0, + "feasibleCandidates": null + }, + "samples": [ + { + "index": 0, + "elapsedNs": 812208, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 284652, + "endLiveBytes": 284652, + "peakLiveBytes": 284652, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 1, + "elapsedNs": 785833, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 284652, + "endLiveBytes": 284652, + "peakLiveBytes": 284652, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 2, + "elapsedNs": 792125, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 284652, + "endLiveBytes": 284652, + "peakLiveBytes": 284652, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 3, + "elapsedNs": 763666, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 284652, + "endLiveBytes": 284652, + "peakLiveBytes": 284652, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 4, + "elapsedNs": 768166, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 284652, + "endLiveBytes": 284652, + "peakLiveBytes": 284652, + "peakAdditionalLiveBytes": 0 + } + ] + }, + { + "name": "maximum-mixed-relations", + "shape": { + "rawRelations": 2047, + "rawAdjacentEntries": 1023, + "opaqueUtf8Bytes": 28662, + "canonicalRelations": 2047, + "applicableRelations": 1023, + "applicableEdges": 1023 + }, + "expected": { + "terminal": "feasible", + "logicalAssessments": 261888, + "packedResultBytes": 32768, + "feasibleCandidates": 7 + }, + "observedIdentity": { + "terminal": "feasible", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "dbe4493668b49a058babc3188b84fc40f321bfd80d8bef22ec9d63f775033eed", + "evaluationIdSha256": "ab188519042404430aa7e71b4766ebf3b64f22fd88cff7898e7bf7ae65b298c2", + "logicalAssessments": 261888, + "assessmentIteratorLen": 261888, + "derivedPackedResultBytes": 32768, + "feasibleCandidates": 7 + }, + "samples": [ + { + "index": 0, + "elapsedNs": 7912959, + "allocationCalls": 1, + "allocatedBytes": 32768, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 230809, + "endLiveBytes": 263577, + "peakLiveBytes": 263577, + "peakAdditionalLiveBytes": 32768 + }, + { + "index": 1, + "elapsedNs": 8426416, + "allocationCalls": 1, + "allocatedBytes": 32768, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 230809, + "endLiveBytes": 263577, + "peakLiveBytes": 263577, + "peakAdditionalLiveBytes": 32768 + }, + { + "index": 2, + "elapsedNs": 8246209, + "allocationCalls": 1, + "allocatedBytes": 32768, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 230809, + "endLiveBytes": 263577, + "peakLiveBytes": 263577, + "peakAdditionalLiveBytes": 32768 + }, + { + "index": 3, + "elapsedNs": 8087708, + "allocationCalls": 1, + "allocatedBytes": 32768, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 230809, + "endLiveBytes": 263577, + "peakLiveBytes": 263577, + "peakAdditionalLiveBytes": 32768 + }, + { + "index": 4, + "elapsedNs": 8162667, + "allocationCalls": 1, + "allocatedBytes": 32768, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 230809, + "endLiveBytes": 263577, + "peakLiveBytes": 263577, + "peakAdditionalLiveBytes": 32768 + } + ] + }, + { + "name": "maximum-opaque-utf8-bytes", + "shape": { + "rawRelations": 1, + "rawAdjacentEntries": 0, + "opaqueUtf8Bytes": 65536, + "canonicalRelations": 1, + "applicableRelations": 0, + "applicableEdges": 0 + }, + "expected": { + "terminal": "not-evaluated", + "logicalAssessments": 0, + "packedResultBytes": 0, + "feasibleCandidates": null + }, + "observedIdentity": { + "terminal": "not-evaluated", + "domainDigestSha256": "9634ac326979b23c2103ffcd92a2b890427ea8914a97b264b0c73409640f8466", + "relationSetDigestSha256": "d89fd489c0f419f8e6ef2ac97f164d2ee1b4b20dc961895da8061688aa24cc2c", + "evaluationIdSha256": null, + "logicalAssessments": 0, + "assessmentIteratorLen": 0, + "derivedPackedResultBytes": 0, + "feasibleCandidates": null + }, + "samples": [ + { + "index": 0, + "elapsedNs": 337250, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 72691, + "endLiveBytes": 72691, + "peakLiveBytes": 72691, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 1, + "elapsedNs": 334292, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 72691, + "endLiveBytes": 72691, + "peakLiveBytes": 72691, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 2, + "elapsedNs": 334542, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 72691, + "endLiveBytes": 72691, + "peakLiveBytes": 72691, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 3, + "elapsedNs": 334125, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 72691, + "endLiveBytes": 72691, + "peakLiveBytes": 72691, + "peakAdditionalLiveBytes": 0 + }, + { + "index": 4, + "elapsedNs": 329917, + "allocationCalls": 0, + "allocatedBytes": 0, + "deallocationCalls": 0, + "deallocatedBytes": 0, + "baselineLiveBytes": 72691, + "endLiveBytes": 72691, + "peakLiveBytes": 72691, + "peakAdditionalLiveBytes": 0 + } + ] + } + ] +} diff --git a/crates/labcolors-core/src/solve.rs b/crates/labcolors-core/src/solve.rs index f89d4af7..3307fa88 100644 --- a/crates/labcolors-core/src/solve.rs +++ b/crates/labcolors-core/src/solve.rs @@ -644,6 +644,8 @@ pub(crate) fn solve_in( .conformance() .min_ratio() .is_none_or(|floor_ratio| solved.wcag_ratio() + 1e-9 >= floor_ratio); + #[cfg(test)] + probe_log::record(solved.hex(), solved.lc()); Ok(Candidate { passes: perceptual_ok && legal_ok, lc: solved.lc(), @@ -895,6 +897,8 @@ pub(crate) fn solve_dj( let solved = finish(rgb, y_gov, bg_disp, false, vc)?; let rgb_quantised = srgb_from_hex(solved.hex()).map_err(Unreachable::InvalidInput)?; let achieved_dj = (jp_of_linear(rgb_quantised, vc) - jp_bg).abs(); + #[cfg(test)] + probe_log::record(solved.hex(), achieved_dj); Ok(DjCandidate { error: (achieved_dj - magnitude_dj).abs(), achieved_dj, @@ -1317,6 +1321,41 @@ pub(crate) fn bg_luma(rgb: [f64; 3], vc: &ViewingConditions) -> f64 { lpc::y_hk(j_hk, vc) } +/// Test-only examined-candidate log (#297 local-search truth): both local +/// searches (`solve`'s quantisation walk and `solve_dj`'s separation walk) +/// record every on-grid candidate they actually materialize, so tests can +/// prove a reported near-miss (`nearest` / degraded `achieved_dj`) is drawn +/// ONLY from this set — a local claim, never a global one. Compiled solely +/// under `cfg(test)`: shipped bytes carry none of this. +#[cfg(test)] +pub(crate) mod probe_log { + use std::cell::RefCell; + + thread_local! { + static EXAMINED: RefCell>> = const { RefCell::new(None) }; + } + + /// Begin recording examined candidates on this thread. + pub(crate) fn start() { + EXAMINED.with(|e| *e.borrow_mut() = Some(Vec::new())); + } + + /// Record one examined candidate: emitted hex + the measure the search + /// compares against its budget (`lc` for `solve`, `|dJ'|` for `solve_dj`). + pub(crate) fn record(hex: &str, measure: f64) { + EXAMINED.with(|e| { + if let Some(log) = e.borrow_mut().as_mut() { + log.push((hex.to_string(), measure)); + } + }); + } + + /// Stop recording and return the examined set (empty if never started). + pub(crate) fn take() -> Vec<(String, f64)> { + EXAMINED.with(|e| e.borrow_mut().take()).unwrap_or_default() + } +} + #[cfg(test)] mod tests { use super::*; @@ -2785,6 +2824,217 @@ mod tests { ); } + // ------------------------------------------------------------------ + // #297 local-search truth: инструментированные exact-candidate тесты. + // Оба локальных поиска пишут каждый материализованный on-grid кандидат в + // `probe_log` (только под cfg(test)); отчётные значения обязаны быть + // взяты ИЗ этого набора — «locality of report». Контрпримеры ниже убивают + // глобальное прочтение `QuantizationGap`/`nearest` и «nearest achievable». + // ------------------------------------------------------------------ + + /// Каждое отданное значение solve — из examined-набора; walk реально + /// стреляет на JND-полосе (анти-вакуум) и никогда не смотрит больше чем + /// 1 + NEIGHBOR_STEPS кандидатов (Floor::None ⇒ bisection не участвует). + #[test] + fn solve_reports_are_drawn_only_from_examined_candidates() { + let vc = ViewingConditions::srgb(); + let mut walk_fired = 0usize; + for (bg_hex, pol) in [("#FFFFFF", 1.0), ("#000000", -1.0)] { + let mut t = 7.30f64; + while t <= 7.60 + 1e-9 { + let target = t * pol; + let bg = BgInput::solid(bg_hex).unwrap(); + probe_log::start(); + let result = solve( + bg, + Contract::range(target, target), + Hue::deg(0.0), + ChromaPolicy::Neutral, + &vc, + Gamut::Srgb, + ); + let examined = probe_log::take(); + assert!( + examined.len() <= 1 + NEIGHBOR_STEPS as usize, + "{bg_hex} {target}: local search examined {} candidates — beyond seed+budget", + examined.len() + ); + if examined.len() > 1 { + walk_fired += 1; + } + match result { + Ok(s) => assert!( + examined.iter().any(|(h, m)| h == s.hex() && *m == s.lc()), + "{bg_hex} {target}: returned colour was never an examined candidate" + ), + // Аналитический отказ ДО квантования: ноль on-grid кандидатов — + // честно (сетка не при чём, мёртвая зона непрерывного ядра). + Err(Unreachable::BelowContrastFloor { .. }) => {} + Err(Unreachable::QuantizationGap { nearest, .. }) => assert!( + examined + .iter() + .any(|(_, m)| (m.abs() - nearest).abs() < 1e-12), + "{bg_hex} {target}: reported nearest is not an examined candidate" + ), + Err(other) => panic!("{bg_hex} {target}: unexpected {other:?}"), + } + t += 0.01; + } + } + assert!( + walk_fired >= 2, + "anti-vacuum: the neighbour walk must fire on the JND band; fired {walk_fired}" + ); + } + + /// Контрпример, убивающий глобальное прочтение `QuantizationGap`/`nearest`: + /// на реальной hex-сетке (distinct-шаги — настоящий `build_color`) с + /// синтетическим законом измерения walk (сид + 2 distinct-соседа) выносит + /// `QuantizationGap`, хотя ТРЕТИЙ distinct-шаг — первый, куда поиску + /// запрещено смотреть — проходит контракт внутри бюджета. `nearest` при + /// этом — ровно ближайший ИЗУЧЕННЫЙ (сид), не глобальный ближайший. + /// Публичной поверхностью этот вариант сегодня недостижим (см. интеграционную + /// характеризацию: класс вымер на solid-фонах), поэтому структурная правда + /// поиска пинится на его собственном шве. + #[test] + fn quantization_gap_wording_is_local_not_global_counterexample() { + let vc = ViewingConditions::srgb(); + let bg = BgInput::solid("#FFFFFF").unwrap(); + let target = 10.0; + let interval = bg.luma_interval(&vc).unwrap(); + let y_gov = interval.governing(target); + let bg_disp = bg.governing_display(target); + let hue = Hue::deg(0.0); + let cp = ChromaPolicy::Neutral; + + // Первые 4 distinct hex-узла по расписанию walk'а (шаг −0.001 от сида, + // полярность dark-on-light) — та же сетка, которую он реально посетит. + let l_start = 0.5; + let mut distinct: Vec<(f64, String)> = + vec![(l_start, hex_from_srgb(build_color(l_start, hue, cp)))]; + let mut l = l_start; + while distinct.len() < 4 { + l -= 0.001; + let hx = hex_from_srgb(build_color(l, hue, cp)); + if hx != distinct.last().unwrap().1 { + distinct.push((l, hx)); + } + } + // Синтетический закон измерения: сид ниже цели (проваливает пол), два + // разрешённых соседа перепрыгивают бюджет, третий — попадает в него. + let law = { + let table: Vec<(String, f64)> = distinct + .iter() + .map(|(_, h)| h.clone()) + .zip([8.8, 11.4, 11.8, 10.3]) + .collect(); + move |hex: &str| -> f64 { + table + .iter() + .find(|(h, _)| h == hex) + .map(|(_, lc)| *lc) + .unwrap_or(200.0) + } + }; + let evaluate = |l_ok: f64| -> Result { + let solved = finish(build_color(l_ok, hue, cp), y_gov, bg_disp, false, &vc)?; + let lc = law(solved.hex()); + Ok(Candidate { + passes: lc >= target, + lc, + solved, + }) + }; + + let start_lc = law(&distinct[0].1); + match solve_quantization_neighbor(l_start, target, hue, cp, start_lc, evaluate) { + Err(Unreachable::QuantizationGap { target: t, nearest }) => { + assert_eq!(t, target); + // `nearest` — ближайший ИЗУЧЕННЫЙ (сид, 8.8)… + assert!( + (nearest - 8.8).abs() < 1e-12, + "nearest {nearest} must be the closest EXAMINED candidate (8.8)" + ); + // …а первый же узел за бюджетом walk'а проходит контракт в бюджете: + // «no on-grid colour» — ложь, правда лишь «в локальном бюджете». + let beyond = evaluate(distinct[3].0).unwrap(); + assert!( + beyond.passes && beyond.error(target) <= QUANT_BUDGET, + "the 3rd distinct step must be a passing in-budget candidate" + ); + assert!( + beyond.error(target) < (nearest - target).abs(), + "the unexamined candidate is strictly closer than the reported nearest" + ); + } + other => panic!("expected QuantizationGap, got {other:?}"), + } + } + + /// Реальный (не синтетический) контрпример для «nearest achievable» в dJ': + /// dark-on-light цель 98.75 на белом. Сид квантуется в #000000 (dj=100.0, + /// err 1.25 > DJ_BUDGET); walk смотрит ТОЛЬКО от фона (к меньшему J'), где + /// distinct-соседей нет вовсе — весь examined-набор состоит из ОДНОГО цвета, + /// и деградация отдаёт его как «nearest achievable». Глобально же #010101 + /// (та же полярность, тот же policy-универсум серых) достигает 98.0964 — + /// строго ближе к цели, но лежит НАЗАД (к фону), куда walk не смотрит. + #[test] + fn dj_degraded_nearest_achievable_is_local_not_global() { + let vc = ViewingConditions::srgb(); + let bg = BgInput::solid("#FFFFFF").unwrap(); + let magnitude = 98.75; + probe_log::start(); + let dj = solve_dj( + &bg, + magnitude, + 1.0, + Hue::deg(0.0), + ChromaPolicy::Neutral, + &vc, + ) + .expect("far dark-on-light dJ' target degrades, not errs (закон 2 ADR-0002)"); + let examined = probe_log::take(); + + assert!( + dj.degraded, + "seed misses DJ_BUDGET and the wall stops the walk" + ); + assert_eq!(dj.solved.hex(), "#000000"); + // Отчёт — только из examined-набора (locality of report)… + assert!( + examined + .iter() + .any(|(h, m)| h == dj.solved.hex() && *m == dj.achieved_dj), + "reported nearest-achievable must be an examined candidate" + ); + // …и весь набор — один-единственный цвет: поиск не «перебрал все hex». + assert!( + !examined.is_empty() && examined.iter().all(|(h, _)| h == "#000000"), + "every examined candidate is the wall colour; got {examined:?}" + ); + + // Глобальная правда: #010101 строго ближе к запрошенной величине. + let bg_disp = bg.governing_display(1.0); + let jp_bg = jp_of_linear( + [ + srgb_gamma_inv(bg_disp[0]), + srgb_gamma_inv(bg_disp[1]), + srgb_gamma_inv(bg_disp[2]), + ], + &vc, + ); + let better_dj = (jp_of_linear(srgb_from_hex("#010101").unwrap(), &vc) - jp_bg).abs(); + assert!( + (better_dj - magnitude).abs() + 0.5 < (dj.achieved_dj - magnitude).abs(), + "#010101 (dj {better_dj:.4}) is strictly closer to {magnitude} than reported {:.4}", + dj.achieved_dj + ); + assert!( + !examined.iter().any(|(h, _)| h == "#010101"), + "the strictly-better on-grid candidate was never examined" + ); + } + #[test] #[ignore] fn _emit_resolve_set_golden() { @@ -2884,6 +3134,13 @@ mod exposure_locks { /// EXPOSURE: доля целевого диапазона, чья приёмка ближайшего узла флипает, пока /// бюджет ходит в +-50% полосе. Малая ⇒ дискретность сетки поглощает свип. + /// + /// УТВЕРЖДАЕМАЯ характеризация (#297: printed-only gates запрещены). Домен — + /// текущая 8-битная СЕРАЯ сетка читаемости (Lc на белом; J' серых), т.е. + /// ровно то, по чему ходят оба локальных поиска при Neutral-политике; числа + /// не несут перцептивной/универсальной претензии — это свойство именно этой + /// сетки и этих бюджетов. Точные счётчики детерминированы (фиксированные + /// сетки, фиксированный шаг свипа) и запинены: дрейф = осознанная правка. #[test] fn exposure_quant_and_dj_budgets() { let lc = grey_lc(); @@ -2908,10 +3165,15 @@ mod exposure_locks { td += 1; t += 0.05; } - eprintln!( - "EXPOSURE QUANT_BUDGET flip={:.2}% | DJ_BUDGET flip={:.2}%", - 100.0 * fq as f64 / tq as f64, - 100.0 * fd as f64 / td as f64 + assert_eq!( + (fq, tq), + (39, 2121), + "QUANT_BUDGET flip-share drifted: {fq}/{tq} (pinned 39/2121 = 1.84%)" + ); + assert_eq!( + (fd, td), + (31, 2001), + "DJ_BUDGET flip-share drifted: {fd}/{td} (pinned 31/2001 = 1.55%)" ); } } diff --git a/crates/labcolors-core/tests/solve_characterization.rs b/crates/labcolors-core/tests/solve_characterization.rs new file mode 100644 index 00000000..84a8501e --- /dev/null +++ b/crates/labcolors-core/tests/solve_characterization.rs @@ -0,0 +1,787 @@ +//! RED-характеризация легаси-солвера (#297) на текущем main. +//! +//! Фикстуры `contracts/solve-characterization-v1-{macos-aarch64,linux-x64}.json` +//! — неизменяемый вход миграции честных имён: записаны ДО любых переименований +//! и обязаны реплеиться бит-в-бит (f64 сравниваются по битам, не по значению) +//! после каждого шага миграции, каждая на своей канонической платформе. Слепой +//! rebaseline запрещён: любое расхождение — дефект PR, а не повод +//! перегенерировать эталон. +//! +//! Запись эталона текущей платформы (ровно один раз, на baseline): +//! `LABCOLORS_RECORD_SOLVE_CHARACTERIZATION=1 cargo test -p labcolors-core \ +//! --test solve_characterization -- --nocapture` + +use std::collections::BTreeMap; +use std::fmt::Write as _; + +use labcolors_core::{ + BgInput, ChromaPolicy, Contract, Floor, Gamut, Hue, SolveJob, Solved, Unreachable, + ViewingConditions, solve, solve_many, +}; + +/// Платформенные эталоны. Текущий релиз — `LegacyPlatformDependent` (#297/#292): +/// f64-корреляты CAM16→Oklab проходят через libm (atan2/cbrt), чьи последние +/// ulp расходятся между платформами, поэтому bit-for-bit фикстура пинится ПО +/// ПЛАТФОРМАМ. Обе зафиксированы и обязаны реплеиться бит-в-бит каждая на +/// своей: macos-aarch64 записана локальной канонической машиной; linux-x64 — +/// дословный вывод канонического CI-раннера (реплей PR #327), верифицированный +/// тем же ранером бит-в-бит. Их расхождение задокументировано и запинено тестом +/// `platform_fixtures_agree_except_documented_hue_ulp_drift` ниже — рост дрифта +/// за пределы экспоната = алярм, не «новая платформа шумит». +const FIXTURE_MACOS_AARCH64: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/contracts/solve-characterization-v1-macos-aarch64.json" +); +const FIXTURE_LINUX_X64: &str = concat!( + env!("CARGO_MANIFEST_DIR"), + "/contracts/solve-characterization-v1-linux-x64.json" +); + +/// Эталон текущей платформы. На незапиненной платформе — громкий отказ: +/// характеризация без записанного эталона не «пропускается», её нужно записать. +fn fixture_path() -> &'static str { + if cfg!(all(target_os = "macos", target_arch = "aarch64")) { + FIXTURE_MACOS_AARCH64 + } else if cfg!(all(target_os = "linux", target_arch = "x86_64")) { + FIXTURE_LINUX_X64 + } else { + panic!( + "no recorded solve-characterization fixture for this platform; \ + record one with LABCOLORS_RECORD_SOLVE_CHARACTERIZATION=1" + ); + } +} + +/// Битовое представление f64: точность «биты payload не меняются» из #297. +fn bits(value: f64) -> String { + format!("{:016x}", value.to_bits()) +} + +#[derive(Debug, Clone, Copy)] +enum FloorSpec { + Default, + None, + AaUi, +} + +impl FloorSpec { + fn key(self) -> &'static str { + match self { + Self::Default => "default", + Self::None => "none", + Self::AaUi => "aa-ui", + } + } + + fn apply(self, contract: Contract) -> Contract { + match self { + Self::Default => contract, + Self::None => contract.with_conformance(Floor::None), + Self::AaUi => contract.with_conformance(Floor::AaUi), + } + } +} + +#[derive(Debug, Clone, Copy)] +enum ContractSpec { + Text(f64), + Ui(f64), + Range(f64, f64), +} + +impl ContractSpec { + fn key(self) -> String { + match self { + Self::Text(lc) => format!("text({lc})"), + Self::Ui(lc) => format!("ui({lc})"), + Self::Range(floor, ceiling) => format!("range({floor},{ceiling})"), + } + } + + fn build(self) -> Contract { + match self { + Self::Text(lc) => Contract::text(lc), + Self::Ui(lc) => Contract::ui(lc), + Self::Range(floor, ceiling) => Contract::range(floor, ceiling), + } + } +} + +struct CaseSpec { + bg: &'static str, + contract: ContractSpec, + floor: FloorSpec, + hue: f64, + chroma: ChromaPolicy, +} + +/// Невакуумная матрица: оба знака полярности, floored/non-floored успехи и +/// каждый достижимый класс ошибки. Полоса |Lc| ∈ (7.3, 7.6) — территория +/// квантизационных гэпов (см. `solve.rs` band-scan тест). +fn matrix() -> Vec { + let mut cases = Vec::new(); + let backgrounds = ["#FFFFFF", "#000000", "#767676", "#101012", "#007AFF"]; + let text_targets = [30.0, 60.0, 75.0, 90.0, 150.0, -30.0, -60.0, -75.0, -90.0]; + for bg in backgrounds { + for target in text_targets { + cases.push(CaseSpec { + bg, + contract: ContractSpec::Text(target), + floor: FloorSpec::Default, + hue: 264.0, + chroma: ChromaPolicy::Neutral, + }); + } + } + // Квантизационная полоса: мелкий шаг у нижней границы читаемости. + let mut t = 7.30_f64; + while t <= 7.60 + 1e-9 { + cases.push(CaseSpec { + bg: "#FFFFFF", + contract: ContractSpec::Text(t), + floor: FloorSpec::None, + hue: 0.0, + chroma: ChromaPolicy::Neutral, + }); + cases.push(CaseSpec { + bg: "#000000", + contract: ContractSpec::Text(-t), + floor: FloorSpec::None, + hue: 0.0, + chroma: ChromaPolicy::Neutral, + }); + t += 0.05; + } + // Средне-серые фоны: территория FloorUnreachable для dark-on-light AA. + for bg in ["#6E6E6E", "#7A7A7A", "#828282"] { + for target in [20.0, 35.0, 45.0] { + cases.push(CaseSpec { + bg, + contract: ContractSpec::Text(target), + floor: FloorSpec::Default, + hue: 145.0, + chroma: ChromaPolicy::Relative(0.35), + }); + } + } + // UI и range контракты, обе полярности, вариации floor-спеки. + for (bg, target) in [("#FFFFFF", 45.0), ("#101012", -45.0)] { + cases.push(CaseSpec { + bg, + contract: ContractSpec::Ui(target), + floor: FloorSpec::Default, + hue: 30.0, + chroma: ChromaPolicy::Relative(0.6), + }); + cases.push(CaseSpec { + bg, + contract: ContractSpec::Ui(target), + floor: FloorSpec::AaUi, + hue: 30.0, + chroma: ChromaPolicy::Neutral, + }); + } + for (bg, floor, ceiling) in [("#FFFFFF", 12.0, 20.0), ("#000000", -20.0, -12.0)] { + cases.push(CaseSpec { + bg, + contract: ContractSpec::Range(floor, ceiling), + floor: FloorSpec::Default, + hue: 200.0, + chroma: ChromaPolicy::Relative(0.2), + }); + } + // Заведомо мёртвая зона и невалидный вход. + cases.push(CaseSpec { + bg: "#FFFFFF", + contract: ContractSpec::Text(3.0), + floor: FloorSpec::None, + hue: 0.0, + chroma: ChromaPolicy::Neutral, + }); + cases.push(CaseSpec { + bg: "not-a-color", + contract: ContractSpec::Text(60.0), + floor: FloorSpec::Default, + hue: 0.0, + chroma: ChromaPolicy::Neutral, + }); + cases +} + +fn chroma_key(policy: ChromaPolicy) -> String { + match policy { + ChromaPolicy::Neutral => "neutral".to_string(), + ChromaPolicy::Relative(fraction) => format!("relative({fraction})"), + } +} + +fn case_key(case: &CaseSpec) -> String { + format!( + "bg={} contract={} floor={} hue={} chroma={}", + case.bg, + case.contract.key(), + case.floor.key(), + case.hue, + chroma_key(case.chroma), + ) +} + +/// Точная сериализация исхода: hex-байты + битовые f64 + все поля ошибок. +fn outcome_line(result: &Result) -> String { + match result { + Ok(solved) => format!( + "ok hex={} lc_bits={} wcag_ratio_bits={} floor_override={} jp_bits={} h_ok_bits={} s_bits={}", + solved.hex(), + bits(solved.lc()), + bits(solved.wcag_ratio()), + solved.floor_override(), + bits(solved.color().jp), + bits(solved.color().h_ok), + bits(solved.color().s), + ), + Err(Unreachable::BelowContrastFloor { target }) => { + format!("err below_contrast_floor target_bits={}", bits(*target)) + } + Err(Unreachable::ExceedsRange { + target, + max_achievable, + }) => format!( + "err exceeds_range target_bits={} max_achievable_bits={}", + bits(*target), + bits(*max_achievable) + ), + Err(Unreachable::QuantizationGap { target, nearest }) => format!( + "err quantization_gap target_bits={} nearest_bits={}", + bits(*target), + bits(*nearest) + ), + Err(Unreachable::FloorUnreachable { floor, max_ratio }) => format!( + "err floor_unreachable floor_bits={} max_ratio_bits={}", + bits(*floor), + bits(*max_ratio) + ), + Err(Unreachable::PolarityMismatch { target }) => { + format!("err polarity_mismatch target_bits={}", bits(*target)) + } + Err(Unreachable::GamutUnsupported) => "err gamut_unsupported".to_string(), + Err(Unreachable::InvalidInput(message)) => { + format!("err invalid_input message={message:?}") + } + Err(Unreachable::InternalInvariant(message)) => { + format!("err internal_invariant message={message:?}") + } + Err(other) => format!("err unknown {other:?}"), + } +} + +fn run_case(case: &CaseSpec) -> Result { + let bg = BgInput::solid(case.bg)?; + solve( + bg, + case.floor.apply(case.contract.build()), + Hue::deg(case.hue), + case.chroma, + &ViewingConditions::srgb(), + Gamut::Srgb, + ) +} + +fn observed_map() -> BTreeMap { + let mut observed = BTreeMap::new(); + // Одна GamutUnsupported-строка поверх матрицы (у solve это внешний гейт). + let gamut_case = solve( + BgInput::solid("#FFFFFF").expect("literal background"), + Contract::text(60.0), + Hue::deg(0.0), + ChromaPolicy::Neutral, + &ViewingConditions::srgb(), + Gamut::DisplayP3, + ); + observed.insert( + "bg=#FFFFFF contract=text(60) floor=default hue=0 chroma=neutral gamut=display-p3" + .to_string(), + outcome_line(&gamut_case), + ); + for case in matrix() { + let previous = observed.insert(case_key(&case), outcome_line(&run_case(&case))); + assert!( + previous.is_none(), + "duplicate case key: {}", + case_key(&case) + ); + } + observed +} + +fn render(observed: &BTreeMap) -> String { + let mut out = String::from("{\n"); + let mut first = true; + for (key, value) in observed { + if !first { + out.push_str(",\n"); + } + first = false; + write!(out, " {}: {}", json_string(key), json_string(value)).unwrap(); + } + out.push_str("\n}\n"); + out +} + +fn json_string(value: &str) -> String { + let mut out = String::with_capacity(value.len() + 2); + out.push('"'); + for ch in value.chars() { + match ch { + '"' => out.push_str("\\\""), + '\\' => out.push_str("\\\\"), + control if (control as u32) < 0x20 => write!(out, "\\u{:04x}", control as u32).unwrap(), + other => out.push(other), + } + } + out.push('"'); + out +} + +#[test] +fn fixture_replays_bit_for_bit() { + let observed = observed_map(); + let rendered = render(&observed); + let fixture = fixture_path(); + if std::env::var_os("LABCOLORS_RECORD_SOLVE_CHARACTERIZATION").is_some() { + // Дисциплина append-only рекордера (как у admission/whole-call): + // перезапись закоммиченного эталона — только осознанным `rm` заранее, + // и recorder-ран НИКОГДА не зелёный, чтобы случайный запуск с env-var + // не мог превратить численный регресс в прошедший тест. + assert!( + !std::path::Path::new(fixture).exists(), + "refusing to overwrite the committed fixture {fixture}; \ + rebaseline must be a deliberate act — delete the file first" + ); + std::fs::write(fixture, &rendered).expect("fixture written"); + panic!( + "solve characterization recorded: {} cases -> {fixture}; \ + recording runs never pass — rerun without \ + LABCOLORS_RECORD_SOLVE_CHARACTERIZATION to verify the replay", + observed.len() + ); + } + let committed = + std::fs::read_to_string(fixture).expect("committed solve characterization fixture exists"); + assert_eq!( + rendered, committed, + "solve characterization drifted from the immutable baseline; \ + a rename migration must not change bytes, payload bits or terminals" + ); +} + +/// Анти-вакуум: матрица обязана населять оба знака, floored/non-floored успехи +/// и каждый достижимый класс ошибки; PolarityMismatch задокументирован как +/// defensively-unreachable и обязан оставаться нулевым. +#[test] +fn characterization_counters_are_non_vacuous() { + let observed = observed_map(); + let mut successes = 0_usize; + let mut floored = 0_usize; + let mut unfloored = 0_usize; + let mut positive = 0_usize; + let mut negative = 0_usize; + let mut class_counts: BTreeMap<&'static str, usize> = BTreeMap::new(); + for (key, line) in &observed { + if line.starts_with("ok ") { + successes += 1; + if line.contains("floor_override=true") { + floored += 1; + } else { + unfloored += 1; + } + if key.contains("contract=text(-") + || key.contains("contract=ui(-") + || key.contains("contract=range(-") + { + negative += 1; + } else { + positive += 1; + } + } else { + let class = line + .strip_prefix("err ") + .and_then(|rest| rest.split_whitespace().next()) + .expect("error line carries a class"); + let slot = match class { + "below_contrast_floor" => "below_contrast_floor", + "exceeds_range" => "exceeds_range", + "quantization_gap" => "quantization_gap", + "floor_unreachable" => "floor_unreachable", + "polarity_mismatch" => "polarity_mismatch", + "gamut_unsupported" => "gamut_unsupported", + "invalid_input" => "invalid_input", + "internal_invariant" => "internal_invariant", + other => panic!("unknown error class {other}"), + }; + *class_counts.entry(slot).or_default() += 1; + } + } + assert!(successes >= 10, "successes: {successes}"); + assert!(floored >= 2, "floored successes: {floored}"); + assert!(unfloored >= 2, "unfloored successes: {unfloored}"); + assert!(positive >= 3 && negative >= 3, "+{positive}/-{negative}"); + for class in [ + "below_contrast_floor", + "exceeds_range", + "floor_unreachable", + "gamut_unsupported", + "invalid_input", + ] { + assert!( + class_counts.get(class).copied().unwrap_or(0) >= 1, + "error class {class} is not populated; counts: {class_counts:?}" + ); + } + // QuantizationGap на публичной поверхности ВЫМЕР. Структурно: допуск + // `meets_floor_lc` (−1 Lc) вместе с QUANT_BUDGET=1 даёт окно приёмки в + // 2 Lc, а same-polarity окна сетки шире 2 Lc существуют только вплотную к + // аналитическому клипу, где отказ принадлежит BelowContrastFloor ЕЩЁ ДО + // квантования; walk в 2 distinct-шага пересекает всё остальное (фикс #44). + // Эмпирически: сканы публичного API на миллионы вызовов (solid-фоны обеих + // полярностей, серые и хроматические, hue-сетка, Neutral/Relative вплоть до + // 1.0, Floor::None/AaText/AaUi, |Lc| 7.3..112, srgb и dim surround; wide + // gamut не участвует — DisplayP3 умирает на внешнем гейте) не производят + // ни одного. Правда самого варианта (`nearest` локален, не глобален) + // запинена на его собственном шве: + // `solve::tests::quantization_gap_wording_is_local_not_global_counterexample`. + // Появление гэпа из этой матрицы = изменение поведения поиска, не «новый кейс». + assert_eq!( + class_counts.get("quantization_gap").copied().unwrap_or(0), + 0, + "QuantizationGap is characterized as publicly extinct on this matrix" + ); + assert_eq!( + class_counts.get("polarity_mismatch").copied().unwrap_or(0), + 0, + "PolarityMismatch is documented as defensively unreachable" + ); + assert_eq!( + class_counts.get("internal_invariant").copied().unwrap_or(0), + 0, + "characterization inputs must not trip internal invariants" + ); +} + +/// `solve_many(bg, jobs) == jobs.map(solve)` позиционно: успехи, каждый класс +/// per-job ошибки, пустой вход, дубликаты и смешанные валидные/невалидные +/// задания; внешняя gamut-ошибка остаётся внешней и не сдвигает позиции. +#[test] +fn solve_many_is_positionally_identical_to_sequential_solve() { + let vc = ViewingConditions::srgb(); + let job = |contract: Contract, hue: f64, chroma: ChromaPolicy| SolveJob { + contract, + hue: Hue::deg(hue), + chroma_policy: chroma, + }; + let jobs = vec![ + job(Contract::text(60.0), 264.0, ChromaPolicy::Neutral), + job(Contract::text(150.0), 0.0, ChromaPolicy::Neutral), + job( + Contract::text(7.45).with_conformance(Floor::None), + 0.0, + ChromaPolicy::Neutral, + ), + job( + Contract::text(3.0).with_conformance(Floor::None), + 0.0, + ChromaPolicy::Neutral, + ), + job(Contract::ui(45.0), 30.0, ChromaPolicy::Relative(0.6)), + // Дубликат первого задания: позиционность, не дедупликация. + job(Contract::text(60.0), 264.0, ChromaPolicy::Neutral), + job( + Contract::range(12.0, 20.0), + 200.0, + ChromaPolicy::Relative(0.2), + ), + // Смешанный batch: невалидное per-job задание (chroma-ratio вне [0,1]) + // между валидными — обязано стать позиционным Err, не сдвинуть соседей + // и не уронить партию (требование #297 «mixed valid/invalid jobs»). + job(Contract::text(60.0), 264.0, ChromaPolicy::Relative(-0.25)), + job(Contract::text(45.0), 90.0, ChromaPolicy::Relative(0.3)), + ]; + let bg = BgInput::solid("#FFFFFF").expect("literal background"); + let batch = solve_many(bg, &jobs, &vc, Gamut::Srgb).expect("batch runs"); + assert_eq!(batch.len(), jobs.len()); + + let mut ok = 0_usize; + let mut err_classes: BTreeMap = BTreeMap::new(); + for (index, job) in jobs.iter().enumerate() { + let bg = BgInput::solid("#FFFFFF").expect("literal background"); + let sequential = solve( + bg, + job.contract, + job.hue, + job.chroma_policy, + &vc, + Gamut::Srgb, + ); + assert_eq!( + outcome_line(&batch[index]), + outcome_line(&sequential), + "position {index} diverged" + ); + match &batch[index] { + Ok(_) => ok += 1, + Err(error) => { + let line = outcome_line(&Err::(error.clone())); + let class = line + .strip_prefix("err ") + .and_then(|rest| rest.split_whitespace().next()) + .expect("class") + .to_string(); + *err_classes.entry(class).or_default() += 1; + } + } + } + // Анти-вакуум партии: успехи, дубликат успеха и ≥3 разных класса per-job + // ошибок (включая invalid_input от смешанного задания); партия целиком из + // Err пройти не может. + assert!(ok >= 4, "batch successes: {ok}"); + assert!( + err_classes.len() >= 3, + "batch must exercise several per-job error classes: {err_classes:?}" + ); + assert!( + err_classes.contains_key("invalid_input"), + "the mixed batch must carry a positional invalid job: {err_classes:?}" + ); + assert_eq!( + outcome_line(&batch[0]), + outcome_line(&batch[5]), + "duplicate jobs" + ); + assert!( + batch[7].is_err() && batch[8].is_ok(), + "the invalid job must not shift or poison its valid neighbour" + ); + + // Отдельная партия на средне-сером #6E6E6E: dark-on-light AA-text там + // математически не достигает 4.5:1 (потолок ~4.14), поэтому per-job + // FloorUnreachable обязан быть позиционным исходом и совпадать с + // последовательным solve. + let grey_jobs = vec![ + job(Contract::text(20.0), 145.0, ChromaPolicy::Neutral), + job( + Contract::text(9.0).with_conformance(Floor::None), + 0.0, + ChromaPolicy::Neutral, + ), + ]; + let grey_bg = BgInput::solid("#6E6E6E").expect("literal background"); + let grey_batch = solve_many(grey_bg, &grey_jobs, &vc, Gamut::Srgb).expect("batch runs"); + for (index, grey_job) in grey_jobs.iter().enumerate() { + let bg = BgInput::solid("#6E6E6E").expect("literal background"); + let sequential = solve( + bg, + grey_job.contract, + grey_job.hue, + grey_job.chroma_policy, + &vc, + Gamut::Srgb, + ); + assert_eq!( + outcome_line(&grey_batch[index]), + outcome_line(&sequential), + "grey position {index} diverged" + ); + } + assert!( + outcome_line(&grey_batch[0]).starts_with("err floor_unreachable"), + "mid-grey AA-text job must be a positional FloorUnreachable: {}", + outcome_line(&grey_batch[0]) + ); + assert!(grey_batch[1].is_ok(), "the floorless grey job must resolve"); + + // Пустой вход — пустой результат. + let bg = BgInput::solid("#FFFFFF").expect("literal background"); + assert!( + solve_many(bg, &[], &vc, Gamut::Srgb) + .expect("empty batch") + .is_empty() + ); + + // Внешняя ошибка гамута — внешняя: Err всей партии, позиций нет. + let bg = BgInput::solid("#FFFFFF").expect("literal background"); + assert!(matches!( + solve_many(bg, &jobs, &vc, Gamut::DisplayP3), + Err(Unreachable::GamutUnsupported) + )); +} + +/// Позитивная характеризация JND-полосы против `recheck_against` — публичного +/// пути перемера, которым адаптивный рантайм проверяет цвета каждый кадр. Это +/// независимый ПУТЬ (другой вход, другая горячая экономия), но та же +/// измерительная сердцевина `lpc::contrast_core` — тест пинит согласованность +/// оси читаемости между solve и recheck, не независимый вывод самой метрики. +/// Пинится наблюдаемый контракт локального поиска: +/// +/// 1. полоса в основном разрешается (анти-вакуум: all-Err пройти не может); +/// 2. каждый разрешённый цвет попадает в симметричный бюджет ±1 Lc; +/// 3. репортуемый `lc` бит-в-бит равен независимому перемеру того же hex — +/// измерительная честность: `finish` и `recheck_against` читают одну ось; +/// 4. приёмка ТОЛЕРАНТНА: существуют разрешённые случаи, где достигнутый `lc` +/// строго НЕ дотягивает до цели (в пределах нижнего допуска бюджета) — то +/// есть «решено» на этой поверхности значит «в допуске», а не «на-или-за +/// целью». Это зафиксированное текущее поведение, которое честные имена +/// #297 обязаны проговорить, а не спрятать. +/// +/// Ни один вход полосы не смеет выносить QuantizationGap (публичное вымирание — +/// см. counters-тест); правда о локальности `nearest`/«nearest achievable» +/// запинена контрпримерами на шве поиска (unit-тесты solve.rs: +/// `quantization_gap_wording_is_local_not_global_counterexample`, +/// `dj_degraded_nearest_achievable_is_local_not_global`). +#[test] +fn jnd_band_resolves_within_budget_with_tolerant_acceptance() { + let vc = ViewingConditions::srgb(); + let mut tolerated_undershoot = 0_usize; + for (bg_hex, pol) in [("#FFFFFF", 1.0_f64), ("#000000", -1.0_f64)] { + let mut resolved = 0_usize; + let mut t = 7.30_f64; + while t <= 7.60 + 1e-9 { + let target = t * pol; + let bg = BgInput::solid(bg_hex).expect("literal background"); + let result = solve( + bg, + Contract::text(target).with_conformance(Floor::None), + Hue::deg(0.0), + ChromaPolicy::Neutral, + &vc, + Gamut::Srgb, + ); + match result { + Ok(solved) => { + resolved += 1; + assert!( + (solved.lc() - target).abs() <= 1.0 + 1e-12, + "{bg_hex} {target}: resolved lc {} escapes the ±1 budget", + solved.lc() + ); + let remeasured = labcolors_core::recheck_against(bg_hex, &[solved.hex()], &vc) + .expect("emitted hex rechecks"); + assert_eq!( + bits(solved.lc()), + bits(remeasured[0].0), + "{bg_hex} {target}: reported lc diverges from the independent \ + re-measurement of the same hex" + ); + let undershoots = if pol >= 0.0 { + solved.lc() < target + } else { + solved.lc() > target + }; + if undershoots { + tolerated_undershoot += 1; + } + } + Err(Unreachable::BelowContrastFloor { .. }) => {} + Err(other) => panic!( + "{bg_hex} {target}: band may refuse only via the analytic dead \ + zone; got {other:?}" + ), + } + t += 0.01; + } + assert!( + resolved >= 20, + "anti-vacuum: the JND band on {bg_hex} must mostly resolve; got {resolved}" + ); + } + // Толерантная нижняя приёмка обязана реально стрелять хотя бы на одном + // фоне полосы (сегодня — на #000000: цель −7.36 принимает #323232 с + // lc −7.3502, недолёт 0.0098 внутри допуска). + assert!( + tolerated_undershoot >= 1, + "anti-vacuum: the tolerant lower acceptance never fired on the band" + ); +} + +/// Экспонат платформенной зависимости текущего релиза (#297 «current path is +/// LegacyPlatformDependent»): между канонической macOS-arm64 и каноническим +/// Linux-x64 расходится РОВНО хвост ulp одного поля — Oklab-hue коррелята +/// `h_ok` — в трёх кейсах матрицы. Всё остальное (hex-байты, `lc`, +/// `wcag_ratio`, `floor_override`, `jp`, `s`, все payload'ы ошибок) — +/// бит-идентично на всех 77 кейсах. Два кейса — честная libm-разница +/// (atan2/cbrt, 5 ulp на хроматике); третий — ахроматический результат, где +/// hue вырожден (atan2 шума о шум) и платформенный шум усиливается до +/// величины ~1e-8 при том же значении в градусах. Рост этого множества — +/// изменение численного поведения, а не «шум новой платформы». +#[test] +fn platform_fixtures_agree_except_documented_hue_ulp_drift() { + let load = |path: &str| -> BTreeMap { + let text = std::fs::read_to_string(path).expect("committed fixture exists"); + let mut out = BTreeMap::new(); + for line in text.lines() { + let Some(rest) = line.trim().strip_prefix('"') else { + continue; + }; + let Some((key, value_part)) = rest.split_once("\": \"") else { + continue; + }; + let value = value_part + .trim_end_matches(',') + .trim_end_matches('"') + .to_string(); + out.insert(key.to_string(), value); + } + out + }; + let mac = load(FIXTURE_MACOS_AARCH64); + let linux = load(FIXTURE_LINUX_X64); + assert_eq!(mac.len(), 77, "macOS fixture cardinality"); + assert_eq!( + mac.keys().collect::>(), + linux.keys().collect::>(), + "the two platform fixtures must pin the same case matrix" + ); + + let mut drifted: Vec<(String, Vec)> = Vec::new(); + for (key, mac_line) in &mac { + let linux_line = &linux[key]; + if mac_line == linux_line { + continue; + } + let fields = |line: &str| -> BTreeMap { + line.strip_prefix("ok ") + .unwrap_or(line) + .split_whitespace() + .filter_map(|pair| pair.split_once('=')) + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect() + }; + let mf = fields(mac_line); + let lf = fields(linux_line); + let differing: Vec = mf + .iter() + .filter(|(k, v)| lf.get(*k) != Some(v)) + .map(|(k, _)| k.clone()) + .collect(); + drifted.push((key.clone(), differing)); + } + drifted.sort(); + + let expected: Vec<(String, Vec)> = vec![ + ( + "bg=#7A7A7A contract=text(20) floor=default hue=145 chroma=relative(0.35)".to_string(), + vec!["h_ok_bits".to_string()], + ), + ( + "bg=#7A7A7A contract=text(35) floor=default hue=145 chroma=relative(0.35)".to_string(), + vec!["h_ok_bits".to_string()], + ), + ( + "bg=#FFFFFF contract=ui(45) floor=aa-ui hue=30 chroma=neutral".to_string(), + vec!["h_ok_bits".to_string()], + ), + ]; + assert_eq!( + drifted, expected, + "the cross-platform drift exhibit must stay exactly the documented \ + three h_ok ulp-tail cases" + ); +} diff --git a/packages/colors/test/release-contract.test.mjs b/packages/colors/test/release-contract.test.mjs index 67c06f36..2fcc662c 100644 --- a/packages/colors/test/release-contract.test.mjs +++ b/packages/colors/test/release-contract.test.mjs @@ -1432,7 +1432,7 @@ test("WCAG22 WASM role budgets are exact, append-only, and acyclic", async () => } }); -test("feasibility benchmark keeps V1-V3 history and admits exact V4 Core subjects", () => { +test("feasibility benchmark keeps V1-V5 history and admits exact V6 Core subjects", () => { const contractNames = readdirSync(join( root, "crates", @@ -1445,12 +1445,14 @@ test("feasibility benchmark keeps V1-V3 history and admits exact V4 Core subject "wcag22-feasibility-benchmark-v3.json", "wcag22-feasibility-benchmark-v4.json", "wcag22-feasibility-benchmark-v5.json", + "wcag22-feasibility-benchmark-v6.json", ]); const immutableArtifactHashes = new Map([ ["wcag22-feasibility-benchmark-v1.json", "7e9ffcbdd9d5d50fe681f511c34fc5c5dd270e9c475ce23ae56e9776922a3c5e"], ["wcag22-feasibility-benchmark-v2.json", "d8d5c7f3eda834bca9912d835fe3ada13d9dcd5a11cb47a131736716b0b51202"], ["wcag22-feasibility-benchmark-v3.json", "46ec939523a9aff4f253c4c74e997dfd95812a694b2507fae885ff60244ade3a"], ["wcag22-feasibility-benchmark-v4.json", "3c257c336bc403eee933990fd7188a3b0a6e89d0cbc983aff18846ef76206275"], + ["wcag22-feasibility-benchmark-v5.json", "6079612797bb28a9fc97c1451efd830e2323ed06e15fbffd70527dddc3fa84c5"], ]); for (const [name, expectedSha256] of immutableArtifactHashes) { const bytes = readFileSync(join( @@ -1477,14 +1479,14 @@ test("feasibility benchmark keeps V1-V3 history and admits exact V4 Core subject "crates", "labcolors-core", "contracts", - "wcag22-feasibility-benchmark-v5.json", + "wcag22-feasibility-benchmark-v6.json", )); const canonicalPayload = JSON.parse(canonicalArtifact.toString("utf8")); - const historicalV4Payload = JSON.parse(read( + const historicalV5Payload = JSON.parse(read( "crates", "labcolors-core", "contracts", - "wcag22-feasibility-benchmark-v4.json", + "wcag22-feasibility-benchmark-v5.json", )); const identityProjection = (payload) => ({ boundedEnvelopeModel: payload.boundedEnvelopeModel, @@ -1499,13 +1501,13 @@ test("feasibility benchmark keeps V1-V3 history and admits exact V4 Core subject }); assert.deepEqual( identityProjection(canonicalPayload), - identityProjection(historicalV4Payload), - "C2 may change provenance and observations, not the admitted finite algorithm", + identityProjection(historicalV5Payload), + "#297 characterization may change provenance and observations, not the admitted finite algorithm", ); const subjectsByPath = (payload) => new Map( payload.subjectManifest.map((subject) => [subject.path, subject.sha256]), ); - const historicalSubjects = subjectsByPath(historicalV4Payload); + const historicalSubjects = subjectsByPath(historicalV5Payload); const canonicalSubjects = subjectsByPath(canonicalPayload); const subjectPaths = [...new Set([ ...historicalSubjects.keys(), @@ -1516,23 +1518,22 @@ test("feasibility benchmark keeps V1-V3 history and admits exact V4 Core subject (path) => historicalSubjects.get(path) !== canonicalSubjects.get(path), ), [ - "crates/labcolors-core/Cargo.toml", "crates/labcolors-core/benches/wcag22_feasibility_admission.rs", - "crates/labcolors-core/src/wcag22_feasibility/explicit.rs", "scripts/check_wcag22_feasibility_benchmark.py", ], - "V5 source drift must be exactly the C2 explicit module, its test-target " + - "registration and admission machinery", + "V6 subject drift must be exactly the admission machinery identity bump; " + + "the #297 characterization touches solve.rs, which sits in the broad " + + "source cone (forcing this re-record) but is not an admission subject", ); assert.equal( "gitRevision" in canonicalPayload.environment, false, - "durable V5 must not claim an ephemeral measurement commit", + "durable V6 must not claim an ephemeral measurement commit", ); assert.equal( "gitTree" in canonicalPayload.environment, false, - "durable V5 must use its exact source-object cone as the provenance SSOT", + "durable V6 must use its exact source-object cone as the provenance SSOT", ); assert.deepEqual( canonicalPayload.environment.explicitEmptyBuildInputs, @@ -1707,18 +1708,23 @@ test("feasibility benchmark keeps V1-V3 history and admits exact V4 Core subject ); assert.match( ci, - /trap - EXIT[\s\S]*?current_artifact="crates\/labcolors-core\/contracts\/wcag22-feasibility-benchmark-v5\.json"[\s\S]*?current_protocol=\([\s\S]*?--admit-rustc-release 1\.96\.0[\s\S]*?--admit-cargo-release 1\.96\.0[\s\S]*?--admit-rustc-binary-sha256 c5922366bfe3d6d028a65d626f4e629b3adad066995cf0b60c8a4b617bba5ffe[\s\S]*?--admit-cargo-binary-sha256 fec239e6b74df873f54ef52912bfcfcc8d8414bc14a7ae1e0be80460bae72841[\s\S]*?--admit-benchmark-binary-sha256 bd8a6289cfc4605ffcba00b38c4e7309a6ee2989cbab8e76f03ed478e4fcff0a[\s\S]*?python3 scripts\/check_wcag22_feasibility_benchmark\.py[\s\S]*?--artifact-sha256 6079612797bb28a9fc97c1451efd830e2323ed06e15fbffd70527dddc3fa84c5[\s\S]*?--self-test/u, - "V5 must bind the current C2 source cone without an intermediate worktree", + /v5_artifact="crates\/labcolors-core\/contracts\/wcag22-feasibility-benchmark-v5\.json"[\s\S]*?v5_snapshot=9819bbd549ef2347eb133b948ccb5f7a3c5a51fe[\s\S]*?--admit-benchmark-binary-sha256 bd8a6289cfc4605ffcba00b38c4e7309a6ee2989cbab8e76f03ed478e4fcff0a[\s\S]*?git worktree add --detach "\$historical_root" "\$v5_snapshot"[\s\S]*?python3 scripts\/check_wcag22_feasibility_benchmark\.py[\s\S]*?--artifact-sha256 6079612797bb28a9fc97c1451efd830e2323ed06e15fbffd70527dddc3fa84c5[\s\S]*?--self-test/u, + "V5 must replay through the exact merged C2/C3 snapshot", + ); + assert.match( + ci, + /trap - EXIT[\s\S]*?current_artifact="crates\/labcolors-core\/contracts\/wcag22-feasibility-benchmark-v6\.json"[\s\S]*?current_protocol=\([\s\S]*?--admit-rustc-release 1\.96\.0[\s\S]*?--admit-cargo-release 1\.96\.0[\s\S]*?--admit-rustc-binary-sha256 c5922366bfe3d6d028a65d626f4e629b3adad066995cf0b60c8a4b617bba5ffe[\s\S]*?--admit-cargo-binary-sha256 fec239e6b74df873f54ef52912bfcfcc8d8414bc14a7ae1e0be80460bae72841[\s\S]*?--admit-benchmark-binary-sha256 1e43b4c8418b8f45da3614d9697966874943e034d4275ee2a404f95aa60dbd2a[\s\S]*?python3 scripts\/check_wcag22_feasibility_benchmark\.py[\s\S]*?--artifact-sha256 2e319643e582ca385f988af173b534cd9d1c921f36fcc929f1c56eb8bd978d24[\s\S]*?--self-test/u, + "V6 must bind the current #297 characterization source cone without an intermediate worktree", ); assert.equal( ci.match(/python3 scripts\/check_wcag22_feasibility_benchmark\.py/gu)?.length, - 5, - "CI must validate exactly four historical and one current benchmark artifact", + 6, + "CI must validate exactly five historical and one current benchmark artifact", ); assert.equal( ci.match(/git worktree add --detach/gu)?.length, - 5, - "only the five main-reachable historical verifier snapshots may use worktrees", + 6, + "only the six main-reachable historical verifier snapshots may use worktrees", ); }); diff --git a/scripts/check_wcag22_feasibility_benchmark.py b/scripts/check_wcag22_feasibility_benchmark.py index 6991aa72..0e6d3504 100644 --- a/scripts/check_wcag22_feasibility_benchmark.py +++ b/scripts/check_wcag22_feasibility_benchmark.py @@ -29,7 +29,7 @@ DEFAULT_ARTIFACT = Path( - "/private/tmp/labcolors-wcag22-feasibility-admission-raw-v5.json" + "/private/tmp/labcolors-wcag22-feasibility-admission-raw-v6.json" ) HEX_256 = re.compile(r"[0-9a-f]{64}") GIT_OBJECT = re.compile(r"[0-9a-f]{40}") @@ -911,7 +911,7 @@ def check( source_before = dependency_cone_snapshot() require(isinstance(payload, dict), "artifact root must be an object") require(payload.get("schemaVersion") == 1, "unsupported benchmark schemaVersion") - require(payload.get("artifactId") == "wcag22-feasibility-admission-raw-v5", + require(payload.get("artifactId") == "wcag22-feasibility-admission-raw-v6", "unexpected benchmark artifactId") require( payload.get("claimBoundary")