Skip to content

Recover StreamCore release-floor headroom#133

Merged
punk6529 merged 4 commits into
mainfrom
codex/streamcore-size-floor-recovery
Jun 12, 2026
Merged

Recover StreamCore release-floor headroom#133
punk6529 merged 4 commits into
mainfrom
codex/streamcore-size-floor-recovery

Conversation

@punk6529

@punk6529 punk6529 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #132.

This PR recovers the documented StreamCore minimum release-floor headroom after PR #131 left the production IR build below the internal 384-byte floor.

  • Moves collection-script and token-metadata freeze hash helpers from StreamCore into the linked StreamMetadataRenderer library, preserving the typed hash inputs used by freeze manifests.
  • Replaces the old-randomizer pending-request lifecycle helper with equivalent low-level staticcalls so unsupported lifecycle providers still do not block migration, supported providers still block when pending probes fail or report pending requests, and failed pending probes preserve the old provider revert data.
  • Keeps small compiler-shaping savings in Core by inlining final-token metadata checks, reusing known collection IDs in token-name rendering, caching collection script storage during retrieval, and reusing final supply in the freeze supply hash.
  • Adds focused randomizer migration regressions for unsupported lifecycle providers and supported providers whose pending-request probe fails.
  • Refreshes size docs, roadmap/state traceability, changelog, release artifacts, source-verification inputs, deployment examples/address books, release manifest, and checksum bundle.

Size Evidence

Final production size gate:

forge build --sizes --via-ir --skip test --skip script --force
StreamCore             24,139 runtime bytes, 437 bytes EIP-170 headroom
StreamMetadataRenderer 11,111 runtime bytes

This restores StreamCore above the 384-byte minimum release floor while still documenting that it remains below the 512-byte warning threshold for larger future Core feature work.

Validation

  • forge test --match-path test\StreamRandomizerLifecycle.t.sol -vvv
  • Focused sweep: test\StreamRandomizerLifecycle.t.sol, test\StreamMetadataFreeze.t.sol, test\StreamMetadataGolden.t.sol, test\StreamCoreBurn.t.sol
  • make release-checksums
  • make release-checksums-check
  • make check
  • powershell -NoProfile -ExecutionPolicy Bypass -File scripts\check.ps1
  • forge fmt --check smart-contracts\StreamCore.sol smart-contracts\StreamMetadataRenderer.sol test\StreamRandomizerLifecycle.t.sol
  • git diff --check

Known pre-existing warnings remain from the current Natspec/lint/compiler baseline.

Summary by CodeRabbit

  • Bug Fixes

    • Restored documented bytecode release floor and improved deployability by optimizing metadata hashing and finality checks, reducing runtime size (24,348 → 24,139 bytes) and increasing headroom (437 bytes).
  • Tests

    • Added regression tests for randomizer migration: unsupported lifecycle providers won’t block migration; lifecycle-aware providers whose pending-request probe fails will block replacement.
  • Documentation

    • Updated status, roadmap, blockers, and test docs with new size measurements, validation details, and known migration behavior.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f494bc03-16a6-42ae-a73c-705244666505

📥 Commits

Reviewing files that changed from the base of the PR and between 43cad7a and 96b0305.

📒 Files selected for processing (13)
  • deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json
  • deployments/address-books/anvil-6529stream-v0.1.0-001.json
  • deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json
  • deployments/examples/anvil-6529stream-v0.1.0-001.json
  • ops/AUTONOMOUS_RUN.md
  • release-artifacts/latest/SHA256SUMS
  • release-artifacts/latest/abi-checksums.json
  • release-artifacts/latest/release-artifact-manifest.json
  • release-artifacts/latest/release-checksums.json
  • release-artifacts/latest/release-manifest.json
  • release-artifacts/latest/source-verification-inputs.json
  • smart-contracts/StreamCore.sol
  • test/StreamRandomizerLifecycle.t.sol
✅ Files skipped from review due to trivial changes (7)
  • release-artifacts/latest/release-artifact-manifest.json
  • deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json
  • deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json
  • ops/AUTONOMOUS_RUN.md
  • release-artifacts/latest/release-manifest.json
  • release-artifacts/latest/source-verification-inputs.json
  • release-artifacts/latest/release-checksums.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • deployments/address-books/anvil-6529stream-v0.1.0-001.json
  • deployments/examples/anvil-6529stream-v0.1.0-001.json
  • release-artifacts/latest/abi-checksums.json
  • test/StreamRandomizerLifecycle.t.sol
  • smart-contracts/StreamCore.sol

📝 Walkthrough

Walkthrough

This PR reduces StreamCore's bytecode by refactoring freeze-manifest hashing delegation to StreamMetadataRenderer, inlining token finality checks, optimizing storage lookups and on-chain rendering, replacing randomizer lifecycle probes with inline assembly staticcalls, adding regression tests, and updating deployment/release artifact checksums.

Changes

StreamCore Bytecode Headroom Recovery

Layer / File(s) Summary
Freeze Metadata Hashing Delegation to StreamMetadataRenderer
smart-contracts/StreamMetadataRenderer.sol, smart-contracts/StreamCore.sol
StreamMetadataRenderer adds EIP-712-style typehash constants and two new public pure hash helpers (collectionScriptHash, tokenMetadataRecordHash). StreamCore delegates freeze-manifest hashing to these methods and removes the local _collectionScriptHash helper implementation.
Randomizer Lifecycle Probe Hardening via Inline Staticcall
smart-contracts/StreamCore.sol
addRandomizer replaces the prior helper-based pending-request check with an inline assembly/staticcall sequence that conditionally probes lifecycle support and pending requests, preserving revert data and allowing unsupported-lifecycle providers to bypass the check.
Token Metadata View Finality Check Inlining
smart-contracts/StreamCore.sol
tokenURI and tokenMetadataState now determine metadata finality by directly checking tokenToHash[tokenId] != bytes32(0), eliminating the _isTokenMetadataFinal helper function-call overhead.
Token Name and Generative Script Rendering Optimization
smart-contracts/StreamCore.sol
getTokenName now accepts collectionId and computes token index relative to reserved range; retrieveGenerativeScript loads collection script once and concatenates in a loop; _freezeSupplyStateHash passes finalSupply consistently; _onchainTokenURI passes collectionId to avoid redundant lookup.
Randomizer Lifecycle Regression Test Coverage
test/StreamRandomizerLifecycle.t.sol
Two new mock randomizers (UnsupportedLifecycleRandomizer, RevertingPendingLifecycleRandomizer) and two migration-focused tests verify that unsupported-lifecycle providers do not block migration, while lifecycle-aware providers with failed probes still prevent replacement.
Changelog, Status, and Roadmap Documentation Updates
CHANGELOG.md, docs/status.md, docs/known-blockers.md, ops/ROADMAP.md, ops/AUTONOMOUS_RUN.md, test/README.md
CHANGELOG documents randomizer migration regression coverage and size-floor recovery mechanics. Status and roadmap files update StreamCore runtime size to 24,139 bytes with 437 bytes EIP-170 headroom. Autonomous run state and queue progression are recorded. Test documentation is updated to reflect new bytecode budget figures.
Deployment Address Books, Examples, and Release Artifact Checksums
deployments/address-books/*, deployments/examples/*, release-artifacts/latest/*
All address books, example manifests, checksum lists, ABI checksums, source verification inputs, and release artifact manifests are updated to reflect new bytecode hashes for DependencyRegistry and StreamCore, along with refreshed SHA-256 digests for generated manifests and library-linking reference positions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped through hashes, lightened the load,
moved frozen hashes out to the renderer's road.
Inlined a check, stitched scripts in a loop,
taught the randomizer a careful staticcall swoop.
Tiny bytes saved — a rabbit's quiet code-skip. 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main objective: recovering StreamCore's release-floor bytecode headroom, which is the primary goal of all changes in this PR.
Linked Issues check ✅ Passed The code changes fully address issue #132's objectives: moving freeze-hash helpers to StreamMetadataRenderer, replacing the randomizer pending-request helper with staticcalls, adding focused randomizer migration regression tests, and achieving the documented 384-byte minimum release floor with 437 bytes headroom.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #132: refactoring freeze-hash helpers, updating randomizer lifecycle checks, improving compiler efficiency, adding regression tests, and updating documentation/release artifacts to reflect the new bytecode measurements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/streamcore-size-floor-recovery

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

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
test/StreamRandomizerLifecycle.t.sol (2)

16-30: 💤 Low value

Consider adding a clarifying comment for the defensive revert.

The pendingRandomnessRequests method reverts even though this mock advertises that it does not support the randomizer lifecycle. While this is good defensive programming (it makes bugs obvious if StreamCore incorrectly calls this method), a brief comment would help future readers understand the intent.

📝 Suggested clarification
+    // Defensive: reverts if called despite unsupported lifecycle flag
     function pendingRandomnessRequests(uint256) external pure returns (uint256) {
         revert("unsupported lifecycle pending probe");
     }
🤖 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 `@test/StreamRandomizerLifecycle.t.sol` around lines 16 - 30, Add a brief
clarifying comment in the UnsupportedLifecycleRandomizer contract explaining
that pendingRandomnessRequests deliberately reverts as defensive programming
because supportsRandomizerLifecycle() returns false; the comment should state
that the revert makes bugs obvious if StreamCore (or any caller) incorrectly
calls pendingRandomnessRequests on a randomizer that does not support lifecycle,
and briefly note this is intentional rather than unfinished test scaffolding.
Locate the contract UnsupportedLifecycleRandomizer and add the comment
immediately above the pendingRandomnessRequests function declaration.

371-382: 💤 Low value

Consider verifying the CollectionRandomizerUpdated event emission.

For consistency with the existing testRandomizerMigrationWithNoPendingRequestsSucceedsAndEmitsEpoch test (line 355), consider adding event verification to confirm both randomizer updates emit the expected CollectionRandomizerUpdated event with correct epoch values.

📋 Optional event verification
     function testUnsupportedLifecycleRandomizerDoesNotBlockMigration() public {
         DeployedStream memory deployed = deployStream(PAYOUT, CURATORS_POOL);
         UnsupportedLifecycleRandomizer unsupported = new UnsupportedLifecycleRandomizer();
         NoopRandomizer replacement = new NoopRandomizer();
 
         deployed.core.addRandomizer(COLLECTION_ID, address(unsupported));
+        vm.recordLogs();
         deployed.core.addRandomizer(COLLECTION_ID, address(replacement));
+        _assertCollectionRandomizerUpdated(
+            vm.getRecordedLogs(), address(deployed.core), address(unsupported), address(replacement), 3
+        );
 
         deployed.core.viewCollectionRandomizerContract(COLLECTION_ID)
             .assertEq(address(replacement), "replacement");
         deployed.core.viewRandomizerEpoch(COLLECTION_ID).assertEq(3, "epoch");
     }
🤖 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 `@test/StreamRandomizerLifecycle.t.sol` around lines 371 - 382, Add assertions
to testUnsupportedLifecycleRandomizerDoesNotBlockMigration to verify the
CollectionRandomizerUpdated events are emitted for both addRandomizer calls:
after deployed.core.addRandomizer(COLLECTION_ID, address(unsupported)) and after
deployed.core.addRandomizer(COLLECTION_ID, address(replacement)). Use the same
event-check pattern as in
testRandomizerMigrationWithNoPendingRequestsSucceedsAndEmitsEpoch to assert
CollectionRandomizerUpdated was emitted with the expected epochs (the epoch
increment when adding unsupported, and the final epoch of 3 after adding
replacement), while keeping the existing checks for
viewCollectionRandomizerContract and viewRandomizerEpoch.
smart-contracts/StreamCore.sol (1)

366-392: Selectors in StreamCore.sol match IRandomizerLifecycle.

In smart-contracts/StreamCore.sol (lines 366-392), the inline-assembly selectors are consistent with the interface:

  • supportsRandomizerLifecycle() => 0x81d673e0
  • pendingRandomnessRequests(uint256) => 0xdd26bdd1

Optional: add a short inline comment mapping these values to the interface signatures for maintainability.

🤖 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 `@smart-contracts/StreamCore.sol` around lines 366 - 392, The inline-assembly
uses hardcoded selectors for supportsRandomizerLifecycle() and
pendingRandomnessRequests(uint256) but lacks explicit explanation; add short
inline comments next to the mstore selector constants in the assembly block (the
lines storing 0x81d673e0... and 0xdd26bdd1...) that map each hex selector to its
ABI function signature (e.g., // supportsRandomizerLifecycle() and //
pendingRandomnessRequests(uint256)), leaving the logic intact and referencing
the same symbols (oldRandomizer, pendingRequests, supportsRandomizerLifecycle,
pendingRandomnessRequests) so future maintainers can quickly see which interface
methods those selectors correspond to.
🤖 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.

Nitpick comments:
In `@smart-contracts/StreamCore.sol`:
- Around line 366-392: The inline-assembly uses hardcoded selectors for
supportsRandomizerLifecycle() and pendingRandomnessRequests(uint256) but lacks
explicit explanation; add short inline comments next to the mstore selector
constants in the assembly block (the lines storing 0x81d673e0... and
0xdd26bdd1...) that map each hex selector to its ABI function signature (e.g.,
// supportsRandomizerLifecycle() and // pendingRandomnessRequests(uint256)),
leaving the logic intact and referencing the same symbols (oldRandomizer,
pendingRequests, supportsRandomizerLifecycle, pendingRandomnessRequests) so
future maintainers can quickly see which interface methods those selectors
correspond to.

In `@test/StreamRandomizerLifecycle.t.sol`:
- Around line 16-30: Add a brief clarifying comment in the
UnsupportedLifecycleRandomizer contract explaining that
pendingRandomnessRequests deliberately reverts as defensive programming because
supportsRandomizerLifecycle() returns false; the comment should state that the
revert makes bugs obvious if StreamCore (or any caller) incorrectly calls
pendingRandomnessRequests on a randomizer that does not support lifecycle, and
briefly note this is intentional rather than unfinished test scaffolding. Locate
the contract UnsupportedLifecycleRandomizer and add the comment immediately
above the pendingRandomnessRequests function declaration.
- Around line 371-382: Add assertions to
testUnsupportedLifecycleRandomizerDoesNotBlockMigration to verify the
CollectionRandomizerUpdated events are emitted for both addRandomizer calls:
after deployed.core.addRandomizer(COLLECTION_ID, address(unsupported)) and after
deployed.core.addRandomizer(COLLECTION_ID, address(replacement)). Use the same
event-check pattern as in
testRandomizerMigrationWithNoPendingRequestsSucceedsAndEmitsEpoch to assert
CollectionRandomizerUpdated was emitted with the expected epochs (the epoch
increment when adding unsupported, and the final epoch of 3 after adding
replacement), while keeping the existing checks for
viewCollectionRandomizerContract and viewRandomizerEpoch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e26a623e-f6cf-487c-8477-862923fbd645

📥 Commits

Reviewing files that changed from the base of the PR and between 3a6405d and 43cad7a.

📒 Files selected for processing (19)
  • CHANGELOG.md
  • deployments/address-books/anvil-6529stream-v0.1.0-001-broadcast.json
  • deployments/address-books/anvil-6529stream-v0.1.0-001.json
  • deployments/examples/anvil-6529stream-v0.1.0-001-broadcast.json
  • deployments/examples/anvil-6529stream-v0.1.0-001.json
  • docs/known-blockers.md
  • docs/status.md
  • ops/AUTONOMOUS_RUN.md
  • ops/ROADMAP.md
  • release-artifacts/latest/SHA256SUMS
  • release-artifacts/latest/abi-checksums.json
  • release-artifacts/latest/release-artifact-manifest.json
  • release-artifacts/latest/release-checksums.json
  • release-artifacts/latest/release-manifest.json
  • release-artifacts/latest/source-verification-inputs.json
  • smart-contracts/StreamCore.sol
  • smart-contracts/StreamMetadataRenderer.sol
  • test/README.md
  • test/StreamRandomizerLifecycle.t.sol

@punk6529 punk6529 merged commit f583f76 into main Jun 12, 2026
2 checks passed
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.

Recover StreamCore release-floor bytecode headroom

1 participant