# Master Prompt: ACT Reference Implementation

## Context

You are implementing the reference implementation for the Agent Compact
Token (ACT), as defined in `draft-nennemann-act-00`. The full draft is
attached or provided in context. Your implementation must be a clean,
well-documented Python package that serves as the normative reference
for the specification — meaning it is the ground truth for
interoperability testing.

The ACS (Agent Compliance Seal) reference implementation (~1,900 lines,
Python) exists as a prior art reference for code style and structure.
ACT follows the same philosophy: minimal dependencies, sub-millisecond
performance for the hot path, Ed25519 as the primary algorithm.

---

## Deliverables

Produce the following files in a single `act/` package directory:

```
act/
├── __init__.py          # Public API exports
├── token.py             # ACTMandate and ACTRecord dataclasses + serialization
├── crypto.py            # Key management: Tier 1 (pre-shared), Tier 2 (PKI),
│                        #   Tier 3 (DID:key, DID:web); sign/verify primitives
├── lifecycle.py         # Phase 1 → Phase 2 transition logic (re-signing)
├── delegation.py        # Delegation chain construction and verification
├── dag.py               # DAG validation (uniqueness, parent existence,
│                        #   temporal ordering, acyclicity, capability
│                        #   consistency)
├── ledger.py            # In-memory append-only audit ledger (for testing;
│                        #   interface suitable for external backends)
├── verify.py            # Unified verification entry point (Phase 1 + Phase 2)
├── errors.py            # All ACT-specific exception types
└── vectors.py           # Generates and validates all Appendix B test vectors
tests/
├── test_token.py
├── test_crypto.py
├── test_lifecycle.py
├── test_delegation.py
├── test_dag.py
├── test_ledger.py
├── test_verify.py
└── test_vectors.py      # Must pass all vectors defined in vectors.py
```

---

## Specification Summary

### Token Structure

An ACT is a JWT (JWS Compact Serialization). It has two phases:

**Phase 1 — Authorization Mandate** (signed by issuing agent):

JOSE Header:
```json
{
  "alg": "EdDSA",       // Ed25519; also support ES256
  "typ": "act+jwt",
  "kid": "<key-id>"
  // optional: "x5c" (Tier 2), "did" (Tier 3)
}
```

Required JWT claims:
- `iss`  — issuer agent identifier (opaque string / X.509 DN / DID)
- `sub`  — target agent identifier (same format as iss)
- `aud`  — intended recipient(s); string or array
- `iat`  — issuance time (NumericDate)
- `exp`  — expiration time (NumericDate); SHOULD be iat + ≤900s for automated flows
- `jti`  — UUID v4; doubles as task identifier for DAG par references

Optional:
- `wid`  — workflow UUID grouping related ACTs

Required ACT-specific claims:
- `task` — object: { purpose (str, REQUIRED), data_sensitivity (str, OPTIONAL),
                     created_by (str, OPTIONAL), expires_at (NumericDate, OPTIONAL) }
- `cap`  — array of { action (str, REQUIRED), constraints (object, OPTIONAL) }
           action names conform to ABNF: component *("." component)
           component = ALPHA *(ALPHA / DIGIT / "-" / "_")
- `del`  — object: { depth (int), max_depth (int), chain (array) }
           chain entries: { delegator (str), jti (str), sig (base64url str) }
           chain is ordered root → immediate parent (chain[0] = root authority)
           If `del` is absent: treat as root mandate, depth=0, delegation forbidden

Optional:
- `oversight` — { requires_approval_for (array of action strings),
                  approval_ref (str, OPTIONAL) }

**Phase 2 — Execution Record** (re-signed by executing agent, i.e. `sub`):

All Phase 1 claims are preserved unchanged. Additional required claims:
- `exec_act` — string; MUST match one of the cap[].action values
- `par`       — array of jti strings (parent task IDs in DAG); [] for root tasks
- `exec_ts`   — NumericDate; actual execution time; MUST be >= iat; SHOULD be <= exp
               (if exec_ts > exp: log warning, do NOT reject)
- `status`    — one of: "completed", "failed", "partial"

Additional optional claims:
- `inp_hash`  — base64url(SHA-256(raw input bytes)), no padding
- `out_hash`  — base64url(SHA-256(raw output bytes)), no padding
- `err`       — { code (str), detail (str) }; present when status != "completed"

**Critical**: In Phase 2, the JOSE header `kid` MUST reference the `sub`
agent's key (not the `iss` agent's key). The re-signature is produced by
the executing agent over the complete Phase 2 payload (all Phase 1 claims
+ execution claims combined).

---

### Trust Tiers

**Tier 1 — Pre-Shared Keys (mandatory-to-implement)**
- Keys: Ed25519 (primary) or P-256
- `kid`: opaque string agreed out-of-band
- Key registry: a dict mapping kid → public key bytes, configured at init time
- No external resolution needed

**Tier 2 — PKI / X.509**
- `kid`: SHA-256 thumbprint of DER-encoded certificate
- `x5c` JOSE header MAY carry the certificate chain
- Verification: standard X.509 chain validation against trusted CA store

**Tier 3 — DID**
- Support `did:key` (self-contained, no resolution needed)
- Support `did:web` (requires HTTP resolution; cache with configurable TTL)
- `kid`: DID key fragment (e.g. `did:key:z6Mk...#key-1`)
- `did` JOSE header MAY carry the full DID for resolution

---

### Delegation Chain

When issuing a delegated ACT (Agent A → Agent B):

1. `del.depth` = parent ACT's `del.depth` + 1
2. `del.max_depth` ≤ parent ACT's `del.max_depth`
3. `cap` must be a subset of parent ACT's `cap` with constraints at least
   as restrictive
4. Each chain entry `sig` = Sign(A.private_key, SHA-256(parent_act_compact_bytes))
   where `parent_act_compact_bytes` is the raw bytes of the parent ACT's
   JWS Compact Serialization (UTF-8 encoded)

Verification of chain entry:
- Retrieve public key for entry.delegator
- Recompute SHA-256(parent_act_compact_bytes)
- Verify entry.sig against that hash using entry.delegator's public key

Rejection conditions:
- `del.depth` > `del.max_depth`
- `del.chain` length != `del.depth`
- Any chain entry sig fails verification
- `cap` contains actions not in parent ACT's `cap`
- Any constraint in `cap` is less restrictive than in parent ACT

---

### DAG Validation (Phase 2)

The ACT ledger (or set of received parent ACTs) is the ECT store.

Required checks on receiving a Phase 2 ACT:
1. `jti` uniqueness within `wid` scope (or globally if `wid` absent)
2. Every `jti` in `par` exists in the ledger/store as a verified Phase 2 ACT
3. For each parent: `parent.exec_ts < child.exec_ts + 30s` (clock skew tolerance)
4. No cycle: following `par` references must not return to current `jti`
   — enforce max traversal limit of 10,000 nodes
5. `exec_act` matches one of the `cap[].action` values in the Phase 1 claims

---

### Verification Procedure

**Phase 1 verification** (ACTVerifier.verify_mandate):
1. Parse JWS Compact Serialization
2. Check `typ` == "act+jwt"
3. Check `alg` in allowlist (must include EdDSA/Ed25519, ES256; MUST NOT include
   "none" or any HS* algorithm)
4. Resolve public key for `kid` per trust tier
5. Verify JWS signature
6. Check `exp` not passed (clock skew tolerance: ≤300s)
7. Check `iat` not unreasonably future (≤30s ahead)
8. Check `aud` contains verifier's own identifier
9. Check `iss` is trusted per local policy
10. Check `sub` matches verifier's own identifier (when verifier is the target)
11. Check all required claims present and well-formed
12. If `del.chain` non-empty: verify delegation chain

**Phase 2 verification** (ACTVerifier.verify_record):
All Phase 1 steps, plus:
13. Check `exec_act` present and matches a `cap[].action`
14. Check `par` present; perform DAG validation
15. Check `exec_ts` present and >= `iat`; if > `exp` log warning but do NOT reject
16. Check `status` present and valid
17. Check re-signature was produced by `sub` agent's key (kid in Phase 2
    header must correspond to sub's public key, not iss's key)
18. Optionally verify `inp_hash`/`out_hash` against provided data

---

### Audit Ledger Interface

`ACTLedger` (in-memory reference implementation):
- `append(act_record: ACTRecord) -> int` — returns sequence number
- `get(jti: str) -> ACTRecord | None`
- `list(wid: str | None) -> list[ACTRecord]`
- `verify_integrity() -> bool` — verifies no records have been tampered with
  (hash-chain over sequence-ordered records)

The ledger must enforce append-only semantics: once appended, a record
cannot be modified or deleted. Raise `ACTLedgerImmutabilityError` on
any attempt.

---

### Error Types

Define in `errors.py`:
```python
ACTError                        # base
ACTValidationError              # malformed token structure
ACTSignatureError               # signature verification failed
ACTExpiredError                 # token expired
ACTAudienceMismatchError        # aud does not contain verifier identity
ACTCapabilityError              # no matching capability / capability escalation
ACTDelegationError              # delegation chain invalid
ACTDAGError                     # DAG validation failed (cycle, missing parent, etc.)
ACTPhaseError                   # wrong phase for operation (e.g. mandate used as record)
ACTKeyResolutionError           # cannot resolve kid to public key
ACTLedgerImmutabilityError      # attempt to modify ledger
ACTPrivilegeEscalationError     # delegated cap exceeds parent cap
```

---

### Test Vectors (Appendix B)

`vectors.py` must generate and validate all of the following. Each vector
must include: description, input parameters, expected output (encoded token
or expected exception class).

**Valid vectors:**
- B.1: Phase 1 ACT — root mandate, Tier 1 (Ed25519 pre-shared key), no delegation
- B.2: Phase 2 ACT — completed execution, transition from B.1 mandate
- B.3: Phase 2 ACT — fan-in, two parent jti values from parallel branches
- B.4: Phase 1 ACT — delegated mandate (depth=1), chain entry with sig
- B.5: Phase 2 ACT — delegated execution record

**Invalid vectors (must raise specified exception):**
- B.6:  `del.depth` > `del.max_depth`                → ACTDelegationError
- B.7:  `cap` escalation in delegated ACT             → ACTPrivilegeEscalationError
- B.8:  `exec_act` not in `cap`                       → ACTCapabilityError
- B.9:  DAG cycle (par references own jti)            → ACTDAGError
- B.10: Missing parent jti in DAG                     → ACTDAGError
- B.11: Tampered payload (bit flip in claims)         → ACTSignatureError
- B.12: Expired token                                 → ACTExpiredError
- B.13: Wrong audience                                → ACTAudienceMismatchError
- B.14: Phase 2 re-signed by iss key instead of sub  → ACTSignatureError
- B.15: Algorithm "none"                              → ACTValidationError

---

## Implementation Constraints

**Dependencies**: use only the Python standard library plus:
- `cryptography` (for Ed25519, P-256, X.509)
- `pyjwt` OR manual JWS implementation (prefer manual for spec fidelity)
- `pytest` (test runner only)

**Performance target**: Phase 1 creation ≤ 500µs mean on modern hardware.
Benchmark in a `bench/` directory.

**Code style**:
- Type-annotated throughout (Python 3.11+)
- Dataclasses for token structures
- No global mutable state
- All public API functions documented with docstrings referencing the
  relevant draft section (e.g. `# ACT §8.1`)

**Security constraints**:
- MUST NOT use symmetric algorithms (HS256 etc.) anywhere
- MUST NOT implement "alg: none" path
- Ed25519 signing MUST use bound key-pair APIs (private key object that
  carries the public key) — never pass raw private key bytes
- All secret key material must be zeroed on deletion where the
  cryptography library supports it

**What NOT to implement**:
- DID:web resolution with live HTTP calls in the reference implementation
  (stub it with a configurable resolver callback instead)
- Token revocation infrastructure
- Persistence (ledger is in-memory only)

---

## Output Format

Produce each file completely, in order. After all files, produce a
`README.md` for the `act/` package that includes:
- Installation instructions
- Quick-start example (Phase 1 mandate → Phase 2 record → verify)
- Running the test suite
- Running the test vectors
- Performance benchmark instructions

At the end, confirm: "All Appendix B test vectors pass."
