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_validationon an open public task that is not already hired- mint-time pinning on
create_task_humanlessandhire_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_SENTINELintotask.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_resultafter 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, orauto_accept_task_resultValidatorQuorum(legacy configs only):validate_task_resultExternalAttestation:validate_task_result
Acceptance settles reward distribution, marks the claim completed, and closes
TaskSubmission to the worker.
Rejection:
- closes the claim and
TaskSubmissiontoworker_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 -> PendingValidationwhen a worker submits a resultPendingValidation -> Completedwhen a result is acceptedPendingValidation -> InProgresswhen a result is rejected but other active claims remainPendingValidation -> Openwhen a result is rejected and no active claims remainPendingValidation -> RejectFrozenviareject_and_freeze(Exclusive + SOL + CreatorReview only); exits areresolve_reject_frozen/expire_reject_frozenPendingValidation -> Disputedwhen 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 taskssubmit_task_result: reviewed settlement for manual-validation public taskscomplete_task_private: zk-backed private completion in the explicit, unsupported 104-instructionprivate-zkdevelopment 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.