Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cargo/mutants.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ examine_globs = [
"crates/labcolors-core/src/wcag22.rs",
"crates/labcolors-core/src/wcag22_evidence.rs",
"crates/labcolors-core/src/wcag22_feasibility.rs",
"crates/labcolors-core/src/wcag22_feasibility/explicit.rs",
"crates/labcolors-core/src/wcag22/kernel.rs",
]

Expand Down
70 changes: 56 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ jobs:
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- name: cargo test
run: cargo test --workspace --locked
- name: prove base-only Core capability is independently testable
run: |
cargo check -p labcolors-core --all-targets --no-default-features --features wcag22-feasibility --locked
cargo test -p labcolors-core --lib --no-default-features --features wcag22-feasibility --locked
cargo test -p labcolors-core --test wcag22_feasibility --no-default-features --features wcag22-feasibility --locked
cargo test -p labcolors-core --doc --no-default-features --features wcag22-feasibility --locked
- name: prove core capability projection boundary
shell: bash
run: |
Expand All @@ -241,7 +247,10 @@ jobs:
"labcolors-conformance",
)
core = packages["labcolors-core"]
if core["features"].get("default") != ["wcag22-feasibility"]:
if core["features"].get("default") != [
"wcag22-feasibility",
"wcag22-explicit-feasibility",
]:
raise SystemExit("labcolors-core default capability set drifted")

protocol_core = [
Expand Down Expand Up @@ -291,6 +300,10 @@ jobs:
raise SystemExit(
f"{consumer} did not resolve protocol-owned wcag22-feasibility"
)
if 'labcolors-core feature "wcag22-explicit-feasibility"' in feature_tree:
raise SystemExit(
f"{consumer} resolved the Core-only explicit-domain capability"
)

print("core capability projection: PASS")
PY
Expand All @@ -302,10 +315,12 @@ jobs:
run: python3 scripts/verify_wcag22_neutral_axis.py
- name: verify WCAG22 feasibility identity byte grammar
run: python3 scripts/verify_wcag22_feasibility_identity.py
- name: validate committed WCAG22 feasibility benchmark evidence
- name: verify explicit WCAG22 feasibility identity and anti-vacuum mutations
run: python3 scripts/verify_wcag22_explicit_feasibility_identity.py --self-test
- name: validate historical and current WCAG22 feasibility benchmark evidence
run: |
artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v1.json"
protocol=(
historical_artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v1.json"
historical_protocol=(
--admit-revision fea99a1ea4148a5a72423c88220655f7f84213fe
--admit-rustc-release 1.96.0
--admit-target-triple aarch64-apple-darwin
Expand All @@ -315,26 +330,53 @@ jobs:
--admit-package-version 0.2.0
--admit-sample-count 5
)
historical_snapshot=6001cf41e0a8364f25543e7955ceaf64d50129b4
historical_checker_snapshot=6001cf41e0a8364f25543e7955ceaf64d50129b4
historical_applicability_snapshot=94efeeeb1811f5515558ab2d79014a5e4c3a570a
historical_root="$RUNNER_TEMP/wcag22-feasibility-slice-a-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
git worktree add --detach "$historical_root" "$historical_snapshot"
git worktree add --detach "$historical_root" "$historical_checker_snapshot"
cleanup_history() {
git worktree remove --force "$historical_root"
}
trap cleanup_history EXIT
(
cd "$historical_root"
python3 scripts/check_wcag22_feasibility_benchmark.py \
"$artifact" "${protocol[@]}" \
"$historical_artifact" "${historical_protocol[@]}" \
--verify-current-subjects \
--artifact-sha256 7e9ffcbdd9d5d50fe681f511c34fc5c5dd270e9c475ce23ae56e9776922a3c5e \
--self-test
)
cleanup_history
git worktree add --detach "$historical_root" "$historical_applicability_snapshot"
(
cd "$historical_root"
python3 scripts/check_wcag22_feasibility_applicability.py \
"$historical_artifact" \
--artifact-sha256 7e9ffcbdd9d5d50fe681f511c34fc5c5dd270e9c475ce23ae56e9776922a3c5e \
--self-test
)
cleanup_history
trap - EXIT

current_artifact="crates/labcolors-core/contracts/wcag22-feasibility-benchmark-v2.json"
current_protocol=(
--admit-revision 554f462b44d6a2061c8791c861dc912bb444704f
--admit-rustc-release 1.96.0
--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[@]}" \
--verify-current-subjects \
--artifact-sha256 4168f2af137ab9001764e0957bab4912fb27ec79f15748fe614959861994150c \
--self-test
python3 scripts/check_wcag22_feasibility_applicability.py \
"$artifact" \
--artifact-sha256 7e9ffcbdd9d5d50fe681f511c34fc5c5dd270e9c475ce23ae56e9776922a3c5e \
"$current_artifact" \
--artifact-sha256 4168f2af137ab9001764e0957bab4912fb27ec79f15748fe614959861994150c \
--self-test

audit:
Expand Down Expand Up @@ -441,20 +483,20 @@ jobs:
node-version: ${{ env.NODE_TOOLCHAIN }}
cache: npm
cache-dependency-path: packages/colors/package-lock.json
- name: "verify committed #295 canonical whole-call WASM boundary evidence"
- name: "verify committed #296-A canonical whole-call WASM boundary evidence"
# The admitted JSON binds exact deterministic bytes/shapes and the
# reviewed Uint8Array package root to this built Linux x64 WASM. Fresh
# latency/maxRSS/pages remain observations only.
working-directory: packages/colors
run: >-
node bench/wcag22-feasibility-boundary.bench.mjs
--verify
- name: independently fingerprint the exact #295 WASM
- name: independently fingerprint the exact #296-A WASM
run: |
bytes="$(wc -c < packages/colors/pkg/labcolors_bg.wasm | tr -d '[:space:]')"
sha256="$(sha256sum packages/colors/pkg/labcolors_bg.wasm | cut -d ' ' -f1)"
echo "canonical candidate raw=${bytes}B sha256=${sha256}"
- name: "upload exact #295 verified whole-call evidence"
- name: "upload exact #296-A verified whole-call evidence"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: wcag22-feasibility-wasm-boundary-${{ github.sha }}-attempt-${{ github.run_attempt }}
Expand All @@ -464,8 +506,8 @@ jobs:
if-no-files-found: error
retention-days: 30
- name: enforce measured WASM raw-byte budget
# Issue #295 owns the current exact Linux x64 measurement and zero-headroom
# ceiling. Issue #284 remains the immutable V1 build-recipe/baseline input.
# Issue #296 owns the current exact Linux x64 measurement and zero-headroom
# ceiling. Issues #284/#295 remain immutable historical inputs.
# gzip is transport diagnostics only.
run: node scripts/check-wasm-size-budget.mjs
- name: "@labpics/colors: typecheck + runtime tests"
Expand Down
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Migration-note: [exact alpha / typed Glow](docs/migrations/exact-alpha-glow.md),
`[UInt8]`;
обе поверхности сохраняют `Success(Feasible | Infeasible | NotEvaluated)`
либо typed `Failure` и не воспроизводят математику Core.
- Rust Core принимает также непустой явный конечный набор пар «opaque ID +
финальный sRGB8», канонизирует точные UTF-8-байты ID и использует тот же
exhaustive kernel. Возможность включена в default Core, но не проецируется в
Protocol/WASM/FFI/npm/Swift.
- Conformance pack 5.0.0 добавляет ровно одно семейство
`wcag22-feasibility.json`: exact 7/2/0/92/59, mixed/all NotApplicable,
typed conflict/resource failures и opaque-ID law. Шесть прежних family
Expand Down Expand Up @@ -71,8 +75,9 @@ Migration-note: [exact alpha / typed Glow](docs/migrations/exact-alpha-glow.md),
`evidence/wcag22-srgb8-q55-proof-v1.json` не меняются: это отдельные version
domains, а доказанная математика и finite artifact прежние.
- WASM size history стала append-only: immutable V1 сохраняет допуск #284
(`454385 B`), а V2 допускает полный transport #295 как точные `521240 B` /
`d37841…9ca0` с нулевым headroom и ссылкой на неизменяемый V1 build recipe.
(`454385 B`), V2 — transport #295 (`521240 B` / `d37841…9ca0`), а V3 —
Core-срез #296-A (`521231 B` / `779379…e029`). Каждый допуск имеет нулевой
headroom и точную ссылку на неизменяемый V1 build recipe; V1/V2 не переписаны.
Canonical whole-call artifact фиксирует 10 крайних форм × 5 свежих процессов;
latency, process maxRSS и WASM pages остаются наблюдениями, не SLO.
- Conformance pack 4.0.0 добавил `wcag22.json`; pack 5.0.0 добавляет только
Expand Down
7 changes: 6 additions & 1 deletion crates/labcolors-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ rust-version.workspace = true
[features]
# Direct core consumers receive the stable default capability set. A transport
# adapter may disable defaults and then enable only capabilities it projects.
default = ["wcag22-feasibility"]
default = ["wcag22-feasibility", "wcag22-explicit-feasibility"]
wcag22-feasibility = []
wcag22-explicit-feasibility = ["wcag22-feasibility"]

[dev-dependencies]
pretty_assertions = "1.4"
Expand Down Expand Up @@ -61,3 +62,7 @@ required-features = ["wcag22-feasibility"]
[[test]]
name = "wcag22_feasibility"
required-features = ["wcag22-feasibility"]

[[test]]
name = "wcag22_explicit_feasibility"
required-features = ["wcag22-explicit-feasibility"]
87 changes: 72 additions & 15 deletions crates/labcolors-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,40 @@ details.
вхождения, применимый критерий WCAG 2.2 и точные соседние цвета sRGB8. Core
канонизирует декларации, вычисляет каждую пару «кандидат × сосед» и возвращает
один запечатанный терминал: `Feasible`, `Infeasible` либо декларационный
`NotEvaluated`. `Infeasible` означает отсутствие решения только в выбранном
зарегистрированном домене; это не утверждение об отсутствии цвета вне домена.

Возможность Cargo `wcag22-feasibility` включена по умолчанию для прямых
потребителей Core. Транспортные адаптеры отключают неэкспортируемые возможности
и включают каждую возможность вместе с её публичным транспортом и контрактом
соответствия.

В версии 1 зарегистрирована нейтральная ось кодированной sRGB8: ровно 256 кодов
`[v, v, v]`, где `v` принимает каждое целое значение от 0 до 255. Число 256 —
мощность исчерпывающе перечисляемого 8-битного домена, а не эмпирический порог.
Core не выводит размер текста, компонентную семантику или применимость из ID.
Превышение ресурсов, противоречивая декларация, ошибка выделения памяти и
нарушение инварианта вычислителя или компилятора возвращаются типизированными
ошибками; частичного или запасного результата нет.
`NotEvaluated`. `Infeasible` означает отсутствие решения только в проверенном
конечном домене; это не утверждение об отсутствии цвета вне него.

Прямой Core по умолчанию включает `wcag22-feasibility` и зависящую от неё
возможность `wcag22-explicit-feasibility`. Транспорты отключают default-features,
а Protocol/WASM/FFI в V1 проецируют только первую возможность с
зарегистрированной нейтральной осью. Поэтому явный клиентский набор остаётся
Core-only API и не попадает в транспортный артефакт; обе формы используют один
математический компилятор.

В V1 доступны две формы одного компилятора. Совместимый вход `evaluate`
перечисляет зарегистрированную нейтральную ось: ровно 256 кодов `[v, v, v]`,
где `v` принимает каждое целое значение от 0 до 255. Вход
`explicit::evaluate` принимает непустой клиентский набор пар «непрозрачный ID +
неизменяемый финальный `Srgb8`». Core сортирует точные UTF-8-байты ID, отклоняет
их повторы и сам выводит мощность, digest, матрицу и partition. Разные ID с
одинаковыми физическими байтами остаются разными кандидатами. Ни один из входов
не выводит размер текста, компонентную семантику, применимость или предпочтение
из ID; выбор среди допустимых кандидатов в этот контракт не входит.

Для `C` кандидатов и `E` канонических применимых рёбер выполняется ровно
`W=C×E` атомарных проверок. При `E>0` единственный упакованный буфер имеет
`B=ceil(C×E/8)+ceil(C/8)` байт; при `E=0` он пуст. Эти величины выводятся и
проверяются до выделения памяти. Остальная стоимость не маскируется формулой
`C×E`: отдельно выполняются линейный просмотр деклараций, сортировка кандидатов
и связей сравнением точных байтов ID, сортировка соседей внутри каждой связи и
линейное хеширование канонического результата. Превышение ресурсов,
противоречивая декларация, ошибка выделения памяти и нарушение инварианта
вычислителя или компилятора возвращаются типизированными ошибками; частичного
или запасного результата нет.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Полные проверки формул `C×E`, случая `E=0`, повторов ID, ресурсных отказов и
запрета частичного результата перечислены в разделе «Конечная компиляция
выполнимости WCAG 2.2» [карты верификации](../../docs/verification-map.md).

```rust
# #[cfg(feature = "wcag22-feasibility")]
Expand Down Expand Up @@ -93,6 +112,44 @@ if let Some(evaluated) = result.evaluated() {
# fn main() {}
```

Клиентский конечный набор использует те же `RelationV1` и атомарный WCAG-путь:

```rust
# #[cfg(feature = "wcag22-explicit-feasibility")]
# fn explicit_feasibility_example() -> Result<(), Box<dyn std::error::Error>> {
use labcolors_core::{
Srgb8,
wcag22::Wcag22CriterionV1,
wcag22_feasibility::{
OccurrenceId, RelationId, RelationV1, ResourceProfileIdV1,
explicit::{
CandidateId, CandidateV1, DomainRequestV1, RequestV1, evaluate,
},
},
};

let domain = DomainRequestV1::try_new(vec![
CandidateV1::new(CandidateId::try_new("brand/ink")?, Srgb8::new([18, 52, 86])),
CandidateV1::new(CandidateId::try_new("brand/paper")?, Srgb8::new([245, 247, 250])),
])?;
let relation = RelationV1::applicable(
RelationId::try_new("content-on-canvas")?,
OccurrenceId::try_new("article/body")?,
Wcag22CriterionV1::Sc143TextDefault,
vec![Srgb8::new([255; 3])],
)?;
let result = evaluate(RequestV1::try_new(
domain,
vec![relation],
ResourceProfileIdV1::Compile,
)?)?;

assert_eq!(result.evaluated().map(|value| value.candidates().len()), Some(2));
# Ok(())
# }
# fn main() {}
```

В примере `Sc143TextDefault` означает явно объявленный клиентом критерий
SC 1.4.3 для обычного текста с отношением 4.5:1; Core не угадывает его по ID или
типографике. `0x75` и `0x76` — вычисленные граничные результаты именно для двух
Expand Down
9 changes: 5 additions & 4 deletions crates/labcolors-core/benches/wcag22_feasibility_admission.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//!
//! ```text
//! LABCOLORS_WCAG22_BENCH_SAMPLES=5 \
//! LABCOLORS_WCAG22_BENCH_OUTPUT=/private/tmp/labcolors-wcag22-feasibility-admission-raw-v1.json \
//! LABCOLORS_WCAG22_BENCH_OUTPUT=/private/tmp/labcolors-wcag22-feasibility-admission-raw-v2.json \
//! cargo bench -p labcolors-core --bench wcag22_feasibility_admission
//! ```

Expand All @@ -39,8 +39,8 @@ use labcolors_core::wcag22_feasibility::{
#[path = "../src/sha256.rs"]
mod subject_sha256;

const ARTIFACT_ID: &str = "wcag22-feasibility-admission-raw-v1";
const DEFAULT_OUTPUT_FILENAME: &str = "labcolors-wcag22-feasibility-admission-raw-v1.json";
const ARTIFACT_ID: &str = "wcag22-feasibility-admission-raw-v2";
const DEFAULT_OUTPUT_FILENAME: &str = "labcolors-wcag22-feasibility-admission-raw-v2.json";
const CANDIDATE_COUNT: u64 = 256;
const PAGE_BYTES: u64 = 65_536;
const DECISION_SLOT_BYTES: u64 = 32;
Expand Down Expand Up @@ -71,10 +71,11 @@ const SOURCE_OBJECTS: [(&str, &str); 8] = [
"scripts/check_wcag22_feasibility_benchmark.py",
),
];
const SUBJECT_PATHS: [&str; 16] = [
const SUBJECT_PATHS: [&str; 17] = [
"Cargo.toml",
"crates/labcolors-core/src/lib.rs",
"crates/labcolors-core/src/wcag22_feasibility.rs",
"crates/labcolors-core/src/wcag22_feasibility/explicit.rs",
"crates/labcolors-core/src/srgb8.rs",
"crates/labcolors-core/src/sha256.rs",
"crates/labcolors-core/src/wcag22.rs",
Expand Down
Loading
Loading