Skip to content

test(policy-registry): cross-validate inactive-feature dispatch#158

Merged
stevieraykatz merged 1 commit into
mainfrom
fork-tests/policy-registry-inactive-dispatch
Jun 10, 2026
Merged

test(policy-registry): cross-validate inactive-feature dispatch#158
stevieraykatz merged 1 commit into
mainfrom
fork-tests/policy-registry-inactive-dispatch

Conversation

@stevieraykatz

Copy link
Copy Markdown
Member

What

Adds fork cross-validation for the PolicyRegistry precompile's inactive-feature dispatch path, which the existing fork suite never exercises (it activates every feature before running).

While a feature is inactive, the dispatcher routes view selectors to ABI dispatch but sends every other selector through the activation gate before classification. As a result, error behavior depends on activation state: an unknown selector or a malformed write returns FeatureNotActivated rather than being classified as an unknown-selector / ABI-decode error. Clients, tests, and monitoring then can't distinguish "feature inactive" from "bad calldata" near activation boundaries.

Changes

  • script/run-fork-tests.sh — new SKIP_ACTIVATE env var leaves named features un-activated (matched by canonical name or raw 0x… id, case-insensitive), making the inactive path reachable. Default is empty, so the standard cross-validation run activates everything exactly as before.
  • test/unit/PolicyRegistry/dispatch_inactive.t.sol — fork-only regression tests (the Solidity MockPolicyRegistry models no activation gate, so these run only under LIVE_PRECOMPILES). They normalize the feature to inactive, then assert:
    1. all four view selectors stay callable while inactive;
    2. a malformed view reaches ABI decode (not the gate);
    3. all seven write selectors stay gated by FeatureNotActivated;
    4. an unknown selector is classified rather than masked by the gate.
      Case 4 encodes a dispatch-ordering fix that isn't in the pinned Rust impl yet, so it's gated behind POLICY_DISPATCH_FIX — leave it unset against stock builds (keeps the run green); set it once the fix is in the build to enforce the regression.
  • FORK_TESTING.md — documents both env vars and the inactive-path invocation.

Testing

forge build, forge fmt --check, and forge lint pass; all four tests compile and skip cleanly in mock mode. Live cross-validation runs under the base-anvil toolchain:

SKIP_ACTIVATE=POLICY_REGISTRY ./script/run-fork-tests.sh \
    --match-contract PolicyRegistryDispatchInactive

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

Interface Coverage

✅ All interface functions have test coverage.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

📊 Forge Coverage (src/lib/)

🟢 ≥99% across all metrics.

File Lines Stmts Branches Funcs
🟢 B20FactoryLib.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockActivationRegistry.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockActivationRegistryStorage.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockB20.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockB20Asset.sol 100.00% 100.00% 100.00% 100.00%
🟡 MockB20Factory.sol 98.96% 99.10% 100.00% 100.00%
🟢 MockB20Stablecoin.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockB20Storage.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockPolicyRegistry.sol 100.00% 100.00% 100.00% 100.00%
🟢 MockPolicyRegistryStorage.sol 100.00% 100.00% 100.00% 100.00%
Total 99.86% 99.88% 100.00% 100.00%

Full report: download artifact. To browse locally: make coverage (runs forge coverage + genhtml + opens the HTML report).

@stevieraykatz stevieraykatz force-pushed the fork-tests/policy-registry-inactive-dispatch branch from 03b7857 to 6532c39 Compare June 10, 2026 18:41
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

✅ Fork tests: all 613 passed

base/base is fully in sync with the base-std spec.

While a feature is inactive, the PolicyRegistry dispatcher routes view
selectors to ABI dispatch but sends every other selector through the
activation gate first, so error behavior depends on activation state: an
unknown selector or malformed write returns FeatureNotActivated instead of
being classified. Clients and monitoring can't then distinguish an inactive
feature from bad calldata near activation boundaries.

Add fork cross-validation for the dispatcher's inactive path:

- run-fork-tests.sh: SKIP_ACTIVATE env var leaves named features (by name or
  0x id, case-insensitive) un-activated so the inactive path is reachable;
  default keeps every feature active, so the existing run is unchanged.
- test/unit/PolicyRegistry/dispatch_inactive.t.sol: fork-only tests that
  views stay callable while inactive, a malformed view reaches decode (not
  the gate), writes stay gated by FeatureNotActivated, and an unknown
  selector is classified rather than masked by the gate. The last encodes a
  not-yet-shipped dispatch fix, so it's gated behind POLICY_DISPATCH_FIX.
- FORK_TESTING.md: document both env vars and the inactive-path invocation.

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@stevieraykatz stevieraykatz force-pushed the fork-tests/policy-registry-inactive-dispatch branch from 6532c39 to 614d48d Compare June 10, 2026 18:47
@stevieraykatz stevieraykatz merged commit 524030d into main Jun 10, 2026
10 checks passed
@stevieraykatz stevieraykatz deleted the fork-tests/policy-registry-inactive-dispatch branch June 10, 2026 18:57
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.

2 participants