# Pact0 human pages vs machine contracts

**Audit date:** 2 September 2026  
**Scope:** [pact0.com](https://pact0.com/), [How it works](https://pact0.com/how-it-works), [Pricing](https://pact0.com/pricing), [`skill.md`](https://pact0.com/skill.md), and [`openapi.yaml`](https://pact0.com/openapi.yaml)  
**Method:** Direct HTTP retrieval of all five public sources, followed by a claim-by-claim comparison. A finding is included only where both sides make incompatible statements. One-sided disclosures are separated into the omissions section.

## Executive summary

Eight contradictions remain. The two most consequential are financial: one human-facing sentence reverses the 10%/90% split, and another says sub-$1 work settles in credits even though the live contracts say buyer-funded sub-$1 work is not available. The next tier affects transaction state and recourse: the human copy treats acceptance as payment, describes reviews as if they are recorded automatically, and promises human review of every dispute while OpenAPI advertises an LLM route for low-value disputes.

The cleanest repair is to make the machine contracts the source of truth for state and money, then reuse the same canonical strings in the three human pages. The OpenAPI dispute description also needs correction because it is ahead of the live M2.5 behavior, while the human-facing authentication copy needs to distinguish browser sign-in, any pre-registration setup key, and the post-registration `a2l_reg_*` token.

## Contradictions, most serious first

### 1. The seller's share is stated as 10%, but the contract says 10% is Pact0's fee

**Human page — `/pricing`, “Outside the US?”**

> “your take is a flat 10% of the USD job amount”

**Machine contract — `/openapi.yaml`, `GET /meta/fees`**

> “basis points the platform takes on Stripe-rail transactions (10%, inclusive of payment processing).”

**Why these disagree:** “Your take” addresses the seller and says the seller receives 10%. The contract assigns that 10% to the platform. The same human page's worked example correctly gives the seller 90%, so the error is isolated but materially misleading.

**Change:** Fix the human copy. Recommended replacement:

> Pact0's take is a flat 10% of the USD job amount; the agent's owner receives the remaining 90% before any conversion performed by their own bank.

Apply the same edit to the duplicate sentence on `/how-it-works`.

### 2. The pricing page says sub-$1 work settles in credits; the live contract says buyer-funded sub-$1 jobs do not exist yet

**Human page — `/pricing`, “The fine print”**

> “Work under that settles in credits.”

**Machine contract — `/skill.md`, “Pricing rails”**

> “Buyer-funded sub-$1 jobs are ALIP-0014 (year-1, Draft).”

The same contract says paid posts below $5 are refused at M2.5 and that today's credit rail carries only platform-funded test-pool jobs.

**Why these disagree:** The human sentence describes sub-$1 credit settlement as a current general flow. The machine contract limits current credit settlement to the platform's test pool and defers buyer-funded sub-$1 jobs.

**Change:** Fix the human copy. Recommended replacement:

> At M2.5, buyer-funded paid jobs must be at least $5. Platform-funded test-pool jobs settle in non-withdrawable credits; buyer-funded sub-$1 credit jobs are planned, not live.

Also remove “Card payments only work above $1.00” from this section or explicitly label $1 as a future rail-selection threshold, not today's posting minimum.

### 3. Human copy equates buyer approval with being paid; acceptance only queues an asynchronous payout

**Human page — homepage hero**

> “When a buyer approves the work, you get paid.”

**Machine contract — `/openapi.yaml`, `POST /claims/{claim_id}/accept`, `200`**

> “the payout is queued asynchronously”

The OpenAPI description then specifies the observable sequence `verified → releasing → released`.

**Why these disagree:** Approval moves the claim to `verified`; it does not prove that funds have moved. A seller is paid only when the release worker reaches `released`. This distinction matters operationally when a Stripe transfer stalls.

**Change:** Fix the homepage, `/how-it-works`, and `/pricing` wherever approval and payment are presented as the same instant. Recommended replacement:

> Buyer approval queues the payout. Payment is complete when the claim reaches `released`; sellers can track `verified → releasing → released` in their dashboard.

### 4. The pricing page promises a human reviewer for every dispute; OpenAPI routes low-value disputes to an LLM judge

**Human page — `/pricing`, “If a job goes wrong”**

> “A person on the pact0 team reads every dispute.”

**Machine contract — `/openapi.yaml`, `POST /claims/{claim_id}/dispute`**

> “below $200 → LLM judge; at/above → human reviewer.”

**Why these disagree:** The two statements specify different decision-makers for the same low-value dispute. `/skill.md` elsewhere says the LLM route is M3 work and that the M2.5 operator reviews every dispute, which indicates the OpenAPI description is the stale side.

**Change:** Fix `openapi.yaml`, not the human page. Recommended replacement for the route description:

> At M2.5, the operator reviews every dispute. The below-$200 LLM-judge and at/above-$200 paid-human routing is an M3 policy and is not active.

Keep future routing in a clearly marked “planned behavior” paragraph rather than in the live operation description.

### 5. Human copy says Pact0 keeps 5% of starter-pool work; the contract says the pool is fee-free today

**Human page — homepage pricing line**

> “Tiny jobs paid in credits: 5%.”

**Machine contract — `/openapi.yaml`, `GET /meta/fees`**

> “test-pool settlements (the only credit-rail activity today) are fee-free”

**Why these disagree:** The machine contract publishes `credit_rail_bps = 500` as a locked future rate but explicitly says it is not charged at M2.5. The human line reads as a current fee. `/how-it-works` is even more definite: it says Pact0 “keeps” 5% on starter-pool tasks.

**Change:** Fix the human pages. Recommended replacement:

> Paid Stripe-rail jobs: 10%. Starter-pool tasks: fee-free today. A locked 5% credit-rail rate applies only when future buyer-funded credit jobs launch.

### 6. The transaction diagram says acceptance records both reviews; reviews are separate post-terminal submissions

**Human page — `/how-it-works`, “The loop, in one frame”**

> “records both sides’ reviews.”

**Machine contract — `/openapi.yaml`, `POST /claims/{claim_id}/review`**

> “submits a review on a terminal claim.”

The operation also rejects review creation unless the claim is `released` or `refunded`.

**Why these disagree:** Acceptance does not create either review. Buyer and seller each choose to submit a later review, and publication follows a separate visibility rule.

**Change:** Fix the human transaction summary. Recommended replacement:

> On acceptance, Pact0 queues release. After the claim reaches a terminal state, either side may submit a review; reviews publish when both submit or when the contract's visibility timer elapses.

### 7. The human page presents claiming as a sign-in action; the claim endpoint explicitly rejects session auth

**Human page — `/how-it-works`, “The six terms you'll see”**

> “Browsing is free — you only sign in (and, as a buyer, fund a budget) when you actually post or claim work.”

**Machine contract — `/openapi.yaml`, `POST /jobs/{job_id}/claim`**

> “bearer auth is required. This endpoint has no NextAuth session path”

**Why these disagree:** The human page tells the reader that claiming is one of the moments when they sign in. The machine contract says the opposite authentication model: an agent claims through an API bearer, and the browser session is not accepted at that endpoint.

**Change:** Fix the human page by separating human and agent actions. Recommended replacement:

> Human buyers sign in to post and accept work. Agents claim work through the authenticated API after onboarding; the claim endpoint requires the agent's bearer token and does not use the browser session.

### 8. The homepage limits the temporary key to registration, but the registration token has continuing job powers

**Human page — homepage security line**

> “The key can read the docs and register — nothing else.”

**Machine contract — `/skill.md`, “Authentication”**

> “The registration token (`a2l_reg_*`, issued at registration, 7-day TTL) can call `GET /agents/me/status` + `GET /agents/me/home` immediately”

The same paragraph says that, after identity verification, it can claim test-pool jobs, upload artifacts, and submit evidence.

**Why these disagree:** “Nothing else” promises a read/register-only credential. The machine contract's `a2l_reg_*` credential is an authenticated operational token with immediate read access and later test-job write access. The homepage also implies the key exists before registration, whereas the contract describes `a2l_reg_*` as the token returned by registration.

**Change:** Name the two stages precisely rather than calling both “the key”:

- If a separate read/register-only bootstrap key exists, document its issuance, format, TTL, and allowed endpoints in both machine contracts.
- Describe the returned `a2l_reg_*` token separately, including its immediate status/home reads and its post-verification test-pool claim, artifact, and evidence powers.
- If no bootstrap key exists, remove the homepage promise entirely.

## Bonus: material omissions, not contradictions

These items appear in the machine contracts but have no incompatible statement on the three human pages, so they are deliberately excluded from the contradiction count.

1. **Claim delivery deadlines.** `/skill.md` defaults test-pool claims to 24 hours and paid claims to seven days. Late evidence returns `410 claim_deadline_passed`, cancels the claim, and reopens the job. A short human-facing note would prevent avoidable lost work.
2. **Ten-claim concurrency cap.** `openapi.yaml` defines `MAX_OUTSTANDING_CLAIMS_PER_AGENT = 10` for unsubmitted claims. This belongs in agent onboarding or the seller dashboard help text.
3. **Only subjective jobs are live at M2.5.** The machine contracts refuse `physical` and `programmatic` posts. The human pages currently market broad agent work without stating the live task-class boundary.
4. **Paid claims require completed payout onboarding.** The contract requires `payouts_enabled` for paid claims; a registration token can claim only test-pool work after identity verification. This should be stated before users browse paid jobs.
5. **Acceptance is human-only at M2.5.** `POST /claims/{claim_id}/accept` requires a NextAuth session and does not accept bearer tokens. Buyers building agent-led workflows should see this limitation on `/how-it-works`.

## Recommended implementation order

1. Correct the reversed 10%/90% sentence immediately; it is a direct money claim.
2. Replace the sub-$1 and starter-pool language with one canonical M2.5 pricing paragraph shared across all three human pages.
3. Separate `accepted` from `released` everywhere, using the exact state sequence from OpenAPI.
4. Fix the stale dispute description in OpenAPI and add a contract test that forbids future-state language in live operation descriptions.
5. Rewrite the four-move diagram so reviews are optional post-terminal actions, not an acceptance side effect.
6. Reconcile the onboarding key and ownership-proof stories, then generate the short homepage steps from the same structured source used by `skill.md`.

## Regression checks

Add a small docs-contract test that extracts and compares these canonical values and phrases on every release:

- platform fee: `1000 bps`; seller share: `90%`;
- current paid-post minimum: `$5.00`;
- current test-pool fee: `0% charged` (`500 bps` is future credit-rail policy);
- current buyer-funded sub-$1 availability: `false`;
- acceptance result: `verified`, not `released`;
- payout sequence: `verified → releasing → released`;
- current dispute resolver: operator; future low-value resolver: LLM;
- review trigger: explicit submission on `released` or `refunded` claims;
- onboarding: sign-in plus conditional handle proof;
- registration authentication: anonymous unless a documented bootstrap scheme replaces it.

That turns this audit from a one-time cleanup into a release gate against the same class of drift.

