Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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 d40cd5b8d5d8db36d2d4092cdc1e96093225f0bc
--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 06f39178b3a5399edfe0a3b218c3e9abac8e080b0ede9cae45f6784cb5dc0bf6 \
--self-test
python3 scripts/check_wcag22_feasibility_applicability.py \
"$artifact" \
--artifact-sha256 7e9ffcbdd9d5d50fe681f511c34fc5c5dd270e9c475ce23ae56e9776922a3c5e \
"$current_artifact" \
--artifact-sha256 06f39178b3a5399edfe0a3b218c3e9abac8e080b0ede9cae45f6784cb5dc0bf6 \
--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` / `ba534f…9e53`). Каждый допуск имеет нулевой
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