# Release v1.4-rc1

> **Historical document.** This is the operational walkthrough for `v1.4-rc1`, a superseded pre-release. It is retained for the project record and is not current. The current release line is `v1.5-rc1`; see [`v1.5-rc1.md`](v1.5-rc1.md). The schema names, batch references, file lists, and verification steps below describe the repository as it stood at `v1.4-rc1` and have deliberately not been updated.

This document is the operational walkthrough to cut the `v1.4-rc1` pre-release tag in the actproof-events repository. The tag is the closing step of Batch A of the Quoruna substrate pivot.

## Summary

`v1.4-rc1` introduces the act-native catalogue entry schema (`actproof.act_catalogue_entry.v2`), two reference catalogue entries (NIS2 Article 20 management body approval, EUDR DDS preparation), deterministic test vector generation, the SCITT alignment downgrade to "aligned, COSE_Sign1 bridge planned", the witness recipient model, the eIDAS firewall (approval evidence model section), and the catalogue loader contract.

This is a **pre-release candidate**, not v1.4 final. v1.4 final lands when Quoruna v2.0 ships and both repositories are tagged simultaneously (Batch E in the Quoruna repository handles the synchronized tag).

## What's in v1.4-rc1

### New files

- `spec/actproof-events.spec.md` - the v1.4-rc1 specification document
- `spec/schemas/act_catalogue_entry.v2.json` - the v2 JSON Schema
- `catalogue/acts/eu/nis2/art20/management_body_approval.v1.json` - NIS2 v2 entry
- `catalogue/acts/eu/nis2/art20/management_body_approval.v1.test_vectors.json` - NIS2 test vector
- `catalogue/acts/eu/nis2/art20/_deprecated/README.md` - v1 deprecation documentation
- `catalogue/acts/eu/eudr/dds_preparation.v1.json` - EUDR v2 entry
- `catalogue/acts/eu/eudr/dds_preparation.v1.test_vectors.json` - EUDR test vector
- `scripts/compute_test_vectors.py` - deterministic test vector generator
- `scripts/test_vector_inputs/README.md` - fixture documentation
- `scripts/test_vector_inputs/nis2_art20_v1_001.json` - NIS2 manifest input
- `scripts/test_vector_inputs/eudr_dds_v1_001.json` - EUDR manifest input
- `CATALOGUE_LOADER_CONTRACT.md` - cross-implementation loader contract
- `docs/releases/v1.4-rc1.md` - this document

### Files that moved in this release

All three v1 catalogue entries were moved into their respective `_deprecated/` directories. The substrate state after this release contains only v2 entries at non-deprecated paths, which keeps the catalogue loader's schema validation consistent:

- `catalogue/acts/eu/nis2/art20/approval.json` → `_deprecated/`
- `catalogue/acts/eu/nis2/art20/approval.test_vectors.json` → `_deprecated/`
- `catalogue/acts/corporate/board_resolution_v1.json` → `_deprecated/`
- `catalogue/acts/corporate/board_resolution_v1.test_vectors.json` → `_deprecated/`
- `catalogue/acts/eu/ai_act/art26/risk_assessment.json` → `_deprecated/`
- `catalogue/acts/eu/ai_act/art26/risk_assessment.test_vectors.json` → `_deprecated/`

Only the NIS2 entry has a v2 successor in this release (`management_body_approval.v1`). The corporate board resolution and AI Act Article 26 risk assessment entries have v2 successors planned for v1.5. The respective `_deprecated/README.md` files document the status.

If you are constructing the release tag from a fresh clone, the file moves are already applied in the merged archive. If you are integrating into an existing local checkout, use `git mv` for each pair so that git detects the renames and preserves history.

## Pre-tag verification

Run these commands from the repository root. All must succeed before tagging.

### 1. JSON Schema validates

```bash
python3 -m pip install jsonschema --upgrade
python3 -c "
import json
from jsonschema import Draft202012Validator
with open('spec/schemas/act_catalogue_entry.v2.json') as f:
    schema = json.load(f)
Draft202012Validator.check_schema(schema)
print('OK')
"
```

Expected output: `OK`

### 2. Both v2 catalogue entries validate against the schema

```bash
python3 -c "
import json
from jsonschema import Draft202012Validator
with open('spec/schemas/act_catalogue_entry.v2.json') as f:
    schema = json.load(f)
validator = Draft202012Validator(schema)
for path in [
    'catalogue/acts/eu/nis2/art20/management_body_approval.v1.json',
    'catalogue/acts/eu/eudr/dds_preparation.v1.json',
]:
    with open(path) as f:
        entry = json.load(f)
    errors = list(validator.iter_errors(entry))
    assert not errors, f'{path}: {errors}'
    print(f'{path}: OK')
"
```

Expected output: two lines, each ending in `OK`.

### 3. Test vectors regenerate deterministically

```bash
python3 -m pip install jcs --upgrade

# Run twice, compare file hashes
python3 scripts/compute_test_vectors.py \
    catalogue/acts/eu/nis2/art20/management_body_approval.v1.json \
    scripts/test_vector_inputs/nis2_art20_v1_001.json \
    /tmp/nis2_v1_test.json

python3 scripts/compute_test_vectors.py \
    catalogue/acts/eu/nis2/art20/management_body_approval.v1.json \
    scripts/test_vector_inputs/nis2_art20_v1_001.json \
    /tmp/nis2_v2_test.json

diff /tmp/nis2_v1_test.json /tmp/nis2_v2_test.json && echo "DETERMINISTIC OK"
```

Expected output: `DETERMINISTIC OK`

Repeat the same check for the EUDR entry.

### 4. Test vectors match committed files

```bash
# Verify the committed test vector matches a fresh regeneration
python3 scripts/compute_test_vectors.py \
    catalogue/acts/eu/nis2/art20/management_body_approval.v1.json \
    scripts/test_vector_inputs/nis2_art20_v1_001.json \
    /tmp/freshly_generated.json

diff catalogue/acts/eu/nis2/art20/management_body_approval.v1.test_vectors.json /tmp/freshly_generated.json \
    && echo "TEST VECTOR MATCHES OK"
```

Expected output: `TEST VECTOR MATCHES OK`

If the diff produces output, the committed test vector is stale; regenerate before tagging.

### 5. Deprecated v1 entry is reachable for historical resolution

```bash
ls catalogue/acts/eu/nis2/art20/_deprecated/approval.json
ls catalogue/acts/eu/nis2/art20/_deprecated/README.md
```

Both files must exist. The deprecated v1 entry remains in the repo for namespace preservation.

### 6. No voting-derivative fields remain in v2 entries

```bash
grep -rn 'method_constraints\|tally_output_hash\|result_hash\|eligibility_snapshot_hash\|action_set_hash\|receipt_profile_recommendations' \
    catalogue/acts/ \
    --include='*.json' \
    --exclude-dir='_deprecated' \
    && echo "FAIL: voting derivatives found in v2 entries" \
    || echo "OK: no voting derivatives in v2 entries"
```

Expected output: `OK: no voting derivatives in v2 entries`

### 7. Spec references are consistent

```bash
# All v2 schema, catalogue entries, and test vector files referenced in the spec must exist
for path in \
    spec/schemas/act_catalogue_entry.v2.json \
    catalogue/acts/eu/nis2/art20/management_body_approval.v1.json \
    catalogue/acts/eu/eudr/dds_preparation.v1.json \
    catalogue/acts/eu/nis2/art20/management_body_approval.v1.test_vectors.json \
    catalogue/acts/eu/eudr/dds_preparation.v1.test_vectors.json \
    scripts/compute_test_vectors.py
do
    [ -f "$path" ] && echo "OK: $path" || echo "MISSING: $path"
done
```

Expected output: six lines, each starting with `OK`.

## Cutting the tag

After all pre-tag verifications pass, cut the tag:

```bash
git add -A
git commit -m "Batch A complete: v2 catalogue schema, NIS2 and EUDR v2 entries, spec, loader contract"

git tag -a v1.4-rc1 -m "v1.4-rc1: act-native catalogue entry schema v2

- New JSON Schema spec/schemas/act_catalogue_entry.v2.json
- NIS2 Article 20 management body approval v1 (op:eu.nis2.art20.management_body_approval.v1)
- EUDR DDS preparation v1 (op:eu.eudr.dds_preparation.v1)
- v1 NIS2 entry preserved in _deprecated/ for namespace continuity
- Deterministic test vectors via scripts/compute_test_vectors.py
- Spec v1.4-rc1 with SCITT alignment downgraded to 'aligned, COSE_Sign1 bridge planned'
- Witness recipient model formally defined
- eIDAS firewall: issuer_record MUST NOT be claimed as AES/QES
- Federation flagged as v1.5+ feature
- CATALOGUE_LOADER_CONTRACT.md cross-implementation contract

This is a pre-release candidate. v1.4 final lands with Quoruna v2.0.0."

git push origin main
git push origin v1.4-rc1
```

## Post-tag verification

After pushing the tag, confirm:

### 1. Tag exists on GitHub

Visit the repository's tags page and confirm `v1.4-rc1` appears with the full annotation message.

### 2. Tag is reachable as a release source

```bash
# Verify the tag can be checked out cleanly from a fresh clone
git clone <repo-url> /tmp/actproof-events-fresh
cd /tmp/actproof-events-fresh
git checkout v1.4-rc1
ls catalogue/acts/eu/nis2/art20/management_body_approval.v1.json
ls catalogue/acts/eu/eudr/dds_preparation.v1.json
ls spec/schemas/act_catalogue_entry.v2.json
```

All three files must exist at this tag.

### 3. Create the GitHub release (optional but recommended)

On the GitHub releases page, draft a new release from the `v1.4-rc1` tag. Mark it as a pre-release. Paste the release notes from the "Release notes" section below.

## Release notes (for GitHub release description)

```markdown
## v1.4-rc1 - Act-native substrate

Pre-release candidate. v1.4 final ships with Quoruna v2.0.0.

### Substrate changes

- New catalogue entry schema `actproof.act_catalogue_entry.v2` removes voting-derivative fields (method_constraints, tally_output_hash, result_hash, eligibility_snapshot_hash, action_set_hash, receipt_profile_recommendations).
- All three v1 catalogue entries moved under `_deprecated/` directories for namespace continuity:
  - `op:eu.nis2.art20.approval` (superseded by `op:eu.nis2.art20.management_body_approval.v1`)
  - `op:corporate.board.resolution.v1` (v2 successor deferred to v1.5)
  - `op:eu.ai_act.art26.risk_assessment` (v2 successor deferred to v1.5)
- Conforming loaders surface only v2 entries for new issuance and allow read-only access to v1 entries for historical attestation rendering.

### New catalogue entries

- `op:eu.nis2.art20.management_body_approval.v1` - NIS2 Article 20 management body approval of cybersecurity risk-management measures
- `op:eu.eudr.dds_preparation.v1` - EUDR Due Diligence Statement preparation

### Specification changes

- SCITT alignment downgraded from "reference implementation" to "aligned, COSE_Sign1 bridge planned" pending RFC 9943 publication
- Witness recipient model formally defined (Section 7)
- Approval evidence model section added with eIDAS firewall (Section 8): `issuer_record` MUST NOT be claimed as an Advanced Electronic Signature
- Federation flagged as v1.5+ feature; v2.0 implementations may defer without losing conformance
- Catalogue loader contract documented at `CATALOGUE_LOADER_CONTRACT.md`

### Tooling

- `scripts/compute_test_vectors.py`: deterministic test vector generator (RFC 8785 JCS canonicalization, SHA-256 hashing, ARC-2 JCS note composition)
- Reference test vectors for both new catalogue entries
- Conformance check is fully offline; verifier implementations can reproduce manifest_hash_hex, envelope_hash_hex, and arc2_note.full_note_b64 from the test vector inputs

### What's not in this release

- COSE_Sign1 wire-format bridge (v1.5)
- v2 versions of `op:corporate.board.resolution.v1` and `op:eu.ai_act.art26.risk_assessment` (v1.5)
- Federation namespace minting and resolution under `x.<reverse-dns>:` (v1.5)
- Multi-leaf Merkle batched anchoring (v2.0+)
- Real Algorand testnet `reference_anchor.txid` values in test vectors (pending; see "Outstanding work for v1.4 final")

### Outstanding work for v1.4 final

`reference_anchor.txid` in both test vector files is currently a placeholder. Before v1.4 final, anchor each test vector's `arc2_note.full_note_b64` (decoded to raw bytes) on Algorand testnet from any funded account, then populate the test vector's `txid`, `round`, `anchored_at`, and `anchoring_address` fields with the result. This enables verifier implementations to confirm byte-identical match against on-chain notes as part of their conformance check.

v1.4 final tag is cut simultaneously with the Quoruna v2.0.0 release tag in Batch E of the substrate pivot work.
```

## Acceptance criteria for Batch A

All seven steps of Batch A are complete when:

- [x] Step 1: v2 JSON Schema committed at `spec/schemas/act_catalogue_entry.v2.json` and validates against the draft 2020-12 meta-schema
- [x] Step 2: NIS2 v2 entry committed at `catalogue/acts/eu/nis2/art20/management_body_approval.v1.json` and validates against the v2 schema; `_deprecated/README.md` documents the migration
- [x] Step 3: EUDR DDS preparation v2 entry committed at `catalogue/acts/eu/eudr/dds_preparation.v1.json` and validates against the v2 schema
- [x] Step 4: `scripts/compute_test_vectors.py` is deterministic; test vectors for both entries committed and reproducible
- [x] Step 5: v1.4-rc1 spec committed at `spec/actproof-events.spec.md` with SCITT downgrade, federation deferral, witness recipient model section, and eIDAS firewall section
- [x] Step 6: `CATALOGUE_LOADER_CONTRACT.md` committed at the repository root
- [ ] Step 7: `v1.4-rc1` tag cut and pushed (this step)

After Step 7 ships, Batch A is closed. The next work begins in the Quoruna repository at Batch B.

## What comes after this tag

Batch B begins in the Quoruna repository:
- Database schema migration for the act-native model
- `catalogue_loader.py` implementing the contract documented here
- `routes_attest.py` for the issuer flow
- Five Jinja2 templates for the issuer surface

The actproof-events substrate is stable until v1.4 final. No further work is expected in this repository until the `reference_anchor` test vector population task and the synchronized v1.4 final tag.
