> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cowboy.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# Cip 33 actor hiring and distribution

# CIP-33: Actor Hiring & Distribution

| Field           | Value                                                                                                                |
| --------------- | -------------------------------------------------------------------------------------------------------------------- |
| **CIP**         | 33                                                                                                                   |
| **Title**       | Actor Hiring & Distribution (Trading Post)                                                                           |
| **Status**      | Draft                                                                                                                |
| **Type**        | Standards Track (System Actor)                                                                                       |
| **Created**     | 2026-05-01                                                                                                           |
| **Author(s)**   | Cowboy Foundation                                                                                                    |
| **Depends-on**  | CIP-2 (off-chain compute), CIP-5 (timers), CIP-8 (MPP sessions), CIP-9 (CBFS/RAS),                                   |
| ..              | CIP-12 (governance & system actors), CIP-13 (runner delegation/reputation), CIP-20 (fungible tokens), CIP-24 (CBSS), |
| ..              | CIP-29 (event hooks)                                                                                                 |
| **Relates-to**  | CIP-27 (actor fork — per-hire instance isolation, optional), CIP-7 (key-delivery precedent)                          |
| **Required-by** | General Store product spec (app-layer; not a CIP)                                                                    |

## Abstract

This CIP defines the protocol rails for **hiring actors**: how an actor declares
itself hireable, how creators grant **stores** the right to distribute it, how
hire payments execute **declared fee splits**, how **review attestations** bind
reviewer identities to exact code snapshots, and how access to private actor
code is enforced through **CBSS key leases** rather than consensus changes.

The rails are **store-neutral**. Any party may operate a store; no store —
including the one operated by Cowboy Labs — holds protocol privileges. Direct
hiring with no store in the loop is a first-class path. The protocol specifies
the *mechanics* of publishing, hiring, splitting, and attesting; it is silent
on review policy, curation, and commission rates, which are store-level
products.

All state and logic live in one governance-controlled system actor, the
**Trading Post**.

## 1. Motivation

### 1.1 Store mechanics belong in the protocol; stores do not

An agent marketplace needs five mechanics no single app should own:

1. **Hireability** — a machine-readable statement that an actor can be hired,
   under what terms, by humans and by other actors.
2. **Distribution rights** — creator-controlled authorization for a store to
   sell access to the actor.
3. **Fee splits** — hire revenue divided among creator, store, and referrers
   exactly as declared, atomically with payment.
4. **Attestation** — verifiable review verdicts bound to exact code snapshots,
   so trust survives redistribution.
5. **Enforcement** — for private-code actors, access that can be granted,
   metered, and revoked without trusting the storefront.

Baking a *particular store* into consensus would freeze product policy into
protocol and contradict the permissionless premise: anyone can deploy an
actor, so anyone must be able to distribute one. Conversely, leaving these
mechanics to apps reproduces the Ethereum royalty failure: splits and
revocation become conventions that any marketplace can ignore.

The resolution is rails-in-protocol, stores-as-apps. The differentiating
consequence: **actors hire actors** through the same rails humans use, making
every published actor a capability available to every other actor.

### 1.2 Why enforcement needs no consensus changes

For private-code actors, the code volume is encrypted (CIP-9). An instance can
only execute if the data encryption key (DEK) reaches the executing runner.
Key delivery already flows through CBSS (CIP-24) under chain-state-conditioned
policy (CIP-7 precedent). Gating share issuance on hire/lease state in the
Trading Post therefore gives cryptographic enforcement of paid access —
a decryption monopoly rather than a distribution monopoly — using machinery
that exists today. Fee capture and IP protection are the same mechanism.

### 1.3 Design principles

* **Neutrality.** No privileged store. Store registration is open. The
  Trading Post grants every store identical powers, scoped to its own grants.
* **Creator sovereignty.** Creators decide which stores may distribute their
  actors. Grants are non-exclusive by default and revocable.
* **Direct hire is first-class.** A hire with no store involved MUST work; a
  store is a discovery and trust layer, never a tollbooth.
* **Enforce by cryptography and settlement, not consensus.** Leases gate key
  delivery; the Trading Post gates payment flows. Validators are unmodified.
* **Policy is replaceable.** Review standards, curation, pricing of trust —
  all app-layer. The protocol records outcomes (attestations), not opinions.

## 2. Specification

### 2.1 The Trading Post system actor

The Trading Post is a system actor deployed at genesis at the well-known address `0x1E` (`TRADING_POST_SYSTEM_ACTOR`), upgradeable
only through CIP-12. It holds all hiring state and executes all hiring flows
as ordinary actor methods. All monetary amounts are u128 wei (1 CBY = 10^9
wei) or CIP-20 token base units.

State objects (canonical encodings follow the conventions of CIP-20 state):

```
HireableDeclaration {
  declaration_id:  Hash,             // caller-supplied: H(creator ‖ actor ‖ salt); §2.1.1
  actor:           Address,          // the hireable actor
  creator:         Address,          // payout + grant authority
  badges:          { human_hireable: bool, agent_hireable: bool },
  latest_version:  u32,
  status:          Active | Retired,
}

DeclarationVersion {                 // append-only under a declaration; never edited in place
  version:           u32,            // 1.. , assigned sequentially
  manifest_root:     Hash,           // CBFS manifest root of the code at this version (CIP-9)
  code_visibility:   Public | Private,
  capability_schema: VolumePath,     // CBFS path to capability document (§2.6)
  terms:             [PricingTerm],  // §2.4
  default_split:     SplitVector,    // §2.3, used for direct hire
}

ServingArtifact {                    // a concrete volume carrying a version's code
  artifact_id:    u32,               // 0 = the creator's own volume, created with the version
  declaration_id: Hash,
  version:        u32,
  store_id:       Option<u64>,       // None for artifact 0; the registering store otherwise
  volume_id:      VolumeId,
  claimed_root:   Hash,              // MUST equal the version's manifest_root (a claim — §2.5.1, §4)
  registered_by:  Address,           // creator (artifact 0) or the store's operator
  ibe_ciphertext: Bytes,             // volume DEK under the artifact's IBE label (§2.5.1); Private only
  status:         Active | Retired,  // Retired = no new hires may pin it; pinned hires unaffected
}

StoreRecord {
  store_id:    u64,
  operator:    Address,              // store's signing/treasury address
  metadata:    VolumePath,           // name, policy URI, branding
  status:      Active | Retired,
}

DistributionGrant {
  grant_id:          u64,
  declaration_id:    Hash,           // grants are declaration-scoped; hires pin versions
  store_id:          u64,
  split:             SplitVector,    // agreed split incl. store commission
  max_referral_bps:  u16,            // ≤ the store's own share; referral entries draw from it (§2.3)
  lease_epoch_blocks:u64,            // §2.5; creator-set, per grant
  status:            Active | Revoked,
}

Hire {
  hire_id:        u64,
  declaration_id: Hash,
  version:        u32,               // pinned at hire time; root swaps never affect live hires
  artifact_id:    u32,               // pinned serving artifact this hire runs (§2.2)
  grant_id:       Option<u64>,       // None = direct hire
  hirer:          Address,           // payer; human account or hiring actor
  hire_block:     BlockHeight,       // anchors lease-epoch numbering (§2.5.1)
  term:           PricingTerm,       // selected at hire time
  split:          SplitVector,       // pinned copy (grant/default split + referral entry, §2.3)
  prepaid:        u128,              // balance held by the Trading Post (§2.4); funds renewals
  reserved:       u128,              // portion of prepaid committed to open PerCall sessions (§2.6.3)
  renewal_on:     bool,              // hirer-controlled via set_renewal; renew() no-ops when false
  paid_through:   BlockHeight,       // subscription horizon; ∞ for one-shot; unused for PerCall
  status:         Active | Paused | Revoked | Lapsed,
}

Attestation {
  attester:      Address,
  manifest_root: Hash,
  verdict:       Approved | Rejected | Flagged,
  policy_uri:    VolumePath,         // the policy the verdict was issued under
  issued_at:     BlockHeight,
}
```

#### 2.1.1 Declaration identity

`declaration_id = H(creator ‖ actor ‖ salt)` with a caller-chosen salt
supplied to `declare`, which recomputes and verifies the hash. Ids are
therefore known to the creator **before** the declaration exists, so CBSS
escrow ciphertexts (whose IBE labels embed the id, §2.5.1) can be produced
client-side in one step — no draft/activate round-trip — and nobody can squat
an id bound to another creator.

#### 2.1.2 Methods

Each method emits a CIP-29 event named for the transition.

| Method                                                                                       | Caller                                                                                                                           | Effect                                                                                                                                                                                                                                                                                                                                                                                                                             |
| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `declare(declaration_id, salt, actor, badges, v1: DeclarationVersion fields + escrow)`       | creator                                                                                                                          | verify id (§2.1.1); create declaration with version 1 and its artifact 0                                                                                                                                                                                                                                                                                                                                                           |
| `declare_version(declaration_id, fields + escrow)`                                           | creator                                                                                                                          | append `latest_version + 1` with its artifact 0; existing hires keep their pinned version                                                                                                                                                                                                                                                                                                                                          |
| `retire_declaration(id)`                                                                     | creator                                                                                                                          | stop new hires; existing hires honored per §2.4                                                                                                                                                                                                                                                                                                                                                                                    |
| `register_store(...)`                                                                        | anyone                                                                                                                           | open registration; creates `StoreRecord`                                                                                                                                                                                                                                                                                                                                                                                           |
| `grant(declaration, store, split, max_referral_bps, lease_epoch_blocks)`                     | creator                                                                                                                          | create `DistributionGrant`                                                                                                                                                                                                                                                                                                                                                                                                         |
| `revoke_grant(id)`                                                                           | creator                                                                                                                          | stop new hires via this grant; existing hires honored per §2.4                                                                                                                                                                                                                                                                                                                                                                     |
| `register_artifact(store_id, declaration, version, volume_id, claimed_root, ibe_ciphertext)` | the store's operator, with an active grant on the declaration                                                                    | register a serving copy (e.g., a reviewed snapshot) it hosts; invariant: at most one `Active` artifact per `(store_id, declaration, version)` — registering another requires retiring the first                                                                                                                                                                                                                                    |
| `retire_artifact(declaration, version, artifact_id)`                                         | the artifact's registering store                                                                                                 | stop new hires pinning it; existing hires and their escrow are unaffected                                                                                                                                                                                                                                                                                                                                                          |
| `hire(declaration, version?, grant?, term, referral?, payment)`                              | hirer (human account or actor)                                                                                                   | pin version (default: latest), artifact (§2.2 — granted hires REQUIRE the granting store's Active artifact for that version, else the call is rejected), and split; validate referral (§2.3); execute split for the first period (paid terms); surplus payment credits `prepaid`; create `Hire`; initialize lease (§2.5, Private only)                                                                                             |
| `deposit(hire, payment)`                                                                     | anyone                                                                                                                           | credit the hire's `prepaid` balance                                                                                                                                                                                                                                                                                                                                                                                                |
| `withdraw_unused(hire)`                                                                      | hirer                                                                                                                            | refund available balance (`prepaid − reserved`) not consumed by the current period                                                                                                                                                                                                                                                                                                                                                 |
| `renew(hire)`                                                                                | anyone (typically a CIP-5 timer)                                                                                                 | deterministic and boundary-gated: no-op (silent, no state change, no event) before the period boundary, when `renewal_on = false`, or when the hire status is `Paused`; errors on a `Revoked` hire; otherwise draws the period price from available balance only and executes the pinned split; insufficient available balance → status `Lapsed` (re-activatable by `deposit` + `renew` while declaration and grant remain Active) |
| `set_renewal(hire, on)`                                                                      | hirer                                                                                                                            | toggle `renewal_on`; turning it off plus `withdraw_unused` is cancellation — current period honored; third-party `deposit`/`renew` cannot reactivate a hire whose hirer turned renewal off                                                                                                                                                                                                                                         |
| `pause(hire)` / `resume(hire)` / `revoke_hire(hire)`                                         | the grant's store, for hires routed through that grant; the creator, for direct hires with `Free` or `PerCall` terms only (§2.4) | trust-and-safety lifecycle control (§2.4, §2.5.3); `revoke_hire` auto-refunds the hire's available balance to the hirer                                                                                                                                                                                                                                                                                                            |
| `settle_per_call(hire, session_receipt)`                                                     | hired actor or hirer                                                                                                             | settle accumulated `PerCall` usage from `reserved` per the CIP-8 receipt (§2.6.3)                                                                                                                                                                                                                                                                                                                                                  |
| `attest(manifest_root, verdict, policy_uri)`                                                 | anyone                                                                                                                           | record `Attestation` (trust is client-side, §2.7)                                                                                                                                                                                                                                                                                                                                                                                  |

Read surface (read-only methods, callable in-PVM via `call()` and exposed
over node RPC / the indexer for off-chain readers): `get_declaration(id)`,
`get_version(id, v)`, `list_artifacts(id, v)`, `get_grant(id)`,
`get_hire(id)`, `list_grants(declaration)`, `list_attestations(manifest_root)`.

Neutrality invariant: there is no method by which any party other than (a) the
creator, for their own declarations, versions, and grants, (b) a store, for
artifacts it registers under its own active grant and for hires routed through
its own grants, or (c) the hirer, for their own hire's funds and renewal
choices, can alter hiring state. The Trading Post's governance authority
(CIP-12) can upgrade code but holds no day-one operational powers over
individual listings.

### 2.2 Direct hire and artifact pinning

`hire(declaration, grant = None, ...)` settles against the pinned version's
`default_split` (typically 100% creator) and initializes the lease with the
protocol default `lease_epoch_blocks = 1800`. Stores MUST NOT be required for
any flow in this CIP. Direct-hire pause/resume/revoke is creator-controlled
under the restricted rule of §2.4 (`Free`/`PerCall` terms only).

Artifact pinning at hire: a granted hire MUST pin the granting store's
`Active` artifact for the pinned version (unique per §2.1.2's
one-Active-artifact invariant, so selection is deterministic) — if the store
has registered none, the hire is rejected. Falling back to the creator's artifact
0 is **direct-hire only**: a store-routed hire that silently served
unreviewed creator-volume code would carry the store's trust without the
store's review. The pinned artifact is the only volume the hire's instances
run and the only escrow the lease will service (§2.5.1).

### 2.3 Split vectors

```
SplitVector = [ (beneficiary: Address, share_bps: u16) ]   // Σ share_bps = 10_000
```

* Validated at `declare`/`declare_version`/`grant` time: shares sum to
  exactly 10,000 bps; max 8 entries; no zero-share entries.
* **Pinned at hire.** The effective vector (grant or default split, plus any
  referral entry) is copied into the `Hire` and every subsequent `renew` and
  `settle_per_call` settles against the pinned copy. Editing a grant's split
  affects only future hires.
* Executed atomically inside `hire`/`renew`/`settle_per_call`: the Trading
  Post receives or draws the payment (CBY or a CIP-20 token named in the
  term) and transfers each beneficiary's share in the same method execution.
  Rounding dust (the remainder after integer division) accrues to the first
  entry (by convention, the creator).
* **Settlement is direct ledger movement.** Trading Post transfers mutate
  balances directly and do NOT invoke CIP-20 transfer hooks — a multi-leg
  split must not be abortable or reenterable by a beneficiary's hook. Hook
  semantics consequently do not fire on hire settlement; tokens whose
  economics depend on transfer hooks should not be offered as pricing
  denominations. Standard CIP-20 transfer events ARE emitted per leg, so
  indexers observe every movement. A settlement fails closed as a whole if
  any participant's token account is frozen.
* **Referral and creator codes are not a mechanism.** At hire time the client
  MAY append at most one referral entry of up to the grant's
  `max_referral_bps`, deducted exclusively from the store's share; the pinned
  vector still sums to 10,000. The protocol has no opinion about what codes
  mean.
* The protocol itself takes **no cut**. Chain revenue from hiring is gas and
  compute, as for any other actor activity.

### 2.4 Pricing terms

```
PricingTerm =
  | OneShot      { price, token }                   // perpetual access; survives retirement (below)
  | Subscription { price, period_blocks, token }    // paid_through advances per renewal
  | PerCall      { price_per_call, token }          // metered via MPP session (§2.6.3)
  | Free
```

`token` names the denomination (native CBY or a CIP-20 token); all amounts
are u128 base units.

**Prepaid balances fund renewals.** No method ever pulls from a hirer's
wallet or actor balance: money enters a hire only as an explicit payment
attached to `hire` or `deposit`. `renew` draws each period's price from the
hire's available balance at the period boundary — callable by anyone, typically a
CIP-5 timer, since its effect is deterministic and boundary-gated.
Insufficient available balance → `Lapsed` (lease stops; recoverable by
`deposit` + `renew` while declaration and grant remain Active). Available
balance is `prepaid − reserved`; `withdraw_unused` returns it to the hirer at
any time, and cancellation is `set_renewal(false)` + `withdraw_unused` — the
current period stays honored.

Term semantics:

* **OneShot** sets `paid_through = ∞` and **survives retirement**: the
  creator's escrow and serving obligation for already-sold one-shot hires is
  perpetual. Creators who want a sunset path MUST price as `Subscription`.
* **Subscription** advances `paid_through` by `period_blocks` per successful
  `renew`.
* **PerCall** ignores `paid_through`; validity is an open, funded MPP session
  (§2.6.3), where "funded" means the session's reservation is covered by
  `reserved`. Reservations move balance from available to `reserved` at
  session open and release at settlement or session close, so
  `withdraw_unused` can never strand an open session.
* **Free** carries no money; validity is simply declaration ∧ grant (if any)
  ∧ hire all `Active`. `Private + Free` is legitimate (e.g., a free private
  beta).

**Consumer protection (creator-side actions).** `retire_declaration` and
`revoke_grant` stop *new* hires but MUST NOT strand paid time — existing
hires remain serviceable (lease shares keep issuing, §2.5) until
`paid_through`, indefinitely for OneShot. A creator cannot rug active
subscribers; they can only decline future renewals.

**Trust-and-safety actions (store-side)** are the deliberate exception:
`pause` and `revoke_hire` MAY stop service inside paid time (§2.5.2–2.5.3).
On `revoke_hire` the Trading Post auto-refunds the hire's available balance
to the hirer. Funds already split for the in-progress period are not clawed
back at the protocol level — per-period escrow of executed splits is
complexity v1 deliberately omits (Open Questions); compensating the
in-progress period is store-level policy. Stated honestly: a store revoking a
`OneShot` hire strands the hirer's perpetual access with no protocol remedy
beyond the (typically zero) available-balance refund — clients SHOULD weight
store trust accordingly, and stores compete on their published compensation
policy.

**Creator-side direct hires get no such exception.** For direct hires, the
creator may `pause`/`revoke_hire` only `Free` and `PerCall` terms (nothing
prepaid is stranded; reservations settle first). Paid `Subscription` and
`OneShot` direct hires are not creator-revocable at all — the creator's exit
is declining renewal (`retire_declaration`); refusing an abusive hirer is the
actor's own application logic, not a protocol power that doubles as a rug.

### 2.5 Key leases (private-code actors)

#### 2.5.1 Mechanism

For `code_visibility = Private`, every `ServingArtifact` carries an escrow:
the registrant (creator for artifact 0, store for snapshot artifacts)
encrypts that volume's DEK under the CBSS committee IBE public key (CIP-24)
to the identity label

```
tradingpost/{declaration_id}/{version}/{artifact_id}
```

and stores the ciphertext in the artifact record. Labels embed ids known
client-side before submission (§2.1.1), so escrow is produced in one step.
No per-epoch ciphertexts are required. `claimed_root` asserts the artifact
carries exactly the version's `manifest_root`; the assertion is signed state
from the registrant — accountability, not proof (§4).

`cbssd` enforces an **issuance policy** (chain-state-conditioned, as for
CIP-7 stream keys). An issuance request carries `(runner_id, job_id,
hire_id)`. Shares for the hire's pinned artifact label are issued iff, per
node RPC at the current block:

```
job(job_id) is assigned to runner_id
  ∧ job(job_id) is bound to (hire_id, pinned artifact)   // job metadata, set at dispatch
  ∧ Hire(hire_id).status == Active
  ∧ term validity:  Subscription | OneShot → current_block ≤ paid_through
                    PerCall              → bound MPP session open ∧ funded (§2.4, §2.6.3)
                    Free                 → declaration ∧ grant (if any) Active (§2.4)
```

Shares are issued at most once per `(hire, runner, lease_epoch)`; the policy
is re-evaluated at every lease-epoch boundary
(`lease_epoch = (block − hire_block) / lease_epoch_blocks`). The node MUST
expose the job-assignment and hire-binding query this predicate reads.

`lease_epoch_blocks` is creator-set per grant (default **1800 blocks ≈ 30
min** at the 1 s minimum block interval; recommended range 900–3600). It is
independent of consensus epochs (none exist; `EPOCH_LENGTH = u64::MAX`) and
of CBFS rent epochs.

#### 2.5.2 Revocation latency

Two layers:

* **Fast path (seconds):** runners MUST subscribe to Trading Post lifecycle
  events (CIP-29 via indexer feed) and stop accepting/continuing jobs for a
  hire upon observing `pause`/`revoke_hire`. This is a runner-policy
  requirement tied to reputation/slashing (CIP-2), not consensus.
* **Cryptographic backstop (≤ one lease epoch):** share issuance stops at the
  next lease-epoch boundary regardless of runner behavior.

#### 2.5.3 Residual risk — cached DEKs

A runner that has lawfully decrypted during epoch *k* may cache the DEK and
compute beyond revocation. This is accepted and bounded: such execution earns
nothing — `cbssd` issues no further shares, the Trading Post refuses
settlement for non-Active hires, and job results for revoked hires are
rejected in the existing runner settlement flow. The penalty surface is the
runner's stake and reputation (CIP-2, CIP-13). Hardening via per-epoch
re-wrapping labels is an upgrade path (Open Questions) and deliberately out
of v1.

Pause powers are correspondingly honest: a store can pause **what it
distributed** — future scheduling and key issuance — not reach into runners'
memory, and not touch the actor itself or hires routed through other stores.

### 2.6 Agent hire

The differentiating flow: a hiring **actor** assembles capabilities at
runtime.

#### 2.6.1 Capability schema

`capability_schema` points to a CBFS-hosted JSON document, content-addressed
by the version's `manifest_root`, describing: methods exposed to hirers
(names, JSON-Schema parameter/result types), supported `PricingTerm`s, runner
requirements (models, mounts), and rate limits. The schema document format is
versioned (`"cip33_schema": 1`); evolution happens by document version, not
protocol change.

#### 2.6.2 Discovery and hire

Hiring actors query listings either off-chain (their runner consults an
indexer during a CIP-2 job and passes candidates into actor logic) or
on-chain (`call()` into the read surface, §2.1.2). The hire itself is an
ordinary in-PVM flow: the hiring actor `call()`s `hire(...)` transferring
payment via CIP-20/CBY syscalls — no new host functions.

#### 2.6.3 Metered usage

`PerCall` terms meter over an MPP session (CIP-8) bound to `(hire_id,
version)`, with per-call price from the pinned term. Session open moves the
session's reservation from available balance into `reserved` ("funded" in
§2.5.1 means the reservation covers it). Settlement is explicit:
`settle_per_call(hire, session_receipt)` — the receipt is the CIP-8
session-close statement (bilaterally signed call count/amount) — draws the
settled amount from `reserved`, releases the remainder to available, and
executes the hire's pinned split. Disputes follow the CIP-8 session dispute
path and the CIP-2 result-dispute window; the Trading Post accepts only
receipts that validate against the session's binding. Receipt validation is
**fail-closed**: a receipt that cannot be fully verified — including when the
implementation has no signature-verifying validator deployed — MUST be
rejected, never settled. Settlement ordering is likewise fail-closed as a
whole (§2.3): `settle_per_call` MUST validate and debit the settled amount
from `reserved` **before** any beneficiary payout, so an over-settle
(`settled` exceeding the reservation) aborts with no partial transfers.
Subscription terms require no session.

#### 2.6.4 Instances

v1 instance model is **shared-actor, hire-scoped state**: the hired actor
serves all hires, partitioning state and (where needed) per-hire private
volumes keyed by `hire_id`; per-user volume provisioning is performed by the
creator's runner flow (CIP-2/CIP-9), since no in-actor deploy syscall exists.
Instances execute the hire's pinned artifact only (§2.2). When CIP-27 (fork)
lands, declarations MAY set `instance_mode: Forked` for hard isolation — one
forked actor per hire; the Trading Post then records the fork address in the
`Hire`. Nothing else in this CIP changes between modes.

### 2.7 Attestations

Attestation records bind `(attester, manifest_root, verdict, policy_uri)`.
Properties:

* Open: any address may attest; there is no attester registry to gatekeep.
  Trust is a **client** decision — wallets, dashboards, and stores choose
  which attesters to honor and how to render unattested code (e.g.,
  Android-style friction). The protocol ranks nothing. Spam is bounded, not
  policed: implementations MUST bound per-root index growth by one of two
  means — (a) storage-proportional gas per record written plus paginated
  reads (`list_attestations` serves pages), or (b) a hard cap on distinct
  attesters per root, under which whole-list reads are acceptable and
  supersession by an already-listed attester MUST still succeed at the cap,
  so a full index can never block an attester from downgrading a prior
  verdict.
* Bound to exact roots: an attestation never carries to a new
  `manifest_root`. Re-review is a new attestation.
* Append-only with supersession: records are never deleted; the **effective
  verdict** for `(attester, manifest_root)` is the latest record, so an
  attester can downgrade a prior `Approved` to `Flagged` or `Rejected`.
  `Flagged` is advisory — clients SHOULD surface it prominently; it gates
  nothing protocol-side.
* Cowboy Labs' review organization is simply one attester, whose verdicts the
  flagship store and first-party clients choose to require.

### 2.8 Events

Every state transition in §2.1 emits a named CIP-29 event carrying the
affected ids and (for lifecycle transitions) the acting party. Store-initiated
`pause`/`revoke_hire` events are thereby publicly auditable; the
"platform can pause apps" power is exactly as visible as it is real.

## 3. Economics and neutrality

The Trading Post charges nothing beyond gas. Store commission is a market
price set per grant; competing stores may undercut it; creators may multi-home
across stores or sell direct. The chain's revenue from a thriving hire economy
is store-agnostic: every hire's execution buys compute and gas regardless of
which storefront brokered it. This is deliberate — the protocol's take is on
*computation*, the unforkable layer, while distribution remains contestable.

## 4. Security considerations

* **Trading Post as high-value target.** It custodies split execution and
  lease state. Mitigations: CIP-12 upgrade governance, no operational
  superpowers to abuse (§2.1 neutrality invariant), splits executed by simple
  arithmetic over validated vectors, and the actor-model's single-threaded
  method execution (no reentrancy across a split's transfers; token transfers
  are CIP-20 syscalls inside one method execution).
* **Grant/declaration forgery.** All mutating methods authenticate the caller
  against the object's authority field (creator, store operator, or hirer);
  standard actor-call sender authentication, no new signature schemes.
  `declaration_id` preimage verification (§2.1.1) prevents id squatting.
* **Prepaid custody.** The Trading Post holds per-hire balances; only the
  hirer can withdraw, only `renew`/`settle_per_call` can draw, and
  `revoke_hire` refunds automatically. Balance accounting is per-hire — no
  pooled-fund invariants to break.
* **Artifact equivalence is a claim.** `claimed_root` is signed state from
  the registrant, not a proof. A store serving content that diverges from the
  attested root is detectable by anyone with read access (decrypt + compare)
  and publicly attributable to the registering address; attesters can
  downgrade (§2.7). A cryptographic equivalence proof is an open question.
* **Lease policy correctness in `cbssd`.** Issuance policy reads chain state;
  `cbssd` hand-rolls chain interaction today and has drifted from node before
  — the policy check MUST be covered by e2e tests against a live devnet node,
  not unit fixtures.
* **Split griefing.** Vector caps (8 entries, no zero shares) bound transfer
  fan-out; beneficiary addresses are not validated as live — a transfer to a
  dead address burns that share, which is the beneficiary's risk, as with any
  CIP-20 transfer.
* **Attestation index growth.** `attest` is open to any address (§2.7), so a
  hostile attester can grow a root's attestation index without bound. §2.7
  mandates a bound: proportional metering plus pagination, or a per-root
  attester cap. The cap variant has a residual: Sybil attesters can fill a
  root's index and block *new* attesters from recording verdicts on it —
  accepted, since filling costs gas per record and verdicts from
  unrecognized attesters carry no client trust weight; attesters clients
  rely on SHOULD attest at review time, before an adversary targets the
  root. Spam records themselves carry no trust weight because clients
  filter by attester.
* **Store-side censorship.** Bounded by design: scope-limited pause powers,
  open store registration, direct hire, and public events.
* **Cached-DEK residual** (§2.5.3): accepted, bounded by settlement refusal
  and runner stake; revisit if runner trust assumptions weaken.

## 5. Out of scope

Review policy and curation; commission values; fork attribution economics (CIP-27 follow-up);
creator-code semantics beyond split entries; store UX; fiat display and
funding rails (CIP-18/CIP-28 territory).

## 6. Open questions

1. Per-epoch IBE label rotation as cached-DEK hardening — cost: ciphertext
   re-production path; candidate for a CIP-33.r2 once runner-trust data
   exists.
2. `PerCall` rate-limit defaults and MPP session caps for hostile hiring
   actors.
3. Capability-schema registry: whether a curated schema-type catalog (beyond
   free-form JSON Schema) earns its complexity once agent-hire volume exists.
4. Whether `instance_mode: Forked` should become the default once CIP-27
   stabilizes.
5. Per-period escrow of executed splits, enabling protocol-level pro-rata
   clawback on trust-and-safety revocation (v1 refunds only unspent
   `prepaid`, §2.4).
6. Cryptographic plaintext-equivalence proof binding a `ServingArtifact` to
   its version's `manifest_root` (v1: signed claim + social detectability,
   §4).
