Skip to content

Task Validation V2: separate submission from settlement for review-based and externally verified tasks #1518

Description

@signerless

Summary

Introduce a real task validation layer that separates submission from settlement for review-based and externally verified tasks.

Today, AgenC is strong for:

  • objective tasks that can auto-settle
  • private tasks that can be verified with constraint_hash + ZK proof

But it does not yet support a safe acceptance flow for subjective work such as apps, UI, research, strategy, or externally attested outcomes such as sales/leads/conversions.

Problem

The current public completion path conflates two different concepts:

  • the worker submitted something
  • the worker delivered the result the creator actually wanted

For public tasks, complete_task effectively means both.

That creates a product/protocol gap for marketplace tasks where quality or correctness is subjective or depends on external evidence.

Current Repo-Grounded Behavior

Protocol state model

  • TaskStatus::PendingValidation exists, but is explicitly described as reserved/future flow in programs/agenc-coordination/src/state.rs
  • TaskClaim already has is_validated, but it is not used as the main settlement gate today
  • TaskStatus does not currently include a Rejected state

Public completion path

  • complete_task requires a non-zero proof_hash, validates status/deadline/claim rules, and rejects private tasks
  • after validation it calls execute_completion_rewards() directly
  • execute_completion_rewards() updates claim/task/protocol state, emits TaskCompleted / RewardDistributed, transfers funds, and closes escrow when final

Claim / worker slot behavior

  • claiming a task increments task.current_workers
  • completion settlement decrements task.current_workers and increments task.completions
  • current_workers currently acts as the live claim-slot counter for claimability and dispute preconditions

Dispute behavior

  • initiate_dispute only accepts tasks in InProgress or PendingValidation
  • initiate_dispute also currently requires task.current_workers > 0
  • this means the standard public path has no creator approval gate before payout; dispute is not a substitute for normal acceptance

Runtime / SDK behavior

  • runtime exposes claimTask() and completeTask()
  • SDK exposes completeTask() and completeTaskPrivate()
  • there is no first-class submit, accept, reject, or validate flow for public tasks

Private verification already exists

  • Task.constraint_hash already supports private/objective verification
  • complete_task_private validates the journal against the task's constraint_hash
  • this is the correct model for objective private tasks and should remain supported

Documentation mismatch

  • docs/architecture/flows/task-lifecycle.md already describes a richer flow including PendingValidation
  • the docs are currently ahead of the actual public handler behavior

Why This Matters

Without a review/validation stage, creators cannot reliably use AgenC for:

  • app builds
  • UI / design work
  • research deliverables
  • strategy / copy / product work
  • sales tasks
  • lead generation / external conversions
  • any marketplace task where correctness is not purely deterministic

As a result, AgenC is currently better positioned as:

  • coordination + settlement for objective tasks
  • privacy-preserving verification for private objective tasks

But not yet as a complete trust layer for subjective marketplace work.

Goals

  • preserve the current fast path for deterministic tasks
  • preserve the current private ZK path for objective private tasks
  • add a real review/validation gate for subjective and externally verified tasks
  • make protocol, SDK, runtime, and docs consistent
  • support marketplace-grade task acceptance without relying on ad hoc disputes
  • define slot / claim behavior clearly so review-based tasks do not deadlock collaborative workflows

Proposed Design

1. Add validation modes to tasks

Add a validation_mode field to Task.

Suggested modes:

  • auto
  • creator_review
  • validator_quorum
  • external_attestation
  • private_zk

Meaning:

  • auto: current public behavior for deterministic tasks
  • creator_review: creator must accept before payout
  • validator_quorum: validators approve/reject before payout
  • external_attestation: an approved attestor/oracle confirms the outcome before payout
  • private_zk: existing constraint_hash + complete_task_private path

2. Make PendingValidation a real state

Recommended state flow:

Open -> InProgress -> PendingValidation -> Completed
Open -> InProgress -> PendingValidation -> Disputed -> Completed|Cancelled
Open -> InProgress -> Completed           (auto)
Open -> InProgress -> Completed           (private_zk)

Interpretation:

  • auto and private_zk may still settle immediately
  • all review-based and externally validated tasks go through PendingValidation
  • Rejected is not introduced as a TaskStatus in the initial v2 scope
  • rejection is modeled at the claim/submission layer, not as a task-wide terminal/intermediate state

3. Split submission from settlement

New instruction: submit_task_result

Worker submits deliverable metadata:

  • submission_hash
  • optional artifact/result hash or pointer metadata
  • submitted_at

Effects:

  • mark claim as submitted
  • move task to PendingValidation when required by validation_mode
  • do not transfer reward
  • do not close escrow
  • keep the worker slot reserved until the submission is accepted, rejected, expired, or disputed

New instruction: accept_task_result

Used for creator_review.

Effects:

  • set claim.is_validated = true
  • increment accepted completion counters
  • release the worker slot
  • call the existing reward settlement helper
  • mark task Completed only when accepted completions reach required_completions

New instruction: reject_task_result

Used for creator_review.

Effects:

  • store rejection_hash
  • mark the submission as rejected at the claim layer
  • release the worker slot without payout
  • do not increment task.completions
  • keep task in PendingValidation or InProgress depending on whether additional accepted work is still required
  • allow dispute initiation from the rejected submission path

New instruction: auto_accept_task_result

Used when the review window expires without response.

Effects:

  • finalize payout after review_window_secs
  • protect workers from abandoned tasks / inactive creators
  • count toward required_completions the same way as normal acceptance

New instruction: validate_task_result

Used for validator_quorum.

Effects:

  • validators vote approve/reject
  • only approved submissions increment accepted completion counters
  • once quorum is reached, finalize or reject accordingly

4. Make claim-layer state explicit

TaskStatus is too coarse to represent submitted vs rejected vs accepted claims.

Add claim-level submission state to TaskClaim, for example:

  • submission_status: u8 where None | Submitted | Accepted | Rejected

Also add:

  • submitted_at: i64
  • submission_hash: [u8; 32]
  • rejection_hash: Option<[u8; 32]>

Reuse:

  • is_validated

This keeps task-wide lifecycle small while making review flow explicit and queryable.

5. Reuse existing settlement logic

Keep execute_completion_rewards() as the settlement primitive.

But change when it is called:

  • complete_task only for auto
  • complete_task_private only for private_zk
  • accept_task_result
  • auto_accept_task_result
  • successful validator quorum
  • successful external attestation finalization

This minimizes risk by preserving the current payout implementation while changing only the gating logic.

6. Clarify completion and slot semantics for collaborative tasks

For review-based modes:

  • task.completions means accepted completions, not mere submissions
  • rejected submissions do not advance required_completions
  • accepted or auto-accepted submissions do advance required_completions
  • submission rejection must release claim capacity so other workers can claim the task
  • the review/dispute path must not depend solely on task.current_workers > 0

That implies initiate_dispute should be updated so rejected/submitted claims remain disputable even after the claim slot is released.

7. Extend on-chain data model

Task

Add:

  • validation_mode: u8
  • review_window_secs: i64
  • validator_quorum: u8
  • attestor: Option<Pubkey>

Do not add in v2 phase 1:

  • acceptance_hash

Rationale:

  • it is currently undefined operationally and would expand account state without a concrete verification rule

TaskClaim

Add:

  • submission_status: u8
  • submitted_at: i64
  • submission_hash: [u8; 32]
  • rejection_hash: Option<[u8; 32]>

Reuse:

  • is_validated

8. Runtime / SDK API changes

SDK

Add:

  • submitTask(...)
  • acceptTask(...)
  • rejectTask(...)
  • validateTask(...)
  • autoAcceptTask(...)

Keep:

  • completeTask(...) for auto
  • completeTaskPrivate(...) for private_zk

Runtime

Extend TaskOperations with the same lifecycle primitives.

This keeps the runtime aligned with the protocol instead of forcing off-chain review semantics into completeTask().

9. Program / IDL surface changes

The on-chain program entrypoints and generated IDL will change.

At minimum, the protocol layer must add new instructions alongside the existing handlers:

  • submit_task_result
  • accept_task_result
  • reject_task_result
  • auto_accept_task_result
  • validate_task_result

Client migration must account for new instruction discriminators and regenerated SDK/runtime bindings.

10. Recommended mapping by task type

  • auto

    • bug fixes
    • deterministic transformations
    • test-driven code tasks
    • formula-based scoring
  • creator_review

    • app builds
    • UI work
    • landing pages
    • research deliverables
    • strategy/copy/product tasks
  • validator_quorum

    • open marketplace work where creator should not be sole judge
    • trust-minimized service marketplace flows
  • external_attestation

    • sales
    • leads
    • traffic/conversions
    • webhook-confirmed external outcomes
  • private_zk

    • objective private tasks already supported by constraint_hash

Acceptance Criteria

Protocol

  • PendingValidation is used as a real state for non-auto public completion paths
  • public complete_task is limited to validation_mode = auto
  • complete_task_private continues to support private_zk tasks
  • submit_task_result exists and does not transfer funds
  • accept_task_result exists and settles via existing reward logic
  • reject_task_result exists and does not settle funds
  • auto_accept_task_result exists and enforces review window expiry
  • validate_task_result exists for validator-based approval
  • dispute flow works from submitted/rejected review states even if the claim slot has already been released
  • collaborative task completion uses accepted completions as the settlement/finality counter

Data Model

  • Task supports validation mode configuration
  • TaskClaim stores submission metadata and rejection metadata
  • TaskClaim has explicit submission/review state
  • TaskClaim.is_validated is part of the actual settlement gate

SDK / Runtime

  • SDK exposes submit/accept/reject/validate/auto-accept operations
  • runtime TaskOperations mirrors the new lifecycle
  • existing auto/private flows remain backward compatible where possible
  • regenerated IDL/client bindings include the new instruction surface

Migration / Compatibility

  • existing tasks with constraint_hash == 0 default to validation_mode = auto
  • existing tasks with constraint_hash != 0 default to validation_mode = private_zk
  • legacy clients keep working for existing auto and private_zk flows during rollout, where feasible

Docs

  • lifecycle docs reflect actual handler behavior
  • protocol/SDK/runtime docs describe the new validation modes
  • examples cover auto, creator_review, and private_zk

Migration Notes

Suggested rollout order:

  1. activate PendingValidation as a real state
  2. add validation_mode with backward-compatible defaults for legacy tasks
  3. add claim-layer submission state and metadata
  4. split public submission from public settlement
  5. add creator_review
  6. update dispute initiation rules for released-but-disputable submissions
  7. add validator_quorum
  8. add external_attestation
  9. regenerate IDL / SDK / runtime bindings
  10. update docs and examples

Non-Goals

  • replacing the existing private ZK verification path
  • redesigning escrow settlement math
  • using dispute resolution as the primary acceptance mechanism for normal work
  • adding a task-wide Rejected state in v2 phase 1

Open Questions

  • should validator_quorum use arbitrary validator agents with VALIDATOR capability, or a task-specific validator set?
  • should external attestation be modeled as a direct attestor signature, a dedicated oracle account, or a generic attestation interface?
  • after creator rejection, should the worker be allowed to resubmit on the same claim, or should rejection force a fresh claim cycle?
  • how should collaborative tasks behave when one submitted claim is rejected and others are still in progress?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions