jouleclaw: bind a policy receipt to the rules, not to a version number #177

Merged
dcharlot merged 1 commit from feat/policy-digest into main 2026-10-09 02:49:56 -04:00
Owner

What a policy receipt said about the policy

A PolicyReceipt recorded policy_version and, on an allow, decision.rule —
a counter and a name. Neither says what the rules were.

The obvious form of this hole is already closed, and it is worth being precise
about that: InMemoryPolicyEngine::install_policy refuses a non-increasing
install, so within one engine instance a version does identify a ruleset.
What the counter cannot do is mean anything outside that instance:

  • A restart, a replica, or a second host starts its own count at 1 with whatever
    rules it was handed.
  • The monotonic guard lives in the bundled engine, not in the PolicyEngine
    contract, so another backend need not have one.

Either way a receipt citing (engine_id, policy_version) is a pointer into
state only its producer holds. A verifier has to be told what engine-A's
version 1 contained — by the party whose decision is under audit. The headline
test is exactly that: two engines, both at version 1, one of which would also
have allowed /etc/shadow, producing receipts whose policy_version and
decision are identical.

The digest

Policy::digest_hex content-addresses the rules. Three choices make it a digest
of the policy rather than of a serialization, each with its own test:

choice why
rule order is included decide scans Deny rules first and short-circuits, so reordering can change the outcome — two orderings are two policies
the agent list is sorted agents:one_of is matched by membership, so two policies differing only in that order are the same policy and must share a digest
a port range is hashed as written from > to matches nothing, which is a different policy from the same pair reversed — normalising would merge an always-deny rule with a permissive one

version is excluded: the digest answers "which rules", the version travels
beside it answering "which installation", and folding the counter in would make
one ruleset hash differently per engine. Mode and method tags are written out
rather than taken from serde, so the digest does not move if a rename or a
variant reordering lands.

A test that proved nothing, caught by falsifying

Every variable-length part is length-prefixed. The first test I wrote for that
did not exercise it: a rule named "ab" with glob "c" is already
distinguishable from one named "a" with glob "bc", because the constant tags
("allow", "action:filesystem") sit between them. Stripping the prefixes left
the suite green.

The prefixes are load-bearing in the one place two arbitrary strings are
adjacent — the sorted agent id list, where nothing separates one id from the
next and the count is equal either way, so ["ab","c"] and ["a","bc"] render
to the identical run "abc". The test now pins that case and fails without the
prefixes.

Captured at decision time, not at shipping time

The digest is recorded on the AuditEvent when the decision is made, not read
off the engine when the event is later shipped — the live policy can be replaced
in between, and attributing a decision to rules installed afterwards is the
error the field exists to prevent. Both construction sites set it (evaluate
and evaluate_traced), because a digest on one but not the other is a gap that
looks like data.

PolicyEngine::policy_digest defaults to None so a backend that holds its
rules somewhere it cannot hash — a remote service, a kernel module — stays
conformant rather than being forced to invent a digest. A consumer that requires
the binding can only refuse such an engine if the absence is reported.

Additive, and the published bytes prove it

policy_digest is skipped when absent and omitted from canonical_wire, so
a receipt without it has a signed core byte-identical to one produced before the
field existed. Regenerating the pack is the proof rather than the claim:

  • vectors 1–3 keep their published signed_core_cbor_hex and cose_sign1_hex
    exactly;
  • new vector 4 is vector 1's decision with the binding, and the two wire maps
    differ by exactly one key;
  • the Rust, Python and Go reference verifiers each verify 4/4 with no
    verifier change
    , because each encodes the map the vector publishes.

Falsifying this is the sharpest check in the set: emitting an absent digest as
an empty string instead of omitting it breaks the committed conformance
vectors.

Three other crates build a PolicyReceipt by struct literal in test fixtures
(jouleclaw-cli, jouleclaw-ledger, jouleclaw-otel), each now passing
None. A targeted cargo check -p jouleclaw-policy-receipt --all-targets did
not reach them; only the whole-workspace run did. jouleclaw-otel also exports
the digest beside the version it already exported.

Spec

§10.1 Binding the receipt to the rules: the preimage written out
byte-for-byte, the three rendering rules as MUSTs, the requirement that the
digest be the one in force at the decision, and the requirement that an absent
digest be omitted rather than nulled.

Verification

Whole jouleclaw-rs workspace: 1457 passed. One failure,
jouleclaw-energy --test process_cpu, is pre-existing and unrelated — it
asserts a child process burns ≥ 0.2 J in a 300 ms wall window, which the dev
Mac's load (average 149 during the run) starves to 0.147 J. It passes on a rerun
and touches nothing in this change; it is being fixed separately, together with
the same class of flake in eoc-meter.

Eight falsifications from the committed baseline:

reverted caught by
rule order dropped (rules sorted) rule_order_is_in_the_digest_because_order_is_semantics
agent list left unsorted agent_list_order_is_not_in_the_digest_because_it_is_a_set
length prefixes removed no_two_policies_share_a_preimage_by_shifting_a_boundary
port range normalised before hashing a_port_range_is_digested_as_written_not_normalised
digest attached but kept out of the signed core 3 tests
digest read off the engine at ship time 3 tests
absent digest emitted as "" the committed conformance vectors
evaluate_traced omits the digest an_audit_event_records_the_policy_that_decided_not_the_one_installed_later

🤖 Generated with Claude Code

## What a policy receipt said about the policy A `PolicyReceipt` recorded `policy_version` and, on an allow, `decision.rule` — a counter and a name. Neither says what the rules were. The obvious form of this hole is already closed, and it is worth being precise about that: `InMemoryPolicyEngine::install_policy` refuses a non-increasing install, so **within one engine instance** a version does identify a ruleset. What the counter cannot do is mean anything outside that instance: - A restart, a replica, or a second host starts its own count at 1 with whatever rules it was handed. - The monotonic guard lives in the bundled engine, not in the `PolicyEngine` contract, so another backend need not have one. Either way a receipt citing `(engine_id, policy_version)` is a pointer into state only its producer holds. A verifier has to be *told* what engine-A's version 1 contained — by the party whose decision is under audit. The headline test is exactly that: two engines, both at version 1, one of which would also have allowed `/etc/shadow`, producing receipts whose `policy_version` and `decision` are identical. ## The digest `Policy::digest_hex` content-addresses the rules. Three choices make it a digest of the *policy* rather than of a serialization, each with its own test: | choice | why | |---|---| | **rule order is included** | `decide` scans `Deny` rules first and short-circuits, so reordering can change the outcome — two orderings are two policies | | **the agent list is sorted** | `agents:one_of` is matched by membership, so two policies differing only in that order *are* the same policy and must share a digest | | **a port range is hashed as written** | `from` > `to` matches nothing, which is a different policy from the same pair reversed — normalising would merge an always-deny rule with a permissive one | `version` is excluded: the digest answers "which rules", the version travels beside it answering "which installation", and folding the counter in would make one ruleset hash differently per engine. Mode and method tags are written out rather than taken from serde, so the digest does not move if a rename or a variant reordering lands. ### A test that proved nothing, caught by falsifying Every variable-length part is length-prefixed. The first test I wrote for that did not exercise it: a rule named `"ab"` with glob `"c"` is already distinguishable from one named `"a"` with glob `"bc"`, because the constant tags (`"allow"`, `"action:filesystem"`) sit between them. Stripping the prefixes left the suite **green**. The prefixes are load-bearing in the one place two *arbitrary* strings are adjacent — the sorted agent id list, where nothing separates one id from the next and the count is equal either way, so `["ab","c"]` and `["a","bc"]` render to the identical run `"abc"`. The test now pins that case and fails without the prefixes. ## Captured at decision time, not at shipping time The digest is recorded on the `AuditEvent` when the decision is made, not read off the engine when the event is later shipped — the live policy can be replaced in between, and attributing a decision to rules installed afterwards is the error the field exists to prevent. Both construction sites set it (`evaluate` and `evaluate_traced`), because a digest on one but not the other is a gap that looks like data. `PolicyEngine::policy_digest` defaults to `None` so a backend that holds its rules somewhere it cannot hash — a remote service, a kernel module — stays conformant rather than being forced to invent a digest. A consumer that requires the binding can only refuse such an engine if the absence is *reported*. ## Additive, and the published bytes prove it `policy_digest` is skipped when absent **and** omitted from `canonical_wire`, so a receipt without it has a signed core byte-identical to one produced before the field existed. Regenerating the pack is the proof rather than the claim: - vectors 1–3 keep their published `signed_core_cbor_hex` and `cose_sign1_hex` **exactly**; - new vector 4 is vector 1's decision with the binding, and the two wire maps differ by exactly one key; - the **Rust, Python and Go** reference verifiers each verify **4/4 with no verifier change**, because each encodes the map the vector publishes. Falsifying this is the sharpest check in the set: emitting an absent digest as an empty string instead of omitting it breaks the committed conformance vectors. Three other crates build a `PolicyReceipt` by struct literal in test fixtures (`jouleclaw-cli`, `jouleclaw-ledger`, `jouleclaw-otel`), each now passing `None`. A targeted `cargo check -p jouleclaw-policy-receipt --all-targets` did not reach them; only the whole-workspace run did. `jouleclaw-otel` also exports the digest beside the version it already exported. ## Spec **§10.1 Binding the receipt to the rules**: the preimage written out byte-for-byte, the three rendering rules as MUSTs, the requirement that the digest be the one in force at the decision, and the requirement that an absent digest be omitted rather than nulled. ## Verification Whole `jouleclaw-rs` workspace: **1457 passed**. One failure, `jouleclaw-energy --test process_cpu`, is **pre-existing and unrelated** — it asserts a child process burns ≥ 0.2 J in a 300 ms wall window, which the dev Mac's load (average 149 during the run) starves to 0.147 J. It passes on a rerun and touches nothing in this change; it is being fixed separately, together with the same class of flake in `eoc-meter`. Eight falsifications from the committed baseline: | reverted | caught by | |---|---| | rule order dropped (rules sorted) | `rule_order_is_in_the_digest_because_order_is_semantics` | | agent list left unsorted | `agent_list_order_is_not_in_the_digest_because_it_is_a_set` | | length prefixes removed | `no_two_policies_share_a_preimage_by_shifting_a_boundary` | | port range normalised before hashing | `a_port_range_is_digested_as_written_not_normalised` | | digest attached but kept out of the signed core | 3 tests | | digest read off the engine at ship time | 3 tests | | absent digest emitted as `""` | the committed conformance vectors | | `evaluate_traced` omits the digest | `an_audit_event_records_the_policy_that_decided_not_the_one_installed_later` | 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jouleclaw: bind a policy receipt to the rules, not to a version number
Some checks failed
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 8m15s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m43s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m41s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 2m13s
standards workspaces build + test / map-rs (pull_request) Successful in 2m11s
standards workspaces build + test / mesh-rs (pull_request) Successful in 2m15s
standards workspaces build + test / openpay (pull_request) Successful in 8m25s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 59s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m9s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m28s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m26s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m24s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m15s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m7s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m57s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 1h42m15s
standards workspaces build + test / macOS energy backends (pull_request) Failing after 1h35m15s
e222aa7d68
A `PolicyReceipt` recorded `policy_version` and, on an allow,
`decision.rule` — a counter and a name. Neither says what the rules were.

The hole is narrower than it first looks, and worth stating precisely because
the obvious version of it is already closed: `InMemoryPolicyEngine::install_policy`
refuses a non-increasing install, so *within one engine instance* a version does
identify a ruleset. What the counter cannot do is mean anything outside that
instance. A restart, a replica, or a second host starts its own count at 1 with
whatever rules it was handed, and the monotonic guard lives in the bundled
engine rather than in the `PolicyEngine` contract, so another backend need not
have one. Either way a receipt citing `(engine_id, policy_version)` is a
pointer into state only its producer holds: a verifier has to be *told* what
engine-A's version 1 contained, by the party whose decision is under audit.

`Policy::digest_hex` content-addresses the rules. Three choices make it a digest
of the policy rather than of a serialization, each with a test:

- **Rule order is in the digest.** `decide` scans `Deny` rules first and
  short-circuits, so reordering can change the outcome: two orderings are two
  policies.
- **The agent list is sorted before hashing.** `agents:one_of` is matched by
  membership, so two policies differing only in that order are the same policy
  and must share a digest.
- **A port range is hashed as written, not normalised.** A range whose `from`
  exceeds its `to` matches nothing, which is a different policy from the same
  pair reversed.

`version` is excluded: the digest answers "which rules", the version travels
beside it answering "which installation", and folding the counter in would make
one ruleset hash differently per engine. Mode and method tags are written out
rather than taken from serde, so the digest does not move if a rename or a
variant reordering lands.

Every variable-length part is length-prefixed. The first test I wrote for that
did not actually exercise it — a rule named "ab" with glob "c" is already
distinguishable from one named "a" with glob "bc", because the constant tags
("allow", "action:filesystem") sit between them. Falsification caught it:
stripping the prefixes left the suite green. The prefixes are load-bearing in
the one place two *arbitrary* strings are adjacent — the sorted agent id list,
where nothing separates one id from the next and the count is equal either way,
so `["ab","c"]` and `["a","bc"]` render to the identical run "abc". The test now
pins that case, and fails without the prefixes.

The digest is recorded on the `AuditEvent` at decision time, not read off the
engine when the event is later shipped: the live policy can be replaced in
between, and attributing a decision to rules installed after it was made is the
error the field exists to prevent. Both construction sites set it — `evaluate`
and `evaluate_traced` — because a digest on one but not the other is a gap that
looks like data. `PolicyEngine::policy_digest` defaults to `None` so a backend
that holds its rules somewhere it cannot hash stays conformant rather than being
forced to invent one; a consumer requiring the binding can only refuse such an
engine if the absence is reported.

