Skip to content

feat: check risk strategies - #1429

Open
Dodecahedr0x wants to merge 1 commit into
dode/crank-refactorfrom
dode/configurable-aml-checks
Open

feat: check risk strategies#1429
Dodecahedr0x wants to merge 1 commit into
dode/crank-refactorfrom
dode/configurable-aml-checks

Conversation

@Dodecahedr0x

@Dodecahedr0x Dodecahedr0x commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduce a configurable risk checking strategy: aggressively check all delegation actions, or only those involving programs relevant to money laundering: token programs and the magic program. Closes #1435

Breaking Changes

  • None, but a new optional config field

Summary by CodeRabbit

  • New Features

    • Added configurable AML verification strategies for all signers or only relevant program activity.
    • Risk checks now use a dedicated risk server, with relevant-program checks enabled by default.
    • Migrated task scheduling to Hydra cranks, including task creation, cancellation, funding, and faucet delegation.
    • Added configurable faucet keypair support for scheduler operations.
  • Documentation

    • Updated configuration guidance for risk-server settings, AML strategies, and scheduler faucet setup.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds configurable AML risk checking with AllSigners and RelevantPrograms. The risk client now uses a risk-server verdict. The task scheduler now creates and cancels faucet-funded Hydra cranks instead of storing tasks in SQLite. Validator startup delegates the configured faucet. Legacy crank execution support was removed.

Assessment against linked issues:

Objective Addressed Explanation
Add configurable risk checking to avoid checking all addresses for every action [#1435]

Assessment against linked issues: Out-of-scope changes:

Code Change Explanation
Hydra crank scheduler migration (magicblock-task-scheduler/src/service.rs:1-320, magicblock-task-scheduler/src/crank.rs:1-183) Replaces SQLite task scheduling with Hydra crank creation and cancellation. This is not part of configurable AML risk checking.
Faucet delegation and scheduler startup changes (bins/magicblock-validator/src/crank_faucet.rs:12-139, bins/magicblock-validator/src/leader.rs:176-193,539-567) Adds faucet delegation and scheduler initialization behavior unrelated to the linked AML objective.
Legacy crank execution removal (magicblock-magic-program-api/src/instruction.rs:306, programs/magicblock/src/magicblock_processor.rs:171-174) Removes the ExecuteCrank instruction and processor entrypoint. This is outside the linked risk-checking objective.

Suggested reviewers: bmuddha, gabrielepicco, thlorenz

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dode/configurable-aml-checks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Dodecahedr0x
Dodecahedr0x force-pushed the dode/configurable-aml-checks branch 2 times, most recently from 65d1e07 to 5104c59 Compare July 30, 2026 16:53
@Dodecahedr0x
Dodecahedr0x changed the base branch from master to engine-integration July 30, 2026 16:53
@bmuddha
bmuddha force-pushed the engine-integration branch 13 times, most recently from 7f9ba49 to 8a4f601 Compare August 4, 2026 14:07
@Dodecahedr0x
Dodecahedr0x force-pushed the dode/configurable-aml-checks branch from 5104c59 to b7addc0 Compare August 4, 2026 15:22

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs`:
- Around line 1577-1582: The signer collection in lines 1584-1602 currently
includes signers from all delegation_actions regardless of the check_strategy
result, which defeats the risk-check optimization. After the
delegation_actions_require_risk_check guard, add conditional logic based on
risk_service.check_strategy(): when the strategy indicates RelevantPrograms,
filter the actions with instruction_involves_risk_relevant_program before
collecting signers; when the strategy indicates AllSigners, preserve the current
behavior of collecting from all actions. Also add a test case that validates the
filtering behavior by including a mixed batch with both relevant and unrelated
actions to ensure only relevant signers are sent to check_addresses.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 37aea70b-9b7d-4458-a5a8-acf7df61fc2d

📥 Commits

Reviewing files that changed from the base of the PR and between 65d1e07 and b7addc0.

📒 Files selected for processing (7)
  • config.example.toml
  • magicblock-aml/src/lib.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs
  • magicblock-chainlink/tests/10_aml_undelegation.rs
  • magicblock-config/src/config/chain.rs
  • magicblock-config/src/config/mod.rs

Comment thread magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs
@bmuddha
bmuddha force-pushed the engine-integration branch 4 times, most recently from 39529ab to fc4f0d6 Compare August 4, 2026 20:01
@Dodecahedr0x
Dodecahedr0x force-pushed the dode/configurable-aml-checks branch from b7addc0 to 4de6e54 Compare August 4, 2026 21:53
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@bmuddha
bmuddha changed the base branch from engine-integration to graphite-base/1429 August 4, 2026 23:40
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 4de6e54 to f269963 Compare August 5, 2026 18:27
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from f269963 to 15ec769 Compare August 5, 2026 18:32
@bmuddha
bmuddha force-pushed the engine-integration branch from 835518e to ec9b7ed Compare August 5, 2026 18:32
@bmuddha
bmuddha changed the base branch from engine-integration to dode/crank-refactor August 5, 2026 18:33

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.agents/context/crates/magicblock-task-scheduler.md:
- Around line 75-78: Rewrite the entire guide to match the current stateless
faucet-funded Hydra crank implementation. Remove references to the nonexistent
db module, SchedulerDatabase, DbTask, SQLite, migrate_persisted_tasks,
DelayQueue, retry state, failed-record cleanup, and the obsolete
TaskSchedulerService::new(path, ...) API; instead document only the exported
crank, errors, and service modules and the behavior implemented by
TaskSchedulerService and its current runtime flow.
- Around line 75-78: Update the relevant change log or task note in
.agents/AGENTS.md to record the addition or modification of
magicblock-task-scheduler.md, preserving the existing weekly documentation
maintenance path and surrounding entries.

In `@bins/magicblock-validator/src/crank_faucet.rs`:
- Around line 63-76: Update the faucet-account handling around faucet_account to
log faucet_account.lamports at info level, and emit a warning when the balance
is below the minimum required to fund one crank. Preserve the existing skip
behavior for a missing account and continue delegation for balances that meet
the threshold.
- Around line 56-79: Replace direct indexing of the get_multiple_accounts result
in the faucet delegation flow with slice destructuring that safely handles
truncated responses and returns FailedToDelegateFaucet for malformed lengths.
Use faucet_account_opt.as_ref() and delegation_record_opt.as_ref() in the
existing account checks, preserving the current delegation behavior for valid
responses.

In `@bins/magicblock-validator/src/leader.rs`:
- Around line 539-567: The scheduler currently starts before the detached faucet
setup completes, allowing requests to reach TaskSchedulerService prematurely.
Update the startup flow around the faucet setup block and scheduler start so
scheduler processing begins only after ensure_faucet_delegated_on_chain
succeeds, or otherwise gate TaskSchedulerService request handling until faucet
delegation is confirmed with retry behavior.

In `@magicblock-aml/src/lib.rs`:
- Around line 132-146: Update assess_address to retry transient transport errors
and HTTP 5xx responses using a bounded backoff before returning failure, while
preserving the existing request and deserialization behavior. Do not retry
definitive responses or successful RiskAssessment values; continue propagating
final errors so the existing fail-closed handling remains unchanged.

In `@magicblock-config/src/tests.rs`:
- Around line 108-131: Update the risk_configuration_loads_from_toml test
fixture to use the HTTPS risk-server-url expected by
RiskService::try_from_config, while preserving the enabled flag and existing
timeout assertions.

In `@magicblock-task-scheduler/src/errors.rs`:
- Around line 25-30: Remove the unused FaucetNotReady and legacy
TaskSchedulerError variants from errors.rs, retaining only variants constructed
by the Hydra task-scheduler path. Update the TaskSchedulerError definition
without changing the existing Engine error conversion.

In `@magicblock-task-scheduler/src/service.rs`:
- Around line 137-142: Update the invalid-schedule and non-positive-iterations
early-return paths in the task scheduling flow to emit a warn! containing the
task ID before returning Ok(()). Remove the redundant clamp around
task.execution_interval_millis and use the validated interval directly,
preserving the existing validation behavior.
- Around line 265-282: Update the submit/process_request flow so failed task
submissions are not silently discarded: add bounded retries with backoff around
transaction creation and scheduling, or persist failed requests for later retry.
Preserve the existing TaskSchedulerError propagation after retries are
exhausted, and document the behavior in the crate documentation if task dropping
is intentionally accepted.
- Around line 285-321: Extend the tests module around test_service with coverage
for the new crank paths: assert send_create builds the expected instruction list
for both a new crank and an existing crank, including the prepended cancel
instruction on reschedule. Add assertions for interval-to-slot conversion and
deterministic PDA derivation, and verify funding equals iterations multiplied by
CRANKER_REWARD plus crank_rent_floor(instructions).
- Around line 157-169: Update process_cancel_request to call the existing
crank_exists check for the derived crank before invoking send_cancel. If the
crank is absent, return Ok(()) without submitting a transaction or logging
cancellation; otherwise preserve the current send_cancel and success behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ef494625-57db-4d98-85aa-c736afb02c3d

📥 Commits

Reviewing files that changed from the base of the PR and between 835518e and f269963.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
  • test-integration/programs/hydra/hydra.so is excluded by !**/*.so
📒 Files selected for processing (48)
  • .agents/context/crates/magicblock-task-scheduler.md
  • Cargo.toml
  • bins/magicblock-validator/Cargo.toml
  • bins/magicblock-validator/src/crank_faucet.rs
  • bins/magicblock-validator/src/errors.rs
  • bins/magicblock-validator/src/leader.rs
  • bins/magicblock-validator/src/main.rs
  • config.example.toml
  • magicblock-aml/Cargo.toml
  • magicblock-aml/src/lib.rs
  • magicblock-chainlink/src/chainlink/errors.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs
  • magicblock-chainlink/src/chainlink/mod.rs
  • magicblock-chainlink/tests/10_aml_undelegation.rs
  • magicblock-config/src/config/chain.rs
  • magicblock-config/src/config/mod.rs
  • magicblock-config/src/config/scheduler.rs
  • magicblock-config/src/consts.rs
  • magicblock-config/src/lib.rs
  • magicblock-config/src/tests.rs
  • magicblock-config/src/types/crypto.rs
  • magicblock-config/src/types/mod.rs
  • magicblock-magic-program-api/src/instruction.rs
  • magicblock-magic-program-api/src/lib.rs
  • magicblock-magic-program-api/src/pda.rs
  • magicblock-runtime/src/lib.rs
  • magicblock-task-scheduler/Cargo.toml
  • magicblock-task-scheduler/src/crank.rs
  • magicblock-task-scheduler/src/db.rs
  • magicblock-task-scheduler/src/errors.rs
  • magicblock-task-scheduler/src/lib.rs
  • magicblock-task-scheduler/src/service.rs
  • programs/magicblock/src/ephemeral_accounts/mod.rs
  • programs/magicblock/src/magicblock_processor.rs
  • programs/magicblock/src/schedule_task/mod.rs
  • programs/magicblock/src/schedule_task/process_execute_task.rs
  • programs/magicblock/src/schedule_task/process_schedule_task.rs
  • programs/magicblock/src/utils/instruction_utils.rs
  • test-integration/Cargo.toml
  • test-integration/configs/schedule-task.devnet.toml
  • test-integration/test-aml/src/lib.rs
  • test-integration/test-aml/tests/range_mock.rs
  • test-integration/test-task-scheduler/Cargo.toml
  • test-integration/test-task-scheduler/src/lib.rs
  • test-integration/test-task-scheduler/tests/test_schedule_magic_cpi_crank.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task.rs
  • test-integration/test-task-scheduler/tests/test_undrained_faucet.rs
💤 Files with no reviewable changes (5)
  • magicblock-magic-program-api/src/pda.rs
  • magicblock-magic-program-api/src/instruction.rs
  • programs/magicblock/src/schedule_task/process_execute_task.rs
  • test-integration/test-task-scheduler/tests/test_schedule_magic_cpi_crank.rs
  • magicblock-task-scheduler/src/db.rs

@coderabbitai coderabbitai Bot 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 12

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.agents/context/crates/magicblock-task-scheduler.md:
- Around line 75-78: Rewrite the entire guide to match the current stateless
faucet-funded Hydra crank implementation. Remove references to the nonexistent
db module, SchedulerDatabase, DbTask, SQLite, migrate_persisted_tasks,
DelayQueue, retry state, failed-record cleanup, and the obsolete
TaskSchedulerService::new(path, ...) API; instead document only the exported
crank, errors, and service modules and the behavior implemented by
TaskSchedulerService and its current runtime flow.
- Around line 75-78: Update the relevant change log or task note in
.agents/AGENTS.md to record the addition or modification of
magicblock-task-scheduler.md, preserving the existing weekly documentation
maintenance path and surrounding entries.

In `@bins/magicblock-validator/src/crank_faucet.rs`:
- Around line 63-76: Update the faucet-account handling around faucet_account to
log faucet_account.lamports at info level, and emit a warning when the balance
is below the minimum required to fund one crank. Preserve the existing skip
behavior for a missing account and continue delegation for balances that meet
the threshold.
- Around line 56-79: Replace direct indexing of the get_multiple_accounts result
in the faucet delegation flow with slice destructuring that safely handles
truncated responses and returns FailedToDelegateFaucet for malformed lengths.
Use faucet_account_opt.as_ref() and delegation_record_opt.as_ref() in the
existing account checks, preserving the current delegation behavior for valid
responses.

In `@bins/magicblock-validator/src/leader.rs`:
- Around line 539-567: The scheduler currently starts before the detached faucet
setup completes, allowing requests to reach TaskSchedulerService prematurely.
Update the startup flow around the faucet setup block and scheduler start so
scheduler processing begins only after ensure_faucet_delegated_on_chain
succeeds, or otherwise gate TaskSchedulerService request handling until faucet
delegation is confirmed with retry behavior.

In `@magicblock-aml/src/lib.rs`:
- Around line 132-146: Update assess_address to retry transient transport errors
and HTTP 5xx responses using a bounded backoff before returning failure, while
preserving the existing request and deserialization behavior. Do not retry
definitive responses or successful RiskAssessment values; continue propagating
final errors so the existing fail-closed handling remains unchanged.

In `@magicblock-config/src/tests.rs`:
- Around line 108-131: Update the risk_configuration_loads_from_toml test
fixture to use the HTTPS risk-server-url expected by
RiskService::try_from_config, while preserving the enabled flag and existing
timeout assertions.

In `@magicblock-task-scheduler/src/errors.rs`:
- Around line 25-30: Remove the unused FaucetNotReady and legacy
TaskSchedulerError variants from errors.rs, retaining only variants constructed
by the Hydra task-scheduler path. Update the TaskSchedulerError definition
without changing the existing Engine error conversion.

In `@magicblock-task-scheduler/src/service.rs`:
- Around line 137-142: Update the invalid-schedule and non-positive-iterations
early-return paths in the task scheduling flow to emit a warn! containing the
task ID before returning Ok(()). Remove the redundant clamp around
task.execution_interval_millis and use the validated interval directly,
preserving the existing validation behavior.
- Around line 265-282: Update the submit/process_request flow so failed task
submissions are not silently discarded: add bounded retries with backoff around
transaction creation and scheduling, or persist failed requests for later retry.
Preserve the existing TaskSchedulerError propagation after retries are
exhausted, and document the behavior in the crate documentation if task dropping
is intentionally accepted.
- Around line 285-321: Extend the tests module around test_service with coverage
for the new crank paths: assert send_create builds the expected instruction list
for both a new crank and an existing crank, including the prepended cancel
instruction on reschedule. Add assertions for interval-to-slot conversion and
deterministic PDA derivation, and verify funding equals iterations multiplied by
CRANKER_REWARD plus crank_rent_floor(instructions).
- Around line 157-169: Update process_cancel_request to call the existing
crank_exists check for the derived crank before invoking send_cancel. If the
crank is absent, return Ok(()) without submitting a transaction or logging
cancellation; otherwise preserve the current send_cancel and success behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ef494625-57db-4d98-85aa-c736afb02c3d

📥 Commits

Reviewing files that changed from the base of the PR and between 835518e and f269963.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
  • test-integration/programs/hydra/hydra.so is excluded by !**/*.so
📒 Files selected for processing (48)
  • .agents/context/crates/magicblock-task-scheduler.md
  • Cargo.toml
  • bins/magicblock-validator/Cargo.toml
  • bins/magicblock-validator/src/crank_faucet.rs
  • bins/magicblock-validator/src/errors.rs
  • bins/magicblock-validator/src/leader.rs
  • bins/magicblock-validator/src/main.rs
  • config.example.toml
  • magicblock-aml/Cargo.toml
  • magicblock-aml/src/lib.rs
  • magicblock-chainlink/src/chainlink/errors.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs
  • magicblock-chainlink/src/chainlink/fetch_cloner/tests.rs
  • magicblock-chainlink/src/chainlink/mod.rs
  • magicblock-chainlink/tests/10_aml_undelegation.rs
  • magicblock-config/src/config/chain.rs
  • magicblock-config/src/config/mod.rs
  • magicblock-config/src/config/scheduler.rs
  • magicblock-config/src/consts.rs
  • magicblock-config/src/lib.rs
  • magicblock-config/src/tests.rs
  • magicblock-config/src/types/crypto.rs
  • magicblock-config/src/types/mod.rs
  • magicblock-magic-program-api/src/instruction.rs
  • magicblock-magic-program-api/src/lib.rs
  • magicblock-magic-program-api/src/pda.rs
  • magicblock-runtime/src/lib.rs
  • magicblock-task-scheduler/Cargo.toml
  • magicblock-task-scheduler/src/crank.rs
  • magicblock-task-scheduler/src/db.rs
  • magicblock-task-scheduler/src/errors.rs
  • magicblock-task-scheduler/src/lib.rs
  • magicblock-task-scheduler/src/service.rs
  • programs/magicblock/src/ephemeral_accounts/mod.rs
  • programs/magicblock/src/magicblock_processor.rs
  • programs/magicblock/src/schedule_task/mod.rs
  • programs/magicblock/src/schedule_task/process_execute_task.rs
  • programs/magicblock/src/schedule_task/process_schedule_task.rs
  • programs/magicblock/src/utils/instruction_utils.rs
  • test-integration/Cargo.toml
  • test-integration/configs/schedule-task.devnet.toml
  • test-integration/test-aml/src/lib.rs
  • test-integration/test-aml/tests/range_mock.rs
  • test-integration/test-task-scheduler/Cargo.toml
  • test-integration/test-task-scheduler/src/lib.rs
  • test-integration/test-task-scheduler/tests/test_schedule_magic_cpi_crank.rs
  • test-integration/test-task-scheduler/tests/test_schedule_task.rs
  • test-integration/test-task-scheduler/tests/test_undrained_faucet.rs
💤 Files with no reviewable changes (5)
  • magicblock-magic-program-api/src/pda.rs
  • magicblock-magic-program-api/src/instruction.rs
  • programs/magicblock/src/schedule_task/process_execute_task.rs
  • test-integration/test-task-scheduler/tests/test_schedule_magic_cpi_crank.rs
  • magicblock-task-scheduler/src/db.rs
🛑 Comments failed to post (11)
.agents/context/crates/magicblock-task-scheduler.md (1)

75-78: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

The documented database and migration API no longer exists in the crate.

magicblock-task-scheduler/src/lib.rs in this same change exports only crank, errors, and service. The db module, SchedulerDatabase, and DbTask are gone, and magicblock-task-scheduler/Cargo.toml no longer lists a SQLite dependency. magicblock-task-scheduler/src/service.rs contains no migrate_persisted_tasks, no DelayQueue, no retry state, and no failed-record cleanup.

These changed lines describe SQLite migration APIs as present. Line 117 describes a startup migration flow that no code implements. The surrounding unchanged sections — the crate exports at Lines 63-66, the TaskSchedulerService::new(path, config, rpc_url, ...) signature at Line 82, the errors section at Line 101, and the runtime-flow sections through Line 171 — are also stale.

This guide is the document the coding guidelines require an agent to read before changing this crate. Rewrite it to describe the stateless faucet-funded Hydra crank service, or the next change based on it will be wrong.

As per coding guidelines: "Before changing code, consult the matching .agents documentation so the change does not violate validator goals, invariants, performance requirements, or specifications."

Also applies to: 117-117

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/context/crates/magicblock-task-scheduler.md around lines 75 - 78,
Rewrite the entire guide to match the current stateless faucet-funded Hydra
crank implementation. Remove references to the nonexistent db module,
SchedulerDatabase, DbTask, SQLite, migrate_persisted_tasks, DelayQueue, retry
state, failed-record cleanup, and the obsolete TaskSchedulerService::new(path,
...) API; instead document only the exported crank, errors, and service modules
and the behavior implemented by TaskSchedulerService and its current runtime
flow.

Source: Coding guidelines


📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'AGENTS.md' -H
echo "--- references to the task scheduler guide ---"
rg -n 'magicblock-task-scheduler' AGENTS.md 2>/dev/null
echo "--- changed files in this PR ---"
git diff --name-only origin/HEAD...HEAD 2>/dev/null | rg 'AGENTS|\.agents' || echo "no AGENTS.md/.agents entries found in range"

Repository: magicblock-labs/magicblock-validator

Length of output: 1734


🏁 Script executed:

#!/bin/bash
set -u

echo "--- AGENTS.md file existence and references ---"
test -f AGENTS.md && echo "AGENTS.md exists" || echo "AGENTS.md missing"
rg -n 'AGENTS|magicblock-task-scheduler|task scheduler|\.agents|context/crates/magicblock-task-scheduler' AGENTS.md .agents 2>/dev/null || true

echo
echo "--- git diff names across all refs if origin/HEAD unavailable ---"
git diff --name-only HEAD 2>/dev/null | rg '(^AGENTS\.md$|\.agents/)' || true
git diff --name-only --cached 2>/dev/null | rg '(^AGENTS\.md$|\.agents/)' || true
git diff --name-only HEAD~1..HEAD 2>/dev/null | rg '(^AGENTS\.md$|\.agents/)' || true

echo
echo "--- AGENTS.md size and first 120 lines if present ---"
wc -l AGENTS.md 2>/dev/null || true
sed -n '1,120p' AGENTS.md 2>/dev/null || true

echo
echo "--- task scheduler changed diff stat and first 120 relevant lines ---"
git diff --stat -- .agents/context/crates/magicblock-task-scheduler.md 2>/dev/null || true
git diff -- .agents/context/crates/magicblock-task-scheduler.md 2>/dev/null | sed -n '1,180p' || true

Repository: magicblock-labs/magicblock-validator

Length of output: 41920


Update AGENTS.md in the same .agents/ change.

magicblock-task-scheduler.md is modified in this change, but AGENTS.md is not updated to document this .agents/ change. The existing entry already points agents to the weekly documentation maintenance path; update the change log/task note to include this guide update.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.agents/context/crates/magicblock-task-scheduler.md around lines 75 - 78,
Update the relevant change log or task note in .agents/AGENTS.md to record the
addition or modification of magicblock-task-scheduler.md, preserving the
existing weekly documentation maintenance path and surrounding entries.

Source: Coding guidelines

bins/magicblock-validator/src/crank_faucet.rs (2)

56-79: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Do not index the get_multiple_accounts result directly.

accounts[0] at Line 69 and accounts[1] at Line 79 assume the RPC returned exactly two entries. solana_rpc_client does not verify that the response length matches the request length, so a truncated or malformed response panics this task. The task runs inside spawn_primary_onchain_setup, so a panic there aborts validator startup setup without the intended FailedToDelegateFaucet diagnostic.

Destructure the slice instead.

🛠️ Proposed fix
-    let accounts = rpc
+    let accounts = rpc
         .get_multiple_accounts(&[faucet_pubkey, delegation_record_pubkey])
         .await
         .map_err(|err| {
             ApiError::FailedToDelegateFaucet(faucet_pubkey, err.to_string())
         })?;
+    let [faucet_account_opt, delegation_record_opt] = accounts.as_slice()
+    else {
+        return Err(ApiError::FailedToDelegateFaucet(
+            faucet_pubkey,
+            format!(
+                "expected 2 accounts from get_multiple_accounts, got {}",
+                accounts.len()
+            ),
+        ));
+    };

Then use faucet_account_opt.as_ref() at Line 69 and delegation_record_opt.as_ref() at Line 79.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bins/magicblock-validator/src/crank_faucet.rs` around lines 56 - 79, Replace
direct indexing of the get_multiple_accounts result in the faucet delegation
flow with slice destructuring that safely handles truncated responses and
returns FailedToDelegateFaucet for malformed lengths. Use
faucet_account_opt.as_ref() and delegation_record_opt.as_ref() in the existing
account checks, preserving the current delegation behavior for valid responses.

63-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Report the faucet balance so operators can diagnose unfunded faucets.

The function only checks that the faucet account exists. A faucet that exists but holds too few lamports passes delegation and then fails at every crank creation. magicblock-task-scheduler/src/service.rs only logs those failures, so the root cause stays invisible. Log faucet_account.lamports at info level here, and warn when it cannot cover at least one crank.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bins/magicblock-validator/src/crank_faucet.rs` around lines 63 - 76, Update
the faucet-account handling around faucet_account to log faucet_account.lamports
at info level, and emit a warning when the balance is below the minimum required
to fund one crank. Preserve the existing skip behavior for a missing account and
continue delegation for balances that meet the threshold.
bins/magicblock-validator/src/leader.rs (1)

539-567: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Gate scheduler processing on faucet readiness.

The detached setup task delegates the faucet after start() can launch the scheduler. A schedule request can therefore reach TaskSchedulerService before the faucet exists in the ephemeral rollup. The service logs a failed request and does not retry it.

Complete faucet setup before starting the scheduler, or make scheduler request processing wait and retry until the faucet is delegated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bins/magicblock-validator/src/leader.rs` around lines 539 - 567, The
scheduler currently starts before the detached faucet setup completes, allowing
requests to reach TaskSchedulerService prematurely. Update the startup flow
around the faucet setup block and scheduler start so scheduler processing begins
only after ensure_faucet_delegated_on_chain succeeds, or otherwise gate
TaskSchedulerService request handling until faucet delegation is confirmed with
retry behavior.
magicblock-aml/src/lib.rs (1)

132-146: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider a retry for transient risk-server failures.

assess_address propagates every request error, including a connect error, a timeout, and a 5xx status. In magicblock-chainlink/src/chainlink/fetch_cloner/mod.rs (lines 895-898) that error is treated the same as a high-risk signer, so the delegated account is cloned and then scheduled for undelegation. The previous implementation absorbed some of these failures through its local cache, which this change removes.

A single transient failure of the local risk server now undelegates a legitimate account. Add a bounded retry with backoff for transport-level and 5xx failures, and keep the fail-closed behavior for a definitive risky verdict.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-aml/src/lib.rs` around lines 132 - 146, Update assess_address to
retry transient transport errors and HTTP 5xx responses using a bounded backoff
before returning failure, while preserving the existing request and
deserialization behavior. Do not retry definitive responses or successful
RiskAssessment values; continue propagating final errors so the existing
fail-closed handling remains unchanged.
magicblock-config/src/tests.rs (1)

108-131: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a URL accepted by the risk client.

Line 115 configures enabled risk checks with remote plaintext HTTP. RiskService::try_from_config rejects this URL, so this fixture does not represent a valid enabled-risk configuration. Use https://risk.example:3001 instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-config/src/tests.rs` around lines 108 - 131, Update the
risk_configuration_loads_from_toml test fixture to use the HTTPS risk-server-url
expected by RiskService::try_from_config, while preserving the enabled flag and
existing timeout assertions.
magicblock-task-scheduler/src/errors.rs (1)

25-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
for v in FaucetNotReady InvalidConfiguration TransactionExecution UnauthorizedReplacing SizeMismatch Wincode; do
  echo "== $v"
  rg -n "TaskSchedulerError::$v|$v\(" --type=rust -g '!**/errors.rs'
done

Repository: magicblock-labs/magicblock-validator

Length of output: 292


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Repository files of interest =="
git ls-files | rg '(^|/)(errors|service)\.rs$|magicblock-task-scheduler|engine|errors' | sed -n '1,200p'

echo
echo "== errors.rs outline =="
ast-grep outline magicblock-task-scheduler/src/errors.rs || true

echo
echo "== errors.rs content =="
cat -n magicblock-task-scheduler/src/errors.rs

echo
echo "== search TaskSchedulerError variant names outside errors.rs =="
for v in FaucetNotReady InvalidConfiguration TransactionExecution UnauthorizedReplacing SizeMismatch Wincode; do
  echo "== $v =="
  rg -n "TaskSchedulerError::$v|\b$v\b|\b(v|enum TaskSchedulerError|TaskSchedulerError)" --type=rust -g '!**/errors.rs' | sed -n '1,200p' || true
done

echo
echo "== inspect service.rs relevant sections =="
wc -l magicblock-task-scheduler/src/service.rs
sed -n '1,260p' magicblock-task-scheduler/src/service.rs

Repository: magicblock-labs/magicblock-validator

Length of output: 2444


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== task scheduler files =="
wc -l magicblock-task-scheduler/src/*.rs
echo
for f in magicblock-task-scheduler/src/lib.rs magicblock-task-scheduler/src/crank.rs magicblock-task-scheduler/src/service.rs; do
  echo "== $f =="
  sed -n '1,260p' "$f"
done

echo
echo "== exact TaskSchedulerError variant constructor occurrences outside errors.rs =="
python3 - <<'PY'
import re, subprocess
patterns = ["TaskSchedulerError::FaucetNotReady", "InvalidConfiguration(", "TransactionExecution(", "UnauthorizedReplacing(", "SizeMismatch(", "TaskSchedulerError::Wincode", "Engine("]
for pat in patterns:
    p = subprocess.run(["rg", "-n", re.escape(pat), "--type=rust", "-g", "!**/errors.rs"], 
                       text=True, capture_output=True)
    print(f"-- {pat} --")
    print(p.stdout or "")
    print("exit", p.returncode)
PY

Repository: magicblock-labs/magicblock-validator

Length of output: 16344


Remove unused TaskSchedulerError variants.

FaucetNotReady and the legacy variants are only declared; no task-scheduler code outside errors.rs constructs them. Keep only the errors the Hydra path returns.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/errors.rs` around lines 25 - 30, Remove the
unused FaucetNotReady and legacy TaskSchedulerError variants from errors.rs,
retaining only variants constructed by the Hydra task-scheduler path. Update the
TaskSchedulerError definition without changing the existing Engine error
conversion.
magicblock-task-scheduler/src/service.rs (4)

137-142: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Log the silently discarded schedule requests.

Two paths return Ok(()) without any record. Line 137 drops the request when the interval is invalid. Line 182 drops it when iterations <= 0. A later cancel for the same task then fails, and the operator has no log line explaining why the task never ran. Emit a warn! with the task ID in both paths.

Note also that clamp(1, u32::MAX as i64) at Line 141 cannot change the value: is_valid_task_interval already requires 0 < interval < u32::MAX.

🛠️ Proposed logging
         if !is_valid_task_interval(task.execution_interval_millis) {
-            // Too large or zero: ignore.
+            warn!(
+                "Ignoring task {}: interval {}ms is out of range",
+                task.id, task.execution_interval_millis
+            );
             return Ok(());
         }
-        let interval_millis =
-            task.execution_interval_millis.clamp(1, u32::MAX as i64);
+        let interval_millis = task.execution_interval_millis;
         if iterations <= 0 {
+            warn!("Ignoring task {task_id}: iterations is {iterations}");
             return Ok(());
         }

Also applies to: 182-184

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/service.rs` around lines 137 - 142, Update the
invalid-schedule and non-positive-iterations early-return paths in the task
scheduling flow to emit a warn! containing the task ID before returning Ok(()).
Remove the redundant clamp around task.execution_interval_millis and use the
validated interval directly, preserving the existing validation behavior.

157-169: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard the cancel path with crank_exists.

process_cancel_request always submits a cancel instruction. The file already contains crank_exists at Line 197. A cancel for a task whose crank was never created — for example a schedule request that process_schedule_request skipped because iterations <= 0 or the interval was invalid — produces a failed transaction and an error log for a request the program treated as valid.

Check existence first and return Ok(()) when no crank is present.

🛠️ Proposed guard
         let crank =
             crank_pubkey(&cancel_request.authority, cancel_request.task_id);
 
-        // Does not check if the crank exists, so it will fail if it does not exist
+        if !self.crank_exists(&crank) {
+            debug!(
+                "No hydra crank for task {}, nothing to cancel",
+                cancel_request.task_id
+            );
+            return Ok(());
+        }
         self.send_cancel(crank).await?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    async fn process_cancel_request(
        &self,
        cancel_request: &CancelTaskRequest,
    ) -> TaskSchedulerResult<()> {
        let crank =
            crank_pubkey(&cancel_request.authority, cancel_request.task_id);

        if !self.crank_exists(&crank) {
            debug!(
                "No hydra crank for task {}, nothing to cancel",
                cancel_request.task_id
            );
            return Ok(());
        }
        self.send_cancel(crank).await?;
        debug!("Cancelled hydra crank for task {}", cancel_request.task_id);

        Ok(())
    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/service.rs` around lines 157 - 169, Update
process_cancel_request to call the existing crank_exists check for the derived
crank before invoking send_cancel. If the crank is absent, return Ok(()) without
submitting a transaction or logging cancellation; otherwise preserve the current
send_cancel and success behavior.

265-282: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

A failed submission drops the task permanently.

submit returns the scheduling error, process_request logs it at Line 127, and nothing else happens. The service holds no state, so a transient failure — a stale blockhash from self.engine.blockhash(), a temporarily unfunded faucet, or a lost race with hydra closing the crank — silently discards a task the user already paid to schedule. The removed database previously provided the retry path.

Add bounded retry with backoff for submission failures, or record the failed request so it can be retried. State explicitly in the crate documentation if dropping the task is the accepted behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/service.rs` around lines 265 - 282, Update the
submit/process_request flow so failed task submissions are not silently
discarded: add bounded retries with backoff around transaction creation and
scheduling, or persist failed requests for later retry. Preserve the existing
TaskSchedulerError propagation after retries are exhausted, and document the
behavior in the crate documentation if task dropping is intentionally accepted.

285-321: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for the new crank paths.

The only remaining test asserts shutdown on cancellation. The rewrite introduced the funding calculation, the reschedule path that prepends a cancel instruction, the interval-to-slot conversion, and the deterministic PDA derivation. None of them are covered. Add tests that assert the instruction list send_create builds for a new crank and for an existing crank, and that funding equals iterations * CRANKER_REWARD + crank_rent_floor(instructions).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@magicblock-task-scheduler/src/service.rs` around lines 285 - 321, Extend the
tests module around test_service with coverage for the new crank paths: assert
send_create builds the expected instruction list for both a new crank and an
existing crank, including the prepended cancel instruction on reschedule. Add
assertions for interval-to-slot conversion and deterministic PDA derivation, and
verify funding equals iterations multiplied by CRANKER_REWARD plus
crank_rent_floor(instructions).

@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 15ec769 to 6863017 Compare August 6, 2026 17:46
@bmuddha
bmuddha force-pushed the dode/crank-refactor branch from 87d5e7c to 1e477a3 Compare August 6, 2026 17:46
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 6863017 to ea76e6a Compare August 7, 2026 18:36
@bmuddha
bmuddha force-pushed the dode/crank-refactor branch from 405bd42 to c4a54d5 Compare August 7, 2026 18:36
@Dodecahedr0x
Dodecahedr0x force-pushed the dode/configurable-aml-checks branch from ea76e6a to dee4d61 Compare August 10, 2026 09:00
@Dodecahedr0x
Dodecahedr0x changed the base branch from dode/crank-refactor to dode/external-risk-server August 10, 2026 09:01
@bmuddha
bmuddha force-pushed the dode/external-risk-server branch from c40cc22 to dd316c3 Compare August 10, 2026 14:54
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from dee4d61 to 9ae900f Compare August 10, 2026 14:54
@Dodecahedr0x
Dodecahedr0x force-pushed the dode/external-risk-server branch 2 times, most recently from c40cc22 to 836e5f9 Compare August 11, 2026 07:47
@bmuddha
bmuddha force-pushed the dode/external-risk-server branch from 836e5f9 to 2e64b83 Compare August 11, 2026 13:09
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 9ae900f to 27e8c37 Compare August 11, 2026 13:09
@bmuddha
bmuddha changed the base branch from dode/external-risk-server to dode/crank-refactor August 11, 2026 13:10
@bmuddha
bmuddha force-pushed the dode/crank-refactor branch from 4761dba to dcebe2c Compare August 11, 2026 13:25
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 27e8c37 to f23a497 Compare August 11, 2026 13:25
@bmuddha
bmuddha force-pushed the dode/crank-refactor branch from dcebe2c to 7368b12 Compare August 11, 2026 14:39
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from f23a497 to 845638d Compare August 11, 2026 14:39
@bmuddha
bmuddha force-pushed the dode/crank-refactor branch from 7368b12 to c0554ec Compare August 12, 2026 06:23
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 845638d to 3288f82 Compare August 12, 2026 06:23
@bmuddha
bmuddha force-pushed the dode/crank-refactor branch from c0554ec to 0b69900 Compare August 12, 2026 07:51
@bmuddha
bmuddha force-pushed the dode/configurable-aml-checks branch from 3288f82 to 25ec8f8 Compare August 12, 2026 07:51
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.

feat: configurable risk check strategies

2 participants