Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions .cargo/mutants.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ examine_globs = [
"crates/labcolors-core/src/numerical_plan.rs",
"crates/labcolors-core/src/numerics.rs",
"crates/labcolors-core/src/pair.rs",
"crates/labcolors-core/src/srgb8.rs",
"crates/labcolors-core/src/wcag22.rs",
"crates/labcolors-core/src/wcag22_evidence.rs",
"crates/labcolors-core/src/wcag22/kernel.rs",
]

# Запас времени на мутант: legacy proxy coordinate считается быстро, но набор в целом не
Expand Down
49 changes: 34 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ jobs:
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- name: cargo test
run: cargo test --workspace --locked
- name: prove WCAG22 sRGB8 Q55 artifact over the full finite domain
run: python3 scripts/verify_wcag22_q55.py

audit:
name: cargo audit (rustsec)
Expand Down Expand Up @@ -315,12 +317,21 @@ jobs:
- name: wasm-pack build (release)
# The release bundle: panic=abort, no panic hook, wasm-opt -Oz. This is
# the artifact @labpics/colors ships, so the size measured below is real.
run: wasm-pack build crates/labcolors-wasm --release --target web --out-dir ../../packages/colors/pkg --out-name labcolors --locked
# Rust error locations otherwise embed the self-hosted runner's mutable
# workspace/CARGO_HOME roots and make identical source hash differently.
run: |
export CARGO_ENCODED_RUSTFLAGS="--remap-path-prefix=$GITHUB_WORKSPACE=/workspace/lab-colors"$'\x1f'"--remap-path-prefix=$CARGO_HOME=/cargo-home"
wasm-pack build crates/labcolors-wasm --release --target web --out-dir ../../packages/colors/pkg --out-name labcolors --locked
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: ${{ env.NODE_TOOLCHAIN }}
cache: npm
cache-dependency-path: packages/colors/package-lock.json
- name: enforce measured WASM raw-byte budget
# This Linux x64 release-equivalent build is the canonical Issue #284
# artifact: the checker binds its exact SHA-256 and raw-byte ceiling,
# without invented headroom. gzip is transport diagnostics only.
run: node scripts/check-wasm-size-budget.mjs
- name: "@labpics/colors: typecheck + runtime tests"
# Now that pkg/ exists (built above), the package's public types resolve
# against the *real* wasm-bindgen declarations — so the type-level smoke
Expand Down Expand Up @@ -357,8 +368,11 @@ jobs:
# 1. Download exact CfT chrome + chromedriver archives and verify SHA-256.
# wasm-pack reads CHROME_PATH for the browser but ignores a CHROMEDRIVER
# variable, so the matching driver is passed through --chromedriver.
# 2. Extract required shared libs (.so) from Ubuntu .deb packages without sudo:
# `apt-get download` fetches .deb; `dpkg --extract` unpacks without root.
# 2. Extract required shared libs (.so) from the runner's configured
# Debian/Ubuntu repository without sudo. Refresh package metadata in
# runner.temp first: shared self-hosted images can retain stale lists
# whose package URLs already return 404. `apt-get download` fetches
# .deb and `dpkg --extract` unpacks it without root.
# Chrome/chromedriver need libnspr4, libnss3, libasound2t64, libgbm1
# which are absent on the slim WSL runner image.
# 3. Diagnose chromedriver session creation (Chrome's stderr) before wasm-pack.
Expand All @@ -385,14 +399,27 @@ jobs:
echo "CHROMEDRIVER_PATH=$CHROMEDRIVER_BIN" >> "$GITHUB_ENV"
echo "Chrome for Testing $CHROME_FOR_TESTING_VERSION installed"

# -- Extract Chrome shared-lib dependencies from Ubuntu .deb (no sudo needed) --
# -- Extract Chrome shared-lib dependencies from distro .deb (no sudo needed) --
DEPS_DIR="$RUNNER_TEMP/chrome-deps-$GITHUB_JOB"
DEBS_DIR="$DEPS_DIR/debs"
mkdir -p "$DEBS_DIR"
APT_LISTS="$DEPS_DIR/apt-lists"
APT_CACHE="$DEPS_DIR/apt-cache"
mkdir -p "$DEBS_DIR" "$APT_LISTS/partial" "$APT_CACHE/archives/partial"
# Keep every mutable APT path job-local and disable global locks. The
# system sources/keyrings and dpkg status remain read-only inputs.
APT_OPTIONS=(
-o "Dir::State::lists=$APT_LISTS"
-o "Dir::State::status=/var/lib/dpkg/status"
-o "Dir::Cache=$APT_CACHE"
-o "Dir::Cache::archives=$APT_CACHE/archives"
-o "Debug::NoLocking=1"
-o "Acquire::Retries=3"
)
apt-get "${APT_OPTIONS[@]}" update
# libnspr4/libnss3: NSS/NSPR crypto deps for Chrome and chromedriver.
# libasound2t64: ALSA (renamed from libasound2 in Ubuntu 24.04 noble).
# libasound2t64: ALSA after the current Debian/Ubuntu time64 transition.
# libgbm1: GPU buffer manager (needed by Chrome headless for DRM/render node).
(cd "$DEBS_DIR" && apt-get download libnspr4 libnss3 libasound2t64 libgbm1 2>&1)
(cd "$DEBS_DIR" && apt-get "${APT_OPTIONS[@]}" download libnspr4 libnss3 libasound2t64 libgbm1 2>&1)
for deb in "$DEBS_DIR"/*.deb; do
dpkg --extract "$deb" "$DEPS_DIR"
done
Expand Down Expand Up @@ -459,14 +486,6 @@ jobs:
# Chrome is provisioned above; the parity smoke runs against native
# resolve_set inside the same wasm runtime. D1 default from the chapter.
run: wasm-pack test --headless --chrome --chromedriver "$CHROMEDRIVER_PATH" crates/labcolors-wasm --locked
- name: report bundle size (gzip)
# Size is part of the perf story (perf-bench). Not a hard gate yet — a
# budget gate lands with perf-bench; here we surface the number in logs.
run: |
wasm="packages/colors/pkg/labcolors_bg.wasm"
glue="packages/colors/pkg/labcolors.js"
echo "wasm: raw=$(wc -c <"$wasm")B gzip=$(gzip -9 -c "$wasm" | wc -c)B"
echo "glue: raw=$(wc -c <"$glue")B gzip=$(gzip -9 -c "$glue" | wc -c)B"
docs-drift:
name: docs-drift (нейминг-канон)
runs-on: [self-hosted, Linux, X64]
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ target/
packages/colors/.release/
packages/colors/LICENSE
packages/colors/build-metadata.json
packages/colors/evidence/

# Психофизический харнесс: сгенерированные манифесты/раннеры/экспорты сессий —
# это артефакты запуска (детерминированы из seed), в гит не коммитятся.
Expand Down
40 changes: 32 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,23 @@ Rust различаются, потому что это разные delivery su

## [Unreleased]

Атомарная numerical-decision граница (#292). Wire/npm JSON, эмитируемые цвета,
config fingerprint и `packDigest` conformance-векторов НЕ изменились; breaking
только Rust API. Migration-note: [exact alpha / typed
Glow](docs/migrations/exact-alpha-glow.md), дополнение ADR-0004 от 2026-07-12.
Атомарная numerical-decision граница (#292) и exact WCAG 2.2 evaluator для
финальной sRGB8-пары (#284). Существующая цветовая эмиссия, config fingerprint
и adaptive runtime не меняются, но Rust/npm capability API и conformance pack
изменены; следующий release обязан получить согласованный 0.x version bump.
Migration-note: [exact alpha / typed Glow](docs/migrations/exact-alpha-glow.md),
дополнение ADR-0004 от 2026-07-12.

### Added

- Versioned `evaluate_wcag22_srgb8` / `evaluate_wcag22_hex` и эквивалентные
WASM/TypeScript/UniFFI границы. Criterion всегда объявляет клиент; verdict
возвращает точное terminal evidence без epsilon или округлённого ratio.
- Canonical Q55 artifact и независимый verifier: Decimal directed-rounding +
integer tightness для 768 строк, полный scan всех `16 777 216` sRGB8-цветов,
source bindings и SHA-256 live typed registry admission-row.
- npm package несёт byte-exact profile/table/proof в `evidence/`; release
verifier и clean-install gate повторно проверяют их хэши и содержимое.

### Breaking (Rust API)

Expand All @@ -23,18 +36,29 @@ Glow](docs/migrations/exact-alpha-glow.md), дополнение ADR-0004 от 2
- `NumericalDecisionEvidenceV1::BitExact` запечатан (приватное поле-печать):
внешний код матчит только с `..`, минт выполняет registry-owned конструктор
(закреплено compile-fail тестом).
- Все terminal-варианты `NumericalDecisionV1<T>` и
`GlowDecisionOutcomeV1` запечатаны variant-level `#[non_exhaustive]`:
подлинное evidence одного site нельзя переупаковать как результат другого;
внешний match обязан использовать `..`.
- Временный capability V1 заменён единственным public
`NumericalCapabilityManifestV2`; WCAG site несёт artifact/bound/proof IDs.
Published `@labpics/colors` 0.10.0 остаётся неизменным, а следующий npm
release должен мигрировать на V2 явно.
- `RoleSpec::Glow` несёт typed execution mode
(`NumericalExecutionModeV1::StableOnly` |
`ExplicitCompatibility { release_id }`); строковый `GlowDecisionProfileV1`
остался boundary-адаптером, прежние wire keys (`stable-v1`,
`legacy-platform-dependent-v1`, `bit-exact`) сохранены byte-for-byte.
- Raw WCAG profile/proof JSON больше не поля runtime-профиля: используйте
`Wcag22ProfileV1::source_json()` / `proof_json()`. Это позволяет linker-у не
включать отдельно поставляемые evidence-документы в WASM.

### Changed

- Conformance pack 3.0.0: `manifest.numericalSites` заменён typed
`numericalCapabilities` — capability manifest ядра (schema v1, coverage
`migrated-sites-only-v1`, FNV-1a-32 drift-checksum над canonical
length-prefixed preimage). Векторные семейства и `packDigest` не изменились.
- Conformance pack 4.0.0 добавляет `wcag22.json`; `packDigest` закономерно
изменён. `manifest.numericalCapabilities` зеркалит single public V2 core
manifest (coverage `migrated-sites-only-v1`, FNV-1a-32 drift-checksum над
canonical length-prefixed preimage).
- Release manifest schema v2: секция `numericalSites` заменена на
`numericalCapabilities`; release verifier и Swift conformance-тесты
пересчитывают capability checksum независимо от Rust-кода.
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,9 @@ CSS-строка, CSSOM и обход DOM сами по себе не повыш
registry с независимо пересчитываемым drift-checksum — входит в conformance
manifest. Он описывает возможности сборки и не повышает незарегистрированный
или explicit `Compatibility`-результат до determinate только потому, что тесты
на одной платформе зелёные.
на одной платформе зелёные. До появления внешних клиентов capability-контракт
исправлен атомарно: единственный `numericalCapabilityManifest()` возвращает
proof-capable schema V2; промежуточный public V1 и второй V2-entrypoint удалены.

## Источники и производные значения

Expand Down Expand Up @@ -216,7 +218,8 @@ anchors
- Нормативный floor применяется только там, где его требует контракт клиента или компонента.
- Core не определяет размер текста, essentialness, disabled/decorative status по имени роли.
- Экспериментальный LPC/APCA-shaped или appearance-результат не меняет WCAG pass/fail.
- До миграции на единый versioned WCAG 2.2 profile старое поле `wcagRatio` нельзя автоматически рекламировать как `Wcag22`.
- Для финальной пары sRGB8 новый `wcag22-srgb8-contrast-v1` принимает явно объявленный критерий и возвращает строгий `Pass | Fail`; профиль, Q55-артефакт и full-domain proof входят в релиз.
- Старое поле `wcagRatio` остаётся compatibility-диагностикой текущего resolver/runtime и не может автоматически рекламироваться как результат нового evaluator-а.
- Цвет не должен быть единственным носителем смысла; текст, иконка и форма принадлежат компоненту.

## Runtime и фон
Expand Down
Loading
Loading