Additive on the wire. `policy_digest` is skipped when absent *and* omitted from
`canonical_wire`, so a receipt without it has a signed core byte-identical to
one produced before the field existed. Regenerating the pack proves it: vectors
1-3 keep their published `signed_core_cbor_hex` and `cose_sign1_hex` exactly,
and new vector 4 is vector 1's decision with the binding, differing by exactly
that one key. The Rust, Python and Go reference verifiers all verify 4/4 with no
verifier change, because each encodes the map the vector publishes.

Three other crates build a `PolicyReceipt` by struct literal in test fixtures
(`jouleclaw-cli`, `jouleclaw-ledger`, `jouleclaw-otel`); each passes `None`, the
legacy shape. A targeted `cargo check -p jouleclaw-policy-receipt --all-targets`
did not reach them — only the whole-workspace run did.

`jouleclaw-otel` exports the digest beside the version it already exported. A
span naming the version alone has the same gap the receipt field closes. Absent
is left absent rather than exported as an empty string, so a query can tell "no
binding" from "a binding that is blank".

SPEC §10 gains §10.1: the preimage written out byte-for-byte, the three
rendering rules as MUSTs, the requirement that the digest be the one in force at
the decision, and the requirement that an absent digest be omitted rather than
nulled.

Co-Authored-By: Claude Opus 5 <[email protected]>
dcharlot force-pushed feat/policy-digest from e222aa7d68
Some checks failed
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 8m15s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m43s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m41s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 2m13s
standards workspaces build + test / map-rs (pull_request) Successful in 2m11s
standards workspaces build + test / mesh-rs (pull_request) Successful in 2m15s
standards workspaces build + test / openpay (pull_request) Successful in 8m25s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 59s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m9s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m28s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m26s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m24s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m15s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m7s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m57s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 1h42m15s
standards workspaces build + test / macOS energy backends (pull_request) Failing after 1h35m15s
to 9f2085ae9e
Some checks failed
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m7s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m27s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m15s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m10s
standards workspaces build + test / proof-rs (pull_request) Successful in 2m30s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m17s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m41s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m14s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 14s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 11m49s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 29s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 48s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m40s
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Successful in 1h14m3s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m3s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m1s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m6s
wai-pack / wai-pack · linux (pull_request) Failing after 12s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Failing after 54s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 1m25s
wai-pack / wai-pack · dependency licences (pull_request) Failing after 1m6s
WAI section references / cited sections exist (pull_request) Successful in 10s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m1s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m58s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
2026-10-07 10:08:01 -04:00
Compare
dcharlot force-pushed feat/policy-digest from 9f2085ae9e
Some checks failed
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m7s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m55s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m27s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m15s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m10s
standards workspaces build + test / proof-rs (pull_request) Successful in 2m30s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m17s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m41s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m14s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 14s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 11m49s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 29s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 48s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m40s
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Successful in 1h14m3s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m3s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m1s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m6s
wai-pack / wai-pack · linux (pull_request) Failing after 12s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Failing after 54s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 1m25s
wai-pack / wai-pack · dependency licences (pull_request) Failing after 1m6s
WAI section references / cited sections exist (pull_request) Successful in 10s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m1s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 1m58s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
to 959b9d8f42
All checks were successful
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m17s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m38s
wai cross-architecture byte-equality / linux-x86_64 (pull_request) Successful in 24s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 6m33s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 13s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 13m3s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 8s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 24s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 46s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 1m47s
WAI HTTP delivery / HTTP corpus · falsification and differential (pull_request) Successful in 1h19m25s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 1m6s
WAI JPEG-AI whole decode (pinned inputs, required) / fetch pinned JPEG-AI inputs → whole decode + pixel hash, required (pull_request) Successful in 1m2s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m8s
wai-pack / wai-pack · linux (pull_request) Successful in 1m4s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 1m43s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 21s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m8s
WAI section references / cited sections exist (pull_request) Successful in 10s
WAI mbt2018_mean integer decode (regenerated vectors) / regenerate mbt2018_mean integer vectors → Rust decode, required (pull_request) Successful in 4m16s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 2m41s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 37m35s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 47m17s
wai cross-architecture byte-equality / macos-arm64 (reference) (pull_request) Successful in 1m4s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 16m12s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 40s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 3m50s
wai-pack / wai-pack · macos (pull_request) Successful in 3m28s
2026-10-08 10:30:32 -04:00
Compare
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!177
No description provided.