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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ bugs, broken examples, or unclear conformance requirements.
| [RFC-0007](rfcs/0007-audit-trail-and-evidence-set.md) | Audit Trail and Evidence Set | Draft |
| [RFC-0008](rfcs/0008-transport-boundary.md) | Transport Boundary | Draft |
| [RFC-0009](rfcs/0009-conformance-and-profiles.md) | Conformance and Profiles | Draft |
| [RFC-0010](rfcs/0010-packet-assembly-attestation.md) | Packet Assembly Attestation | Experimental Draft |

## HACP 0.2 Draft Status

Expand Down Expand Up @@ -391,6 +392,11 @@ executable candidate package:
- closed candidate schemas and computed vectors in
[schemas/v0.3-candidate/](schemas/v0.3-candidate/).

Packet-construction provenance is explored separately in
[RFC-0010](rfcs/0010-packet-assembly-attestation.md) and the
[experimental packet-assembly-attestation package](schemas/experimental/packet-assembly-attestation/v0.1-draft/README.md).
It does not modify or extend the published v0.3-candidate package.

Implementation-specific trial artefacts are not required to review this public
draft. The v0.3 candidate package includes bounded public evidence, conformance
fixtures, and an independent-implementation report. Future work may add other
Expand Down Expand Up @@ -531,6 +537,12 @@ v0.2 artefacts:
- [fixtures/happy-path/](fixtures/happy-path/)
- [fixtures/risk-cases/](fixtures/risk-cases/)

experimental future record families:

- [packet-assembly-attestation v0.1 draft](schemas/experimental/packet-assembly-attestation/v0.1-draft/README.md):
authenticated construction-claim shape, trust-bound validation harness, and
positive/negative fixtures. This is not part of HACP v0.3-candidate.

## Canonical Vocabulary Sources

