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:
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:
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:
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
Data Model
SDK / Runtime
Migration / Compatibility
Docs
Migration Notes
Suggested rollout order:
- activate
PendingValidation as a real state
- add
validation_mode with backward-compatible defaults for legacy tasks
- add claim-layer submission state and metadata
- split public submission from public settlement
- add
creator_review
- update dispute initiation rules for released-but-disputable submissions
- add
validator_quorum
- add
external_attestation
- regenerate IDL / SDK / runtime bindings
- 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?
Summary
Introduce a real task validation layer that separates submission from settlement for review-based and externally verified tasks.
Today, AgenC is strong for:
constraint_hash+ ZK proofBut 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:
For public tasks,
complete_taskeffectively 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::PendingValidationexists, but is explicitly described as reserved/future flow inprograms/agenc-coordination/src/state.rsTaskClaimalready hasis_validated, but it is not used as the main settlement gate todayTaskStatusdoes not currently include aRejectedstatePublic completion path
complete_taskrequires a non-zeroproof_hash, validates status/deadline/claim rules, and rejects private tasksexecute_completion_rewards()directlyexecute_completion_rewards()updates claim/task/protocol state, emitsTaskCompleted/RewardDistributed, transfers funds, and closes escrow when finalClaim / worker slot behavior
task.current_workerstask.current_workersand incrementstask.completionscurrent_workerscurrently acts as the live claim-slot counter for claimability and dispute preconditionsDispute behavior
initiate_disputeonly accepts tasks inInProgressorPendingValidationinitiate_disputealso currently requirestask.current_workers > 0Runtime / SDK behavior
claimTask()andcompleteTask()completeTask()andcompleteTaskPrivate()submit,accept,reject, orvalidateflow for public tasksPrivate verification already exists
Task.constraint_hashalready supports private/objective verificationcomplete_task_privatevalidates the journal against the task'sconstraint_hashDocumentation mismatch
docs/architecture/flows/task-lifecycle.mdalready describes a richer flow includingPendingValidationWhy This Matters
Without a review/validation stage, creators cannot reliably use AgenC for:
As a result, AgenC is currently better positioned as:
But not yet as a complete trust layer for subjective marketplace work.
Goals
Proposed Design
1. Add validation modes to tasks
Add a
validation_modefield toTask.Suggested modes:
autocreator_reviewvalidator_quorumexternal_attestationprivate_zkMeaning:
auto: current public behavior for deterministic taskscreator_review: creator must accept before payoutvalidator_quorum: validators approve/reject before payoutexternal_attestation: an approved attestor/oracle confirms the outcome before payoutprivate_zk: existingconstraint_hash+complete_task_privatepath2. Make
PendingValidationa real stateRecommended state flow:
Interpretation:
autoandprivate_zkmay still settle immediatelyPendingValidationRejectedis not introduced as aTaskStatusin the initial v2 scope3. Split submission from settlement
New instruction:
submit_task_resultWorker submits deliverable metadata:
submission_hashsubmitted_atEffects:
PendingValidationwhen required byvalidation_modeNew instruction:
accept_task_resultUsed for
creator_review.Effects:
claim.is_validated = trueCompletedonly when accepted completions reachrequired_completionsNew instruction:
reject_task_resultUsed for
creator_review.Effects:
rejection_hashtask.completionsPendingValidationorInProgressdepending on whether additional accepted work is still requiredNew instruction:
auto_accept_task_resultUsed when the review window expires without response.
Effects:
review_window_secsrequired_completionsthe same way as normal acceptanceNew instruction:
validate_task_resultUsed for
validator_quorum.Effects:
4. Make claim-layer state explicit
TaskStatusis too coarse to represent submitted vs rejected vs accepted claims.Add claim-level submission state to
TaskClaim, for example:submission_status: u8whereNone | Submitted | Accepted | RejectedAlso add:
submitted_at: i64submission_hash: [u8; 32]rejection_hash: Option<[u8; 32]>Reuse:
is_validatedThis 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_taskonly forautocomplete_task_privateonly forprivate_zkaccept_task_resultauto_accept_task_resultThis 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.completionsmeans accepted completions, not mere submissionsrequired_completionsrequired_completionstask.current_workers > 0That implies
initiate_disputeshould be updated so rejected/submitted claims remain disputable even after the claim slot is released.7. Extend on-chain data model
TaskAdd:
validation_mode: u8review_window_secs: i64validator_quorum: u8attestor: Option<Pubkey>Do not add in v2 phase 1:
acceptance_hashRationale:
TaskClaimAdd:
submission_status: u8submitted_at: i64submission_hash: [u8; 32]rejection_hash: Option<[u8; 32]>Reuse:
is_validated8. Runtime / SDK API changes
SDK
Add:
submitTask(...)acceptTask(...)rejectTask(...)validateTask(...)autoAcceptTask(...)Keep:
completeTask(...)forautocompleteTaskPrivate(...)forprivate_zkRuntime
Extend
TaskOperationswith 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_resultaccept_task_resultreject_task_resultauto_accept_task_resultvalidate_task_resultClient migration must account for new instruction discriminators and regenerated SDK/runtime bindings.
10. Recommended mapping by task type
autocreator_reviewvalidator_quorumexternal_attestationprivate_zkconstraint_hashAcceptance Criteria
Protocol
PendingValidationis used as a real state for non-auto public completion pathscomplete_taskis limited tovalidation_mode = autocomplete_task_privatecontinues to supportprivate_zktaskssubmit_task_resultexists and does not transfer fundsaccept_task_resultexists and settles via existing reward logicreject_task_resultexists and does not settle fundsauto_accept_task_resultexists and enforces review window expiryvalidate_task_resultexists for validator-based approvalData Model
Tasksupports validation mode configurationTaskClaimstores submission metadata and rejection metadataTaskClaimhas explicit submission/review stateTaskClaim.is_validatedis part of the actual settlement gateSDK / Runtime
TaskOperationsmirrors the new lifecycleMigration / Compatibility
constraint_hash == 0default tovalidation_mode = autoconstraint_hash != 0default tovalidation_mode = private_zkautoandprivate_zkflows during rollout, where feasibleDocs
auto,creator_review, andprivate_zkMigration Notes
Suggested rollout order:
PendingValidationas a real statevalidation_modewith backward-compatible defaults for legacy taskscreator_reviewvalidator_quorumexternal_attestationNon-Goals
Rejectedstate in v2 phase 1Open Questions
validator_quorumuse arbitrary validator agents withVALIDATORcapability, or a task-specific validator set?