cd /news/ai-agents/openworkproof-protocol-specification Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-93835] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=Β· neutral

OpenWorkProof Protocol Specification

A community-driven specification, OpenWorkProof, defines a protocol for verifying AI agent work through signed, auditable evidence and negative control arms. The protocol addresses the failure model where verification can be green yet structurally meaningless, citing production data showing a gate caught only 56% of known degradations. It introduces primitives such as guards, negative controls, and population manifests to test verifier capability and prevent silent decay.

read9 min views1 publishedAug 12, 2026

Status: Draft v0.3 β€” community co-design

Date: 2026-08-12

Repository: https://github.com/dengyier/OpenWorkProof

License: TBD (project convention: open, permissive)

This specification is the product of a public design conversation (2026-08-08 β†’ 2026-08-12) across LinkedIn and Dev.to. Every primitive below was shaped by named community contributions; each section cites its origin. The protocol's governing principle, stated by the community and adopted here:

Verification must itself be tested.A check that never fails has never been checked.

OpenWorkProof is a protocol for verifying AI agent work: producing signed, auditable evidence that a piece of agent execution happened as claimed, and that the verifier producing that evidence is capable of detecting failure.

Two distinct claims are always separated in this protocol:

Claim Mechanism Meaning
Authenticity
Signature over a receipt This work was executed and attested as stated
Verifier capability
Negative control arm in the receipt The verifier would have caught a lie

Signatures alone prove the first. They say nothing about the second β€” the ln.strip()

lesson (Section 4.1).

In scope:

Non-goals (for now):

Term Definition
Guard
A verification check: command + assertion + expected failure behavior
Guard inventory
The set of guards an operator runs, classified proven / unproven / broken
Negative control
A deliberately broken input, run on every CI pass, asserting the guard goes red
Provocation contract
The formal spec of what a negative control provokes (exit code, stderr pattern, schema scope)
Receipt
Signed evidence of one verification event
Positive arm
The "did it pass" side of a receipt: test suite, result, population
Negative arm
The "would it catch a lie" side: control fixture, control result, control target
Population manifest
The honest enumeration of what a check was supposed to examine
Eligible seen
Pre-selection count: what reached the gate
Selection loss
The auditable gap between eligible_seen and population_size
Rot
Silent decay of a check's capability while output stays green (three kinds: guard, control, population)

The protocol exists because verification can be green and structurally meaningless. The failure model is explicit.

ln.strip()

) A production gateway ran a signed, audited check that reported verified: true

on every run for months. The bug: a stray newline pushed an assert

below a return

, so the assertion never executed. Exit code 0. Verdict verified.