The draft prose explains the contracts, but machine-readable vocabulary should
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"hacp:doctor": "node scripts/hacp-doctor.mjs",
"hacp:cli-bridge-examples": "node scripts/validate-cli-bridge-examples.mjs",
"hacp:v03-candidate": "node scripts/compute-vectors.mjs --check && node --test scripts/compute-vectors.test.mjs scripts/validate-external-bundle.test.mjs",
"hacp:v03-external": "node scripts/validate-external-bundle.mjs"
"hacp:v03-external": "node scripts/validate-external-bundle.mjs",
"hacp:packet-assembly-attestation": "node scripts/validate-packet-assembly-attestation.mjs --check && node --test scripts/validate-packet-assembly-attestation.test.mjs"
},
"dependencies": {
"ajv": "^8.17.1",
Expand Down
209 changes: 209 additions & 0 deletions rfcs/0010-packet-assembly-attestation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# RFC-0010: Packet Assembly Attestation

Status: Experimental Draft

Copyright (c) 2026 Joe Feser. Licensed under CC BY 4.0.

This draft uses normative keywords to express design intent. It is a separate,
experimental record family. It does not change, republish, or version-bump the
HACP v0.3-candidate schemas.

## Abstract

A packet digest preserves integrity after construction, but it does not answer
who assembled the packet or how that identity was authenticated. A Packet
Assembly Attestation binds an authenticated builder principal to a specific
construction claim: the exact packet digest, exact source revisions and
digests, construction profile, tool and runtime identities, construction time,
declared transformations, and limitations.

The record is an attestation. It is not proof that the packet was assembled
correctly, that its sources were authentic, that a human approved it, that a
runtime admitted it, or that an executor performed the work.

## Motivation

HACP v0.3-candidate task packets have domain-separated content digests and
source references. Those fields support integrity and interworking checks after
construction. They do not authenticate the builder. This is a real but
non-breaking limitation of the candidate package and does not invalidate its
current integrity, conformance, or WITS interworking evidence.

RFC-0001's base-draft `created_by` field is self-asserted artifact authorship.
It remains useful display metadata, but it is not authenticated construction
provenance. A bare `createdBy` or equivalent string MUST NOT satisfy this RFC.

## Roles

Implementations MUST keep these roles explicit and MUST NOT infer one from
another:

| Role | Responsibility |
| --- | --- |
| Builder or assembler | Constructs the packet from declared inputs. |
| Authorized human approver | Decides whether a bounded continuation may proceed. |
| Runtime issuer or admitter | Admits a continuation under an approved runtime profile. |
| Executor | Performs or attempts the authorized work. |

One principal MAY occupy more than one role, but each role still requires its
own applicable evidence. A builder signature is not human approval. Human
approval is not runtime admission. Runtime admission is not execution proof.

## Record

The experimental record kind is
`hacp.experimental.packet_assembly_attestation`. The draft schema version is
`hacp-packet-assembly-attestation-0.1-draft`.

The record MUST contain:

- a unique attestation identifier;
- an authenticated builder principal claim, authentication method,
verification-profile reference, and key identifier;
- the exact packet identifier, schema version, and digest;
- one or more exact source references, revisions, representations, and
digests;
- construction profile identity, version, reference, and digest;
- construction tool identity, version, and artifact digest;
- construction runtime identity, version, and artifact digest;
- construction time;
- declared transformations and their input/output references;
- declared limitations;
- a domain-separated claim digest;
- a cryptographic binding; and
- the required non-authority boundary statement.

The draft machine-readable contract is
[`schemas/experimental/packet-assembly-attestation/v0.1-draft/packet-assembly-attestation.schema.json`](../schemas/experimental/packet-assembly-attestation/v0.1-draft/packet-assembly-attestation.schema.json).

## Canonical Claim and Cryptographic Binding

The claim preimage is the complete top-level attestation record with
`claimDigest` and `cryptographicBinding` omitted. Producers MUST serialize the
following envelope with RFC 8785 JSON Canonicalization Scheme:

```json
{"domain":"io.hacp.packet-assembly-attestation-claim.v0.1-draft","record":{}}
```

`record` is the claim preimage described above. Producers MUST hash the UTF-8
envelope bytes with SHA-256 and place the lowercase hexadecimal result in
`claimDigest.value`. Producers MUST sign the same UTF-8 envelope bytes using
the declared cryptographic scheme. The initial draft fixture profile supports
Ed25519 only.

Digest equality proves integrity after construction. It does not establish
builder identity, source authenticity, correct interpretation, approval, or
execution authority. The signature shows that the holder of the corresponding
private key signed the construction claim. Builder authentication exists only
when an independently selected verification profile binds that key to the
declared principal and authentication method.

## Trust-Anchor Selection

The receiving owner system or an independently authorized verifier MUST select
the accepted verification profile and trust anchors. The attestation MUST NOT
select its own trust merely by naming a profile or key.

A verification profile claiming support for this record MUST define:

- admitted builder principals and authentication methods;
- key or certificate discovery and rotation;
- trust-anchor ownership and current status;
- revocation and expiry processing;
- algorithm policy;
- source revision and digest resolution policy;
- failure and audit behavior; and
- redaction rules for runtime or environment identity.

An unknown, expired, revoked, self-asserted, or otherwise unverifiable builder
MUST fail closed as `UNTRUSTED_BUILDER_PRINCIPAL`. A valid signature from an
untrusted key does not authenticate the builder.

## Verification

A verifier claiming this experimental profile MUST, in order:

1. validate the closed record shape;
2. recompute and compare the domain-separated claim digest;
3. resolve the builder principal, authentication method, and key through the
independently selected verification profile;
4. verify the cryptographic binding over the canonical claim envelope;
5. compare the exact packet identifier, schema version, and digest with the
packet under review; and
6. resolve each source revision and digest under the profile's source policy.

The experimental fixture harness uses these stable diagnostics:

| Code | Meaning |
| --- | --- |
| `SCHEMA_VALIDATION_FAILED` | The record is not the closed draft shape. |
| `CLAIM_DIGEST_MISMATCH` | The canonical construction claim changed. |
| `UNTRUSTED_BUILDER_PRINCIPAL` | No accepted profile binds the declared principal, method, and key. |
| `SIGNATURE_INVALID` | The cryptographic binding does not verify. |
| `PACKET_DIGEST_MISMATCH` | The attestation does not bind the exact packet under review. |
| `SOURCE_REVISION_MISMATCH` | A declared source revision differs from trusted resolution context. |
| `SOURCE_DIGEST_MISMATCH` | Resolved source bytes do not match the declared digest. |
| `CONSTRUCTION_ARTIFACT_MISMATCH` | A declared profile, tool, or runtime identity does not match resolved artifact bytes. |

Failure MUST NOT fall back to an unauthenticated `createdBy` value. It MUST NOT
activate approval, admission, execution, retry, or packet-reconstruction
authority.

## Correctness Boundary

Authenticated construction provenance remains an attestation, not proof that
the packet was correctly assembled. A conforming verifier can establish that a
trusted profile associates a principal with the signing key and that the exact
claim has not changed. It cannot establish, from this record alone, that:

- the builder selected every relevant source;
- a source was truthful or authoritative;
- the builder interpreted a source correctly;
- a declared transformation was semantically correct;
- the declared construction time came from a trusted timestamping authority;
- omitted context was irrelevant;
- the packet should be approved;
- a runtime should admit the packet; or
- any execution or external effect occurred.

Those judgments require separate evidence and, where consequential, an
authorized human decision.

## HACP v0.3-candidate Disposition

The absence of this record is a non-breaking HACP v0.3-candidate limitation. It
becomes a correctness defect only when an implementation claims that the
packet builder was authenticated or that correct packet construction was
proven without the required evidence.

This RFC and its experimental schema do not modify the v0.3-candidate task
packet or any of its digest domains, fixtures, manifests, or publication
evidence.

## Conformance Evidence

The experimental package includes positive signed fixtures for raw-byte,
Git-blob, and RFC 8785 canonical-JSON content digests, plus negative fixtures
for source-revision substitution, packet-digest mismatch,
self-asserted identity under an untrusted key, signature corruption, and
post-signature claim mutation. The included keys and identities are synthetic,
public test material and MUST NOT be trusted outside the fixture harness.

Run:

```bash
npm run hacp:packet-assembly-attestation
```

Passing the harness proves only that this implementation validates the bounded
fixture contract. It does not authenticate any production builder or promote
the record beyond experimental draft status.

## Open Questions

- Which authentication profiles should be standardized first: workload
identity, organizational signing keys, or another mechanism?
- How should source resolvers express repository-specific revision semantics?
- Should future profiles support threshold or transparency-log bindings?
- Which construction details require redaction while remaining auditable?
18 changes: 18 additions & 0 deletions schemas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Need to choose a concrete stop reason? See
- `https://hacp.example/schemas/v0.2-draft/`
- `https://hacp.example/schemas/v0.3-candidate/` for executable candidate
interworking contracts; exact digest domains remain owner review gates.
- `https://hacp.example/schemas/experimental/packet-assembly-attestation/v0.1-draft/`
for the separate experimental construction-provenance record family. This
deliberately non-routable identifier does not imply publication by hacp.io;
use the repository copy of the schema.

Versioning for future phases should preserve backward-readable draft history
rather than rewriting old identifiers.
Expand Down Expand Up @@ -101,6 +105,20 @@ Validate the generated candidate corpus with:
npm run hacp:v03-candidate
```

### Experimental Packet Assembly Attestation

- [record, fixtures, and explicit non-claims](experimental/packet-assembly-attestation/v0.1-draft/README.md)

Validate the separate experimental package with:

```bash
npm run hacp:packet-assembly-attestation
```

This record family does not change or version-bump HACP v0.3-candidate. Its
authenticated construction claim remains an attestation, not proof of correct
assembly, approval, runtime admission, or execution.

## Evidence Field Compatibility

The base RFCs require simple `evidence` arrays so the minimum contract stays
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Packet Assembly Attestation v0.1 Draft

Status: experimental draft record family. This directory is not part of the
HACP v0.3-candidate package and does not change that package's schemas, digest
domains, fixtures, or publication status.

The record authenticates a bounded construction claim when an independently
selected verification profile binds the declared builder principal and key. It
keeps the builder or assembler, authorized human approver, runtime issuer or
admitter, and executor as distinct roles.

It does not prove correct construction. It does not establish source
authenticity, approval, runtime admission, execution, completion, or external
effects. A bare `createdBy` string is insufficient.

## Validate

From the repository root:

```bash
npm ci
npm run hacp:packet-assembly-attestation
```

The validator checks the closed schema, RFC 8785 claim digest, Ed25519 fixture
signature, independently supplied synthetic trust binding, exact packet
binding, and source revision/digest resolution. Positive fixtures exercise
raw-byte, Git-blob, and RFC 8785 canonical-JSON representations for both source
and construction-artifact digests. All fixture identities and keys are public
test material with no production authority.

## Files

- `packet-assembly-attestation.schema.json`: closed experimental record shape.
- `fixtures/manifest.json`: exact expected valid and invalid outcomes.
- `fixtures/verification-context.json`: synthetic, independently supplied
builder trust and source-resolution context for the harness.
- `fixtures/construction/`: exact synthetic profile, tool, and runtime identity
descriptors bound by the valid attestation.
- `fixtures/valid/`: authenticated construction claims covering every declared
content-digest representation.
- `fixtures/invalid/`: source substitution, packet mismatch, self-asserted
identity, signature corruption, changed-claim, and construction-artifact
mismatch cases.

See [RFC-0010](../../../../rfcs/0010-packet-assembly-attestation.md) for trust,
verification, role-separation, and non-claim semantics.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"kind": "packet-assembly-construction-profile",
"id": "org.hacp.fixture.packet-assembly",
"version": "0.1-test",
"transformationPolicy": "select-declared-source-and-structure-bounded-fields",
"fixtureOnly": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"kind": "packet-assembly-runtime-identity",
"id": "nodejs-fixture-runtime",
"version": "24.14.0-test",
"fixtureOnly": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"kind": "packet-assembly-tool-identity",
"id": "fixture-packet-builder",
"version": "1.0.0-test",
"fixtureOnly": true
}
Loading