Skip to content

feat(TaskManager v6): task deadlines + expired-claim takeover#174

Open
hudsonhrh wants to merge 1 commit into
mainfrom
hudsonhrh/task-deadlines-cross-repo
Open

feat(TaskManager v6): task deadlines + expired-claim takeover#174
hudsonhrh wants to merge 1 commit into
mainfrom
hudsonhrh/task-deadlines-cross-repo

Conversation

@hudsonhrh

Copy link
Copy Markdown
Member

What

TaskManager v6 adds task deadlines with a lenient takeover model — part 1 of a 3-repo feature (contracts → subgraph → frontend).

Three deadline fields per task (all optional, 0 = unset; append-only — pre-v6 tasks read zeros, no migration):

Field Type Meaning
absoluteDeadline uint48 unix calendar cutoff; while CLAIMED past it, the claim is open to takeover
completionWindow uint32 sec per-claim window: submit within N seconds of claiming or the claim opens up
claimDeadline uint48 unix derived: claimTime + window, recomputed at claim/assign/approve/reject

A fourth, soft due date lives only in IPFS task metadata (dueDate) — display-only, no contract involvement (frontend/subgraph PRs).

Lenient enforcement

  • submitTask is never deadline-blocked — late work can be submitted (and paid) until someone actually takes the task over.
  • An expired claim is taken over in one tx via the normal claimTask / assignTask / approveApplication — emits TaskClaimExpired(id, previousClaimer, newClaimer) then the usual lifecycle event; new claimer gets a fresh window. No separate unclaim function.
  • applyForTask now also accepts applications while CLAIMED-and-expired (otherwise application-gated tasks could only be taken over by the original applicant pool).
  • rejectTask restarts the window (fresh allowance for rework). SUBMITTED tasks are never takeover-able.
  • updateTask edits both knobs; window edits preserve the original claim start. A past absoluteDeadline is deliberately accepted on update — the only unstick lever for abandoned CLAIMED tasks (cancelTask is UNCLAIMED-only), incl. all pre-v6 ones. Create paths revert InvalidDeadline for non-future values.

Selector replacements (paymaster + frontend ship in lockstep)

Function v5 (dead) v6
createTask 0x22fa79bc 0x4d0265d4
createTasksBatch 0xc18aa1c9 0xf31d148f
createAndAssignTask 0xaf425951 0x98e30e89
updateTask 0x48db6f65 0xb7c288e8

New events (existing signatures untouched; ordering documented in docs/TASK_MANAGER.md as the subgraph contract): TaskDeadlinesSet, TaskClaimDeadlineSet (only-on-change), TaskClaimExpired.

Also: OrgDeployer _appendTaskManagerRules swapped to the v6 strings (count stays 43); Lens decodes the 10-field tuple + new TASK_DEADLINES key.

Testing

  • New TaskManagerDeadlineTest: 37 cases — create combos + born-expired reverts (all 3 paths), window lifecycle (claim/assign/approve/reject), lenient late submit+complete, takeover happy/sad paths (boundary: deadline second protected, +1s expired), application-flow takeover, self-reclaim refresh, updateTask arithmetic (claim-start preservation, 0→W, W→0, past-absolute unstick, perm parity), fuzz (window-edit invariant + expiry boundary).
  • DeployerTest asserts the 4 v6 selectors are auto-whitelisted at deploy + selector-accuracy strings pinned to the real selectors.
  • Full suite: 1419 passed / 0 failed. forge fmt clean.
  • Production sizes: TaskManager 20,690 / OrgDeployer 19,389 (margins +3,886 / +5,187).

Ops scripts — all 7 sims fork-run to PASS under FOUNDRY_PROFILE=production (--skip test)

  • script/upgrades/UpgradeTaskManagerDeadlines.s.sol — 3-step cross-chain upgrade. v6 probed FREE (registry + CREATE2) on Gnosis AND Arbitrum (predicted impl 0x7833c4670C42dbCe1a7aB1BAB7e7Baf0A982ff57). DryRuns on both chains exercise the live proxies: pre-v6 task zero-state (real Poa tasks on Arbitrum), born-expired revert, window start, expiry boundary, takeover with fresh window, lenient late submit + complete, window-edit arithmetic, deadline-less claims stay protected, executor storage preserved.
  • script/upgrades/UpgradeOrgDeployerDeadlineRules.s.sol — OrgDeployer v15 (probed FREE both chains, predicted 0xFa5Bc9343631489094e68a6059E93994C33127A3).
  • script/fixes/WhitelistTaskDeadlineRules{Poa,Test6Kubi,DecentralPark}ViaGovernance.s.sol — per-org proposals: 4 v6 selectors allowed + 4 dead v5 selectors disallowed (griefing hygiene). Sims execute create → vote → warp → announceWinner and assert getRule flips on the real fork.

Broadcast runbook (Hudson)

  1. Create + vote the 4 org proposals (Poa/Arbitrum; Test6, KUBI, DecentralPark/Gnosis).
  2. After windows: announceWinner per org → TaskManager Step1 (Gnosis) → Step2 (Arbitrum + cross-chain) → Step3 verify → OrgDeployer v15 Step1/Step2/Step3.
  3. Subgraph deploy + gateway publish, then frontend deploy (sibling PRs). Old-frontend degradation window = minutes between announceWinner and beacon upgrade, ops-controlled.

Known limitation

FOUNDRY_PROFILE=production forge build with tests now hits a YulException (stack-too-deep) inside the giant DeployerTest contract — optimizer-on inlining pressure; it persists even with all v6-touched functions stubbed, i.e. marginal-budget instability of that compilation unit, not a specific new function (also repros on solc 0.8.30). The CI gate (default profile) is green, src + scripts compile clean under production, and sims run with --skip test. Not load-bearing for broadcast artifacts.

Cross-repo

Binding spec (events, param order ..., absoluteDeadline, completionWindow, CreateTaskInput field names, zero→null indexing semantics) is mirrored by the subgraph PR (poa-box/subgraph-pop) and frontend PR (poa-frontend) — linked once opened.

🤖 Generated with Claude Code

Core (append-only Task fields; pre-v6 tasks read zeros = no deadlines):
- absoluteDeadline (uint48) + completionWindow (uint32) packed into the
  bountyToken slot; claimDeadline (uint48) derived per claim in slot 5.
- Lenient enforcement: submitTask is never deadline-blocked. An expired
  claim (claimDeadline or absoluteDeadline strictly past while CLAIMED)
  loses protection - claimTask/assignTask/approveApplication take the task
  over in one tx (TaskClaimExpired + lifecycle event + fresh window).
  applyForTask accepts applications on expired claims; rejectTask restarts
  the window; updateTask edits both knobs (past absoluteDeadline allowed on
  update: the admin unstick lever for abandoned claims, incl. pre-v6 ones;
  create paths revert InvalidDeadline on non-future values).
- New events: TaskDeadlinesSet, TaskClaimDeadlineSet, TaskClaimExpired.
  Existing event signatures untouched; emission ordering documented in
  docs/TASK_MANAGER.md for the subgraph.
- Selector replacements (paymaster + frontend ship in lockstep):
  createTask 0x22fa79bc->0x4d0265d4, createTasksBatch 0xc18aa1c9->0xf31d148f,
  createAndAssignTask 0xaf425951->0x98e30e89, updateTask 0x48db6f65->0xb7c288e8
- OrgDeployer: v6 selector strings in _appendTaskManagerRules (count 43).
- TaskManagerLens: 10-field task tuple, new TASK_DEADLINES key, version v2.

Tests: new TaskManagerDeadlineTest (37 cases incl. fuzz expiry boundary and
claim-start-preserving window arithmetic); DeployerTest asserts the v6
selectors in the deploy-time whitelist. Full suite: 1419 passed.

Scripts (sim-first per CLAUDE.md; all 7 sims fork-run to PASS under
FOUNDRY_PROFILE=production):
- upgrades/UpgradeTaskManagerDeadlines: 3-step cross-chain upgrade; v6
  probed FREE (registry + CREATE2) on Gnosis AND Arbitrum; DryRuns on both
  chains exercise live proxies end-to-end (pre-v6 zero-state, born-expired
  revert, window start, expiry boundary, takeover, lenient late submit,
  window arithmetic, deadline-less protection).
- upgrades/UpgradeOrgDeployerDeadlineRules: OrgDeployer v15 (probed FREE).
- fixes/WhitelistTaskDeadlineRules{Poa,Test6Kubi,DecentralPark}ViaGovernance:
  per-org proposals allowing the 4 v6 selectors and disallowing the 4 dead
  v5 ones; sims run create->vote->warp->announceWinner and assert getRule.

Known limitation: FOUNDRY_PROFILE=production forge build (with tests) hits
a YulException stack-too-deep in test/DeployerTest.t.sol from optimizer-on
inlining pressure in that giant test contract. The CI gate (default
profile) is green; src + scripts compile clean under production; sims run
with --skip test. Not load-bearing for broadcast artifacts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant