Task Validation V2

August 23, 2026 ยท View on GitHub

Task Validation V2 adds a reviewed-completion path for public tasks that should not settle immediately when a worker finishes execution.

The live implementation keeps the original Task and TaskClaim layouts stable and stores review state in dedicated PDAs instead of resizing core accounts.

What It Supports

  • standard public tasks can stay on the existing auto-settlement path
  • public tasks can be switched to manual validation before any worker claims them
  • private zk tasks in the explicit development build are not eligible for manual validation
  • competitive tasks are eligible for CreatorReview only when they use the contest-aware schema (task_schema >= 1); canary still rejects Competitive review
  • bid-exclusive tasks remain single-worker flows; review still happens on the accepted claim

How A Task Enters Manual Validation

A task can enter Task Validation V2 in two ways:

  • configure_task_validation on an open public task that is not already hired
  • mint-time pinning on create_task_humanless and hire_from_listing_humanless (CreatorReview)

configure_task_validation rejects a live HireRecord. New configs also reject ValidatorQuorum; that mode remains only so validate_task_result can settle legacy quorum accounts.

The configure instruction:

  • validates that the task is still configurable
  • stores validation settings in task-scoped PDAs
  • writes MANUAL_VALIDATION_SENTINEL into task.constraint_hash

That sentinel is how the program, runtime, and downstream tooling distinguish:

  • auto public completion
  • manual public validation
  • private zk completion

Validation Modes

CreatorReview

The task creator explicitly accepts or rejects a submitted result.

  • requires review_window_secs > 0
  • supports auto_accept_task_result after the review window elapses, except contest tasks (ContestAutoAcceptDisabled)

ValidatorQuorum (legacy settlement only)

New configure_task_validation calls reject this mode (InvalidValidationMode). validate_task_result remains so a legacy quorum config proven by deployment preflight can still settle.

  • requires validator_quorum > 0
  • validator agents must be active and hold the validator capability
  • the reviewer cannot be the task creator or the worker behind the submission

ExternalAttestation

A specific wallet attests to the result.

  • requires an attestor wallet in TaskAttestorConfig
  • quorum is effectively one attestation

On-Chain Model

TaskValidationConfig

PDA seeds: ["task_validation", task]

Stores:

  • task and creator identity
  • active ValidationMode
  • review window
  • validator quorum
  • pending submission count

TaskAttestorConfig

PDA seeds: ["task_attestor", task]

Stores the external attestor wallet for ExternalAttestation.

TaskSubmission

PDA seeds: ["task_submission", claim]

Stores the active or most recent reviewed submission for a claim:

  • submitted proof hash
  • submitted result payload
  • submission round
  • review deadline
  • accept / reject timestamps
  • rejection hash
  • validator approval and rejection counters

TaskValidationVote

PDA seeds: ["task_validation_vote", task_submission, reviewer]

Stores one reviewer vote or attestation for a specific submission round.

If a vote survives after its exact TaskSubmission parent is gone, reclaim_orphan_task_child (live in revision 5) can close only the canonical ["task_validation_vote", submission, reviewer] PDA and returns rent to the reviewer stored in the vote. A permissionless cranker cannot substitute the parent, reviewer, address, bump, or rent recipient.

Instruction Flow

1. Configure review

Creator calls:

  • configure_task_validation

2. Claim the task

Workers use the pinned-job-spec claim path:

  • claim_task_with_job_spec

3. Submit the result

Workers call:

  • submit_task_result

This moves the task into PendingValidation and records the result in TaskSubmission.

complete_task no longer settles these tasks directly. Manual-validation tasks must go through submission and review.

4. Resolve the submission

Resolution depends on mode:

  • CreatorReview: accept_task_result, reject_task_result, or auto_accept_task_result
  • ValidatorQuorum (legacy configs only): validate_task_result
  • ExternalAttestation: validate_task_result

Acceptance settles reward distribution, marks the claim completed, and closes TaskSubmission to the worker.

Rejection:

  • closes the claim and TaskSubmission to worker_authority
  • releases the worker's active claim slot
  • reopens the task if no other active claims remain

After that reject, both PDAs are gone. initiate_dispute only admits InProgress or PendingValidation with a live claim.

close_task keeps the Task PDA as a rent-exempt tombstone. It refunds surplus and children and decrements listing open_jobs. It does not close the Task.

Status Transitions

Manual validation adds these task transitions:

  • InProgress -> PendingValidation when a worker submits a result
  • PendingValidation -> Completed when a result is accepted
  • PendingValidation -> InProgress when a result is rejected but other active claims remain
  • PendingValidation -> Open when a result is rejected and no active claims remain
  • PendingValidation -> RejectFrozen via reject_and_freeze (Exclusive + SOL + CreatorReview only); exits are resolve_reject_frozen / expire_reject_frozen
  • PendingValidation -> Disputed when review is contested

Additional submissions can keep a task in PendingValidation while review is active.

Public vs Private Completion

The completion surface is now intentionally split:

  • complete_task: immediate settlement for normal public tasks
  • submit_task_result: reviewed settlement for manual-validation public tasks
  • complete_task_private: zk-backed private completion in the explicit, unsupported 104-instruction private-zk development build; it is absent from the 101-instruction production IDL

In the explicit private-zk development build, private tasks stay on the zk path and are not eligible for Task Validation V2. Production rejects private-task creation and does not expose the private-completion instructions.