Skip to content

feat(tasks): add task status files and scaffolder - #821

Merged
jackchuma merged 5 commits into
mainfrom
toshi/chain-5952-task-status-scaffolder
Oct 19, 2026
Merged

jackchuma merged 5 commits into
mainfrom
toshi/chain-5952-task-status-scaffolder

Conversation

@jackchuma

@jackchuma jackchuma commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

What changed? Why?

Every task now carries a machine-readable status.json that humans and the contract-ops bot both read and update, and one make target scaffolds new tasks with it. Today a task's progress (which step each network is at, its PR, BlockSec ticket, signatures, execution) lives only in people's heads, Slack threads and the signer README's Status: line, so nothing can tell at a glance what is waiting on whom.

  • Status file. status.json sits at the task root: active/evm/tasks/<task-id>/status.json, or standby/evm/tasks/<operation>/status.json while a standby invocation exists. Per network it records step (authoring, validation, review, ready_to_sign, collecting, ready_to_execute, executed, canceled), pr, blocksec_ticket, signatures (collected/required per validation file) and executed_tx, plus a task-level last_updated. The schema is scripts/task-status.schema.json.

  • Check. scripts/task-status.py check (also make check-task-status) validates every status file against the schema with a small stdlib validator, so the schema file is the single source of truth and CI needs no extra Python packages. It also fails when an active task has no status file, network keys differ from the config/<network>/ directories, executed and executed_tx disagree, a README marked EXECUTED/CANCELED disagrees with the step (either direction), a standby invocation has no status file, or a canonical standby task has one. It runs in a new validate-task-status.yml workflow.

  • Scaffolder. make new-task with exactly one selector:

    • TASK_SLUG=<slug> TASK_NETWORK=<network> [TASK_DATE=YYYY-MM-DD] creates active/evm/tasks/<date>-<slug>/ with a Makefile modeled on the Denim task (command-line TASK_NETWORK guard, global and task .env includes, signer and task-origin paths), a network-agnostic FACILITATOR.md, script/, config/<network>/.env (empty BASE_CONTRACTS_COMMIT so deps fails loudly, no RECORD_STATE_DIFF), a signer README with Status: READY TO SIGN, and status.json.
    • TASK_ID=<active task> TASK_NETWORK=<network> adds a network to an existing active task, per the one-task-many-networks rule in AGENTS.md.
    • STANDBY_OP=<operation> TASK_NETWORK=<network> adds a standby invocation (config/<network>/.env, signer README, status entry) without touching canonical files.

    It refuses overwrites, networks without config/<network>.env, invalid identifiers or dates, a TASK_NETWORK not given on the command line, unknown tasks or operations, and zero or multiple selectors. scripts/task-status.py add-network <task-dir> <network> is the same status step on its own, for other setup scripts and for adopting existing tasks.

  • Standby archival. scripts/standby-task.py treats root status.json as invocation data like config/, records/ and signatures/: it is ignored in the canonical-vs-main comparison, carried into the dated archive and removed from standby.

  • Adoption. The two active tasks on main get a status.json (both executed on Zeronet; tx hashes from their READMEs, PRs from git history). No other file in them changes.

  • Docs. New "Task status and scaffolding" section in README.md; AGENTS.md lifecycle bullets updated.

Notes to reviewers

  • Why the task root and not config/<network>/: task-origin signing signs over config/<network> (TASK_ORIGIN_DIR), so a status update after signing would change the signed payload. A test asserts scaffolded status files never land inside a config directory.
  • Open PRs that add networks or tasks need a status entry once this merges, or the new check fails on them: the Denim Sepolia invocation (feat(sepolia): add Denim upgrade with L2 predeploys #819) needs a sepolia entry in the Denim status.json, and the tasks added by feat(zeronet): add Denim SystemConfig gas parameters task #808, feat(sepolia): replace BalanceTracker and repoint FeeDisburser (CHAIN-1245) #807 and feat(CHAIN-4644): update Sepolia BalanceTracker profit wallet #768 each need their own status.json. One command each: python3 scripts/task-status.py add-network <task-dir> <network>, then set the step.
  • Signing scope of hand-written tasks: status.json stays out of the signed payload only when a task's Makefile scopes TASK_ORIGIN_DIR to config/<network>, as Denim and the scaffolded Makefile do. 2026-10-15-upgrade-l2-predeploys keeps the root default (the whole task directory), which already includes mutable records/ and other networks' files; its executed Zeronet invocation skips task-origin validation. Any future rollout of that task that collects task-origin signatures should add the same override. This PR leaves its Makefile unchanged.
  • Relation to other open PRs:
    • feat: add reusable active EVM task workflows #778 (reusable active EVM task workflows): no shared scripts or workflows, but both PRs edit README.md, so expect a small README conflict. That PR moves task Makefiles to a thin Task.mk dispatched from active/evm/Makefile, and its dispatcher reads a per-network config/<network>/network.env. The scaffolder writes today's Denim-style Makefile and .env; if feat: add reusable active EVM task workflows #778 lands, the templates in scripts/new-task.py need to switch to Task.mk and its config files. Status files and the check do not depend on the Makefile layout.
    • feat: add pause task setup command #789 (pause task setup command): that is a specialized setup for pause tasks; this is a generic scaffolder and does not duplicate it. The new root targets sit after archive-task so they don't collide textually with where feat: add pause task setup command #789 adds setup-pause-task. Pause tasks it creates will need a status file; setup-pause-task.sh can call scripts/task-status.py add-network to write it.
    • feat(KEYS-5638): task signature checking #565 (task signature checking): keeping status.json outside config/<network> means status updates never change the checksum that creators and facilitators sign, so the two checks don't interfere.
    • docs: align README with task-local workflows #780 (README alignment): README changes here are limited to one new section before "CI script validation", one line in the directory tree and one sentence in the standby section, written as unwrapped prose per that PR's convention, to keep the merge small.
  • The validation-file-vs-script CI check from the same milestone is a separate change.

How has it been tested?

  • python3 -B -m unittest scripts.tests.test_task_status scripts.tests.test_standby_lifecycle -v: 34 tests pass. New tests drive make new-task and check in temporary git repos: every refusal, every failing check above, all three scaffold modes passing check, the scaffolded Makefile parsing and rejecting a missing TASK_NETWORK, and lossless standby archival with a status file present.
  • python3 -B scripts/task-status.py check passes on the repository.
  • Scaffolded a task in a scratch clone and compared it with the Denim task. The scaffold has the same layout minus generated artifacts (validations/, records/, addresses.json) and task-specific Solidity:
Scaffolded task              Denim task (tracked)
FACILITATOR.md               FACILITATOR.md
Makefile                     Makefile
config/zeronet/.env          config/zeronet/.env
config/zeronet/README.md     config/zeronet/README.md
                             config/zeronet/addresses.json
                             config/zeronet/validations/*.json
                             records/<script>/<chain-id>/*.json
script/.gitkeep              script/*.sol
status.json                  status.json

Generated with Toshi

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
@cb-heimdall

cb-heimdall commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Heimdall Review Status

Requirement Status More Info
Reviews ✅ 2/2
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 2
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 2
2
1 if commit is unverified 0
Sum 2

⚠️ Ignored Reviews (2)

Reviewer Reason
0xth4nh Old or outdated review
0xth4nh Review missing MFA

@linear

linear Bot commented Oct 17, 2026

Copy link
Copy Markdown

CHAIN-5952

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
@jackchuma

Copy link
Copy Markdown
Contributor Author

Review round 1

Reviewers: anthropic/claude-opus-5-5, cbhq-openai/gpt-6.1-sol (parallel)

  • Fixed: [P2] Standby facilitator guides did not cover status.json (opus) — standby/evm/tasks/*/FACILITATOR.md (b399229)
  • Fixed: [P2] Test pinned the two live active tasks (opus + gpt) — scripts/tests/test_task_status.py (b399229)
  • Fixed: [P2] Standby test fixtures copied live invocation artifacts (gpt) — scripts/tests/test_task_status.py (b399229)
  • Fixed: [P2] Standby archival accepted an invalid or unfinalized status.json (gpt) — scripts/standby-task.py (b399229)
  • Fixed: [P2] Check ignored status.json inside signed config// (gpt) — scripts/task-status.py (b399229)
  • Description: corrected the feat: add reusable active EVM task workflows #778 overlap note (both PRs edit README.md; its config//network.env layout).
    Synced with main: 796a45c (already current)
    Validation: 35 unit tests pass (task status + standby lifecycle), task-status.py check passes, git diff --check clean.

🤖 Reply generated with Toshi

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
@jackchuma

Copy link
Copy Markdown
Contributor Author

Review round 2

Reviewers: anthropic/claude-opus-5-5, cbhq-openai/gpt-6.1-sol (parallel)

🤖 Reply generated with Toshi

@jackchuma

Copy link
Copy Markdown
Contributor Author

Review round 3

Reviewers: anthropic/claude-opus-5-5, cbhq-openai/gpt-6.1-sol (parallel)

  • Fixed: [P3] Schema patterns accepted values with a trailing newline (opus) — scripts/task-status.py (9a77cb4)
  • Dropped in triage: [P2] 2026-10-15-upgrade-l2-predeploys signs its whole task directory, now including status.json (gpt) — pre-existing scope (the directory already holds mutable records and other networks' files), its executed Zeronet invocation skips task-origin validation, and changing that task's Makefile is out of scope here. Noted in the PR description.
    Synced with main: 796a45c (already current)
    Validation: task status suite passes, task-status.py check passes.

🤖 Reply generated with Toshi

@jackchuma

Copy link
Copy Markdown
Contributor Author

Review round 4

Reviewers: anthropic/claude-opus-5-5, cbhq-openai/gpt-6.1-sol (parallel)

  • Opus: no findings.
  • Dropped in triage: [P2] README Status: written in bold or below line 20 is not recognized (gpt) — no task README in active, standby or archive uses either form; the check accepts the same formats and 20-line window that standby archival enforces.
  • Dropped in triage: [P3] last_updated accepts calendar-invalid dates (gpt) — low impact, not in scope.
    Spec check: all acceptance criteria met.
    Synced with main: 796a45c (already current)
    Validation: 17 task status tests and 20 standby lifecycle tests pass, task-status.py check passes.

🤖 Reply generated with Toshi

@jackchuma
jackchuma marked this pull request as ready for review October 17, 2026 20:39

@0xth4nh 0xth4nh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3 (stale docs, outside the diff): standby/evm/tasks/update-verifier-hashes/README.md:5.

Issue: the README still says "Invocations add only config/<network>/.env and a signer README". With this PR every invocation also needs a task-root status.json: make check-task-status fails without one, and standby archival now refuses a network that is not finalized in status.json (scripts/standby-task.py:151-157). The sibling FACILITATOR.md in the same directory, AGENTS.md and the root README were updated; this README line was not.

Impact: an operator who follows this README alone will get a CI failure or an archive refusal.

Requested change: add that an invocation also needs the task-root status.json, created with make new-task STANDBY_OP=update-verifier-hashes ..., as the FACILITATOR now describes.

Co-authored-by: Toshi <toshi-noreply@coinbase.com>
@jackchuma

Copy link
Copy Markdown
Contributor Author

@0xth4nh Fixed in 312b495. standby/evm/tasks/update-verifier-hashes/README.md now says to create an invocation with make new-task STANDBY_OP=update-verifier-hashes TASK_NETWORK=<network>, which adds config/<network>/.env, a signer README and the task-root status.json, matching the FACILITATOR. The delay-upgrade-activation README makes no "only" claim about invocation files, so it is unchanged.

🤖 Reply generated with Toshi

@jackchuma
jackchuma requested a review from 0xth4nh October 19, 2026 18:41

@0xth4nh 0xth4nh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks Good to Thanh's Toshi

@jackchuma
jackchuma merged commit 13b02c7 into main Oct 19, 2026
8 checks passed
@jackchuma
jackchuma deleted the toshi/chain-5952-task-status-scaffolder branch October 19, 2026 19:11
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.

4 participants