Measured impact (fintech engineer's post, 2026-08-09):

Status Count
Guards total 40
Proven (can detect failure) 7
Broken 0
Unproven
33

Five of eight caller-test shapes produced false passes. The agent had "passed 2,283 tests" and failed in production.

Lesson: the verifier is part of the system being verified. It must be tested with inputs designed to make it fail.

Even with negative controls in place, a check can go silently dead three ways (community taxonomy, 2026-08-12):

Rot Failure Countermeasure Origin
Guard rot
Guard stops catching real failures Continuous negative control on every CI pass Max Quimby
Control rot
Control stops testing the right failure (recall/precision of the test itself) Digest pinning + control_schema_version
Skillselion
Population rot
Guard examines the wrong population, or none at all
eligible_seen in the population manifest
Tom Jones

All three can produce a green checkmark while being structurally meaningless. All three need different countermeasures.

Production data (Ethan Walker, 2026-08-12): a gate caught 23 of 41 known degradations β€” a 56% catch rate β€” across eleven green weeks in which nobody asked what fraction it catches.

Lesson: every guard must be measurable against known-bad inputs. The negative control is the cheap, proactive version of the expensive forensic replay Ethan had to do retroactively.

A guard is a check plus a control:

guard:
  id: gw_check_response_shape
  description: "Every gateway response matches the documented schema"
  command: "check_response.sh"
  assertion: "schema_validate $INPUT"
  status: unproven        # proven | unproven | broken β€” set by control runs
  controls: [gw_control_null_handling]

The guard inventory is a published, versioned list β€” not a private detail. It is the unit of honesty:

guard_inventory:
  schema_version: "1.0"
  generated_at: 2026-08-12T00:00:00Z
  totals:
    guards: 40
    proven: 7
    unproven: 33
    broken: 0
  guards: [ ... ]

"Proven" is defined operationally: a guard is proven only while its negative control fails as expected. The moment the control passes (green on broken input), the guard is reclassified unproven

or broken

. Proven is a time-decaying label, not a permanent badge (Max Quimby: guard rot).

A negative control pins the exact broken input and the exact expected failure, and scopes itself to schema versions (Skillselion: control rot / digest pinning):

negative_control:
  fixture_digest: sha256:abc123...            # The exact broken input
  expected_failure_digest: sha256:def456...   # The exact failure signature
  control_schema_version: 2                   # For schema migration tracking
  control_spec:
    target_schema_version: ">=1.0, <3.0"      # Valid for these schema versions
    provocation_type: null_handling           # What class of failure it tests
    expected_exit_code: non-zero              # Minimum bar
    expected_stderr_pattern: "NullPointerException"  # Specific signal

Rules:

control_schema_version

and expected_failure_digest

over time.target_schema_version

range.A guard's scope must be auditable. The manifest distinguishes what reached the gate from what passed selection (Tom Jones, third round):

population_manifest:
  selection_rule: "threads we have commented in"   # What we HOLD
  eligible_seen: 400                               # What reached the gate (pre-selection)
  population_size: 12                              # What passed selection (post-selection)
  population_digest: <merkle_root>                 # Tamper-evident enumeration
  sampling_rate: 1.0                               # 100% = no sampling
  effective_from: <timestamp>                      # When the rule was authoritative

Semantics:

eligible_seen

β€” population_size

β€” Canonical decision table (Tom Jones):

| Scenario | eligible_seen | population_size | Meaning | |---|---|---|---| | Healthy instrument | 0 | 0 | Nothing to do, nothing expected | | Broken collector | 400 | 0 | 400 things should have been checked, 0 were |

Without eligible_seen

, both scenarios produce the same receipt. With it, the broken case is a live, self-reporting rot signal on the day it happens β€” not at the next review.

Operational rule: check the set you HOLD, not the set you FETCHED. The selection_rule

must be defined over the population you intend to cover, and eligible_seen

proves the collector reached it.

Reference scenarios (included in Appendix A with attribution): the thread monitor and the sampler.

The signed unit of verification. One payload, two arms (Cophy Origin: the receipt–content gap; Mikhail: dual-arm verification):

dual_arm_receipt:
  schema_version: "1.0"
  claim:
    task_id: owp-task-20260812-001
    description: "Refund processed for order R-4491"
    result: done
    output_digest: sha256:9f8e...               # What was actually produced
  positive_arm:
    test_suite_digest: sha256:77aa...
    test_result: pass
    population_manifest:                       # 5.3 β€” what the pass covered
      selection_rule: "refunds with amount > 0"
      eligible_seen: 113
      population_size: 113
      population_digest: sha256:31cd...
      sampling_rate: 1.0
      effective_from: 2026-08-12T00:00:00Z
  negative_arm:                                # 5.2 β€” would the verifier catch a lie?
    control_fixture_digest: sha256:abc123...
    control_result: fail-as-expected
    control_schema_version: 2
    control_target: guard:gw_check_response_shape
  signature:
    algorithm: ed25519
    key_id: owp-key-issuer-01
    value: 0x...

Rules:

output_digest

(what was produced), not merely record that a file exists.control_target

ties the control to the specific guardA receipt is a bounded claim: "this was true under these conditions at this time" (Suraj Suradkar). Obsolescence is tracked, not hidden.

retraction_receipt:
  parent_receipt_id: owp-receipt-20260812-001
  retraction_auth: <PolicyDecision>            # Independent trust boundary; co-signed
  propagation_class: none | downstream_causal | same_predicate
  semantic_cause:                              # Open, versioned enum
    category: superseded_by | refuted_by | scope_changed
    superseding_receipt_id: owp-receipt-20260812-009
    valid_until: 2026-08-20T00:00:00Z

Categories (Suraj, refining Mikhail's v0.2):

Category Meaning Consequence
superseded_by
Decision was correct then, no longer current Old receipts: not invalid, bounded
refuted_by
Old evidence was wrong Old receipts: retrospective scope loss
scope_changed
Population/policy shifted Old receipts: incomplete relative to new scope

Design constraints (Mikhail):

REVOKED / SUPERSEDED / EXPIRED

are retraction_auth

is an propagation_class

lives in the protocol layer; semantic_cause

in the application layer.Policies and their checkpoints are versioned in a monotonic registry (Brian Jin, rounds 2–3):

policy_checkpoint:
  policy_id: pol-refund-eligibility
  revision: 4
  artifact_digest: sha256:e0b1...
  effective_from: 2026-08-12T00:00:00Z
  previous_checkpoint_digest: sha256:c2a9...    # Monotonic chain
  signature:
    key_id: owp-key-policy-01
    value: 0x...
β”Œβ”€ Every CI pass ─────────────────────────────────────────────┐
β”‚ 1. Define  guard + negative_control (provocation contract)   β”‚
β”‚ 2. Run positive arm:   suite β†’ test_result, population_manifest
β”‚ 3. Run negative arm:   broken fixture β†’ control_result        β”‚
β”‚    β€” control must FAIL as expected, else guard reclassified   β”‚
β”‚ 4. Package DualArmReceipt (claim + positive + negative)       β”‚
β”‚ 5. Sign with issuer key; publish to registry                  β”‚
β”‚ 6. On policy/scope change: emit RetractionReceipt             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Outputs:

Causal order (community-corrected model; PolicyAnchor is Layer βˆ’1, not the top):

Layer Concern Primitive
Policy history / authority What rules were in force when Policy-State Registry, PolicyAnchor
Judgment What decision was authorized JPS layer (external)
Execution What the agent did claim + output_digest
Evidence That verification worked DualArmReceipt (positive + negative arm)

Evidence is the result of the pipeline; authority is its input. Confusing the two was the original ln.strip()

error β€” evidence was signed while authority was dead.

(Glen Allen: "verification must itself be tested".)

Level State Signal
0 Trust the agent's own report No independent evidence
1 Logs exist "It ran" (unverifiable claim)
2 Signed receipts Authenticity proven
3 Negative controls Verifier capability proven for fixtures
4 Continuous controls + guard inventory published Capability continuously re-proven; rot visible
5 Controls are themselves tested (control rot guarded) The verifier's verifier is verified

Target for production adoption: Level 4, with Level 5 as the differentiator.

(Sri Ramya: layered adoption β€” execution evidence first, signed receipts second.)

DualArmReceipt

s, continuous controls, published inventory. What this specification defines.Teams adopt Tier 1 first; Tier 2 is the upgrade path, not the entry requirement.

eligible_seen

: is it total events or matched events? Do we need a third count, total_seen

?control_schema_version

migration: what is the deprecation protocol for a control whose target_schema_version

range expires?semantic_cause

enum: who curates versions, and how do downstream consumers handle unknown values?This specification was co-designed in public. Contributions by:

ln.strip()

eligible_seen

, FETCHED vs HOLD, reference scenarios (5.3, Appendix A)DualArmReceipt

(5.4)Attributed to Tom Jones (2026-08-12), canonical for the population manifest:

Scenario 1 β€” The thread monitor. A sampler configured to measure, on 100% of eligible events, how often two models agree on correctness. Four days produced zero rows, while the box served 113–209 requests/day. Every part of the receipt was valid: selection rule correct, tool ran, exit 0, signature valid. The population was empty because the eligible shape was too narrow. eligible_seen = 400, population_size = 0

exposes the broken collector the day it happens.

Scenario 2 β€” The sampler. An invite sampler claims to have sampled 12 threads. Without a manifest, the claim is unfalsifiable. With selection_rule + eligible_seen + population_size

:

"You sampled 12 of 400" invites an argument. "You sampled 12" ends one.

schema_version

.negative_control.control_schema_version

tracks migration of control fixtures; a control is only valid within control_spec.target_schema_version

.

── more in #ai-agents 4 stories Β· sorted by recency
── more on @openworkproof 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/openworkproof-protoc…] indexed:0 read:9min 2026-08-12 Β· β€”