jouleclaw-compliance: EU Cyber Resilience Act Article 14 reporting as an auditable filing chain #282

Merged
dcharlot merged 2 commits from feat/cra-art14-filing-chain into main 2026-10-17 04:02:37 -04:00
Owner

What this adds

The cra module in jouleclaw-compliance records EU Cyber Resilience Act reporting as an auditable chain of filings. It covers both kinds of Article 14 case: an actively exploited vulnerability (Art. 14(2)) and a severe incident affecting the product's security (Art. 14(4)). Article 14 has applied since 11 September 2026 (Art. 71(2)).

The chain. Each filing names the content id of the one it supersedes, and every accepted filing is a leaf in a Merkle log. Filing returns a receipt with the leaf index, the content id, an inclusion proof and the root. Tree heads can be signed, and consistency proofs show that nothing filed earlier was changed.

The chain refuses a filing that:

  • is for another case or subject;
  • does not supersede the current head;
  • is dated before the previous filing;
  • goes back to an earlier stage;
  • moves the awareness time later (an earlier awareness is accepted, and it moves the deadlines earlier);
  • is dated before its own awareness;
  • names a product twice.

Deadlines follow the text of Article 14:

  • early warning: 24 hours after the earliest stated awareness;
  • notification: 72 hours after it;
  • vulnerability final report: 14 days after a corrective or mitigating measure is available;
  • incident final report: one calendar month after the incident notification was submitted.

Each stage is reported as met, late, pending, overdue, or with its clock not yet started.

On the "unless the relevant information has already been provided" clause:

  • each stage's content contains the earlier stages', so a filing at a later stage satisfies every earlier one;
  • a filing that already carries a later stage's information declares it in also_provides.

Queries:

  • known_at(t): what had been filed by a given time, for example hour 24;
  • revisions(): every change in a product's status across the chain;
  • replay: rebuilds a chain from stored filings and re-checks every rule.

Checked

On the build host:

  • cargo test -p jouleclaw-compliance: 76 passed, including the cra tests (the chain rules, every deadline state for both subjects, calendar-month arithmetic from 31 January, known_at, revisions, receipts, and tamper and replay checks);
  • clippy with -D warnings is clean;
  • the public-surface audit passes.

Each of these mutations fails a test:

  • the awareness-moved-later rule disabled;
  • one month computed as 30 days;
  • also_provides ignored;
  • a later stage no longer carrying the earlier stages.

The Article 14 wording was checked against a published copy of the regulation's text.

🤖 Generated with Claude Code

## What this adds The `cra` module in `jouleclaw-compliance` records EU Cyber Resilience Act reporting as an auditable chain of filings. It covers both kinds of Article 14 case: an actively exploited vulnerability (Art. 14(2)) and a severe incident affecting the product's security (Art. 14(4)). Article 14 has applied since 11 September 2026 (Art. 71(2)). **The chain.** Each filing names the content id of the one it supersedes, and every accepted filing is a leaf in a Merkle log. Filing returns a receipt with the leaf index, the content id, an inclusion proof and the root. Tree heads can be signed, and consistency proofs show that nothing filed earlier was changed. The chain refuses a filing that: - is for another case or subject; - does not supersede the current head; - is dated before the previous filing; - goes back to an earlier stage; - moves the awareness time **later** (an earlier awareness is accepted, and it moves the deadlines earlier); - is dated before its own awareness; - names a product twice. **Deadlines** follow the text of Article 14: - early warning: 24 hours after the earliest stated awareness; - notification: 72 hours after it; - vulnerability final report: 14 days after a corrective or mitigating measure is available; - incident final report: one calendar month after the incident notification was submitted. Each stage is reported as met, late, pending, overdue, or with its clock not yet started. On the "unless the relevant information has already been provided" clause: - each stage's content contains the earlier stages', so a filing at a later stage satisfies every earlier one; - a filing that already carries a later stage's information declares it in `also_provides`. **Queries:** - `known_at(t)`: what had been filed by a given time, for example hour 24; - `revisions()`: every change in a product's status across the chain; - `replay`: rebuilds a chain from stored filings and re-checks every rule. ## Checked On the build host: - `cargo test -p jouleclaw-compliance`: **76 passed**, including the cra tests (the chain rules, every deadline state for both subjects, calendar-month arithmetic from 31 January, `known_at`, revisions, receipts, and tamper and replay checks); - clippy with `-D warnings` is clean; - the public-surface audit passes. Each of these mutations fails a test: - the awareness-moved-later rule disabled; - one month computed as 30 days; - `also_provides` ignored; - a later stage no longer carrying the earlier stages. The Article 14 wording was checked against a published copy of the regulation's text. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
A new `cra` module records one Article 14 case (an actively exploited
vulnerability, Regulation (EU) 2024/2847, Art. 14(2), or a severe incident,
Art. 14(4)) as a hash-linked chain of filings. Every accepted filing's
BLAKE3 content hash is a leaf in a Merkle log, and filing returns a receipt
carrying the leaf index, content id, inclusion proof and root. A filing
altered after it was filed no longer verifies against its receipt.

The chain refuses a filing for another case or subject, one that does not
supersede the current head, one dated before the previous filing, one whose
stage is behind the furthest filed, one that moves awareness later, one
dated before its own awareness, and one naming a product twice. An earlier
awareness is accepted and moves the deadlines earlier.

Deadlines: early warning 24 h and notification 72 h after the chain's
earliest awareness; the vulnerability final report 14 days after the
earliest stated corrective measure; the incident final report one calendar
month after the filing that satisfied the notification. The early warning
is satisfied by any filing; the later stages by a filing at that stage or
one declaring the stage in `also_provides`.

Also: known_at(t), per-product status revisions, tree heads for signing,
consistency and inclusion proofs, and replay from stored filings.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
jouleclaw-compliance: a later-stage CRA filing carries the earlier stages' information
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 5s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m32s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 1m5s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 2m52s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m3s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m2s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 52s
ebeed2de38
As first built, a stage was satisfied only by a filing at exactly that
stage, or one that listed it in `also_provides`. A final report filed
without a separate notification therefore left the notification stage
unsatisfied. Since a stage cannot be filed after a later one, it would have
stayed overdue for good, although the final report carries everything the
notification does.

`Filing::provides(stage)` is now `self.stage >= stage` or a stage listed in
`also_provides`. Each stage's content contains the earlier stages', and
`also_provides` keeps its real job: declaring that a filing already carries
a LATER stage's information early. The module and method docs say so.
`a_later_stage_carries_the_earlier_ones` covers a final report filed on
time and one filed late with no separate notification.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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!282
No description provided.