diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 0756e24..e5ac281 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -63,21 +63,25 @@ jobs: npx -y "$YAML_CLI" valid < codecov.yml fi - - name: Validate package count matches codecov config + - name: Validate matrix entry count matches codecov config run: | - matrix_count=$(grep -cE '^\s+module:' .github/workflows/main-ci.yml) + # Source the module catalog and count generated entries + source .github/workflows/module-catalog.sh + INCLUDES="[]" + add_all_modules + matrix_count=$(echo "$INCLUDES" | jq 'length') codecov_count=$(grep 'after_n_builds:' codecov.yml | grep -oE '[0-9]+') - echo "Matrix modules: $matrix_count" + echo "Matrix entries: $matrix_count" echo "Codecov after_n_builds: $codecov_count" if [ "$matrix_count" != "$codecov_count" ]; then - echo "::error::Matrix has $matrix_count modules but codecov.yml expects $codecov_count builds" - echo "::error::Update codecov.yml after_n_builds to match module count" + echo "::error::Matrix has $matrix_count entries but codecov.yml expects $codecov_count builds" + echo "::error::Update codecov.yml after_n_builds to match matrix entry count" exit 1 fi - echo "Configuration validated: $matrix_count modules" + echo "Configuration validated: $matrix_count matrix entries" lint: needs: changes @@ -101,9 +105,22 @@ jobs: if: needs.changes.outputs.packages == 'true' runs-on: ubuntu-latest timeout-minutes: 5 + outputs: + test_matrix: ${{ steps.build-matrix.outputs.test_matrix }} steps: - uses: actions/checkout@v6 + - name: Build test matrix + id: build-matrix + run: | + source .github/workflows/module-catalog.sh + INCLUDES="[]" + add_all_modules + + MATRIX=$(echo "$INCLUDES" | jq -c '{include:.}') + echo "test_matrix=$MATRIX" >> "$GITHUB_OUTPUT" + echo "Matrix: $(echo "$INCLUDES" | jq 'length') entries" + - name: Extract tool versions run: | echo "SCARB_VERSION=$(grep '^scarb ' .tool-versions | awk '{print $2}')" >> "$GITHUB_ENV" @@ -140,96 +157,14 @@ jobs: - name: Warm snforge plugin cache run: snforge --version - - name: Verify workspace compiles (no warnings) - run: | - scarb build --workspace 2>&1 | tee /tmp/build.log - if grep -qE '^ --> .*\.cairo:[0-9]+:[0-9]+' /tmp/build.log; then - echo "::error::Build produced compiler warnings. Fix all warnings before merging." - grep -B1 -E '^ --> .*\.cairo:[0-9]+:[0-9]+' /tmp/build.log - exit 1 - fi - test: - name: test (${{ matrix.module }}) + name: test (${{ matrix.module }}${{ matrix.total_partitions > 1 && format(' {0}/{1}', matrix.partition, matrix.total_partitions) || '' }}) needs: setup - runs-on: ${{ matrix.runner }} + runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: true - matrix: - # NOTE: When adding/removing modules, also update: - # - codecov.yml: after_n_builds must equal module count - # - AGENTS.md: CI Configuration section - include: - # Embeddable Game Standard - - package: game_components_embeddable_game_standard - module: token - runner: ubuntu-latest-32 - fuzzer_runs: 32 - - package: game_components_embeddable_game_standard - module: minigame - runner: ubuntu-latest-8 - fuzzer_runs: 32 - - package: game_components_embeddable_game_standard - module: metagame - runner: ubuntu-latest-8 - fuzzer_runs: 32 - - package: game_components_embeddable_game_standard - module: registry - runner: ubuntu-latest-8 - fuzzer_runs: 32 - # Metagame - - package: game_components_metagame - module: leaderboard - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_metagame - module: registration - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_metagame - module: entry_requirement - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_metagame - module: entry_fee - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_metagame - module: prize - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_metagame - module: ticket_booth - runner: ubuntu-latest-4 - fuzzer_runs: 256 - # Economy - - package: game_components_economy - module: tokenomics - runner: ubuntu-latest-4 - fuzzer_runs: 256 - # Utilities - - package: game_components_utilities - module: math - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_utilities - module: distribution - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_utilities - module: utils - runner: ubuntu-latest-4 - fuzzer_runs: 256 - - package: game_components_utilities - module: renderer - runner: ubuntu-latest-4 - fuzzer_runs: 256 - # Presets (standalone package, no module filter) - - package: game_components_presets - module: presets - runner: ubuntu-latest-4 - fuzzer_runs: 256 + matrix: ${{ fromJson(needs.setup.outputs.test_matrix) }} steps: - uses: actions/checkout@v6 @@ -289,12 +224,18 @@ jobs: - name: Run tests with coverage run: | - if [ "${{ matrix.package }}" = "game_components_${{ matrix.module }}" ]; then - snforge test -p ${{ matrix.package }} --fuzzer-runs ${{ matrix.fuzzer_runs }} --coverage 2>&1 | tee /tmp/test.log - else - snforge test -p ${{ matrix.package }} "::${{ matrix.module }}::" --fuzzer-runs ${{ matrix.fuzzer_runs }} --coverage 2>&1 | tee /tmp/test.log + PARTITION_FLAG="" + if [ "${{ matrix.total_partitions }}" != "1" ]; then + PARTITION_FLAG="--partition ${{ matrix.partition }}/${{ matrix.total_partitions }}" fi + TEST_FILTER="" + if [ "${{ matrix.package }}" != "game_components_${{ matrix.module }}" ]; then + TEST_FILTER="::${{ matrix.module }}::" + fi + + snforge test -p ${{ matrix.package }} $TEST_FILTER --fuzzer-runs ${{ matrix.fuzzer_runs }} $PARTITION_FLAG --coverage 2>&1 | tee /tmp/test.log + - name: Check for compiler warnings if: always() && steps.cache-tools.outcome != 'failure' run: | diff --git a/.github/workflows/module-catalog.sh b/.github/workflows/module-catalog.sh new file mode 100644 index 0000000..7caae5f --- /dev/null +++ b/.github/workflows/module-catalog.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# Module catalog for CI test matrix generation. +# Sourced by both main-ci.yml and pr-ci.yml. +# +# All modules run on ubuntu-latest (standard 2-core runners). +# Partition counts compensate for smaller runners: +# was 32-core or 8-core → 8 partitions +# was 4-core → 4 partitions +# +# Usage: +# source .github/workflows/module-catalog.sh +# INCLUDES="[]" +# add_all_modules # or add selectively with add_egs, add_metagame, etc. +# echo "$INCLUDES" | jq . + +add() { + INCLUDES=$(echo "$INCLUDES" | jq -c \ + --arg p "$1" --arg m "$2" \ + --argjson f "$3" --argjson total "$4" \ + '. + [range($total) | {package:$p, module:$m, runner:"ubuntu-latest", fuzzer_runs:$f, partition:(. + 1), total_partitions:$total}]') +} + +# Embeddable Game Standard (previously 32-core / 8-core runners → 8 partitions) +add_egs() { + add game_components_embeddable_game_standard token 64 8 + add game_components_embeddable_game_standard minigame 64 8 + add game_components_embeddable_game_standard metagame 64 8 + add game_components_embeddable_game_standard registry 64 8 +} + +# Metagame extensions (previously 4-core runners → 4 partitions) +add_metagame() { + add game_components_metagame leaderboard 256 4 + add game_components_metagame registration 256 4 + add game_components_metagame entry_requirement 256 4 + add game_components_metagame entry_fee 256 4 + add game_components_metagame prize 256 4 + add game_components_metagame ticket_booth 256 4 +} + +# Economy (previously 4-core runner → 4 partitions) +add_economy() { + add game_components_economy tokenomics 256 4 +} + +# Utilities (previously 4-core runners → 4 partitions) +add_utilities() { + add game_components_utilities math 256 4 + add game_components_utilities distribution 256 4 + add game_components_utilities utils 256 4 + add game_components_utilities renderer 256 4 +} + +# Presets (previously 4-core runner → 4 partitions) +add_presets() { + add game_components_presets presets 256 4 +} + +# All modules — used by main-ci.yml (always runs everything) +add_all_modules() { + add_egs + add_metagame + add_economy + add_utilities + add_presets +} diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml index 699bd76..49e08a7 100644 --- a/.github/workflows/pr-ci.yml +++ b/.github/workflows/pr-ci.yml @@ -237,21 +237,25 @@ jobs: npx -y "$YAML_CLI" valid < codecov.yml fi - - name: Validate package count matches codecov config + - name: Validate matrix entry count matches codecov config run: | - matrix_count=$(grep -cE '^\s+module:' .github/workflows/main-ci.yml) + # Source the module catalog and count generated entries + source .github/workflows/module-catalog.sh + INCLUDES="[]" + add_all_modules + matrix_count=$(echo "$INCLUDES" | jq 'length') codecov_count=$(grep 'after_n_builds:' codecov.yml | grep -oE '[0-9]+') - echo "Matrix modules: $matrix_count" + echo "Matrix entries: $matrix_count" echo "Codecov after_n_builds: $codecov_count" if [ "$matrix_count" != "$codecov_count" ]; then - echo "::error::Matrix has $matrix_count modules but codecov.yml expects $codecov_count builds" - echo "::error::Update codecov.yml after_n_builds to match module count" + echo "::error::Matrix has $matrix_count entries but codecov.yml expects $codecov_count builds" + echo "::error::Update codecov.yml after_n_builds to match matrix entry count" exit 1 fi - echo "Configuration validated: $matrix_count modules" + echo "Configuration validated: $matrix_count matrix entries" lint: needs: changes @@ -289,42 +293,18 @@ jobs: NEED_UTILITIES: ${{ needs.changes.outputs.need_utilities }} NEED_PRESETS: ${{ needs.changes.outputs.need_presets }} run: | - # Build JSON matrix from per-package boolean flags - # Module catalog must match main-ci.yml + source .github/workflows/module-catalog.sh INCLUDES="[]" - add() { INCLUDES=$(echo "$INCLUDES" | jq -c --arg p "$1" --arg m "$2" --arg r "$3" --argjson f "$4" '. + [{package:$p,module:$m,runner:$r,fuzzer_runs:$f}]'); } - if [ "$NEED_EGS" = "true" ]; then - add game_components_embeddable_game_standard token ubuntu-latest-32 32 - add game_components_embeddable_game_standard minigame ubuntu-latest-8 32 - add game_components_embeddable_game_standard metagame ubuntu-latest-8 32 - add game_components_embeddable_game_standard registry ubuntu-latest-8 32 - fi - if [ "$NEED_METAGAME" = "true" ]; then - add game_components_metagame leaderboard ubuntu-latest-4 256 - add game_components_metagame registration ubuntu-latest-4 256 - add game_components_metagame entry_requirement ubuntu-latest-4 256 - add game_components_metagame entry_fee ubuntu-latest-4 256 - add game_components_metagame prize ubuntu-latest-4 256 - add game_components_metagame ticket_booth ubuntu-latest-4 256 - fi - if [ "$NEED_ECONOMY" = "true" ]; then - add game_components_economy tokenomics ubuntu-latest-4 256 - fi - if [ "$NEED_UTILITIES" = "true" ]; then - add game_components_utilities math ubuntu-latest-4 256 - add game_components_utilities distribution ubuntu-latest-4 256 - add game_components_utilities utils ubuntu-latest-4 256 - add game_components_utilities renderer ubuntu-latest-4 256 - fi - if [ "$NEED_PRESETS" = "true" ]; then - add game_components_presets presets ubuntu-latest-4 256 - fi + if [ "$NEED_EGS" = "true" ]; then add_egs; fi + if [ "$NEED_METAGAME" = "true" ]; then add_metagame; fi + if [ "$NEED_ECONOMY" = "true" ]; then add_economy; fi + if [ "$NEED_UTILITIES" = "true" ]; then add_utilities; fi + if [ "$NEED_PRESETS" = "true" ]; then add_presets; fi MATRIX=$(echo "$INCLUDES" | jq -c '{include:.}') echo "test_matrix=$MATRIX" >> "$GITHUB_OUTPUT" - echo "Matrix: $(echo "$INCLUDES" | jq 'length') modules" - echo "$MATRIX" | jq . + echo "Matrix: $(echo "$INCLUDES" | jq 'length') entries" - name: Extract tool versions run: | @@ -362,20 +342,11 @@ jobs: - name: Warm snforge plugin cache run: snforge --version - - name: Verify workspace compiles (no warnings) - run: | - scarb build --workspace 2>&1 | tee /tmp/build.log - if grep -qE '^ --> .*\.cairo:[0-9]+:[0-9]+' /tmp/build.log; then - echo "::error::Build produced compiler warnings. Fix all warnings before merging." - grep -B1 -E '^ --> .*\.cairo:[0-9]+:[0-9]+' /tmp/build.log - exit 1 - fi - test: - name: test (${{ matrix.module }}) + name: test (${{ matrix.module }}${{ matrix.total_partitions > 1 && format(' {0}/{1}', matrix.partition, matrix.total_partitions) || '' }}) needs: [changes, setup] if: needs.changes.outputs.has_tests == 'true' - runs-on: ${{ matrix.runner }} + runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: true @@ -439,12 +410,18 @@ jobs: - name: Run tests with coverage run: | - if [ "${{ matrix.package }}" = "game_components_${{ matrix.module }}" ]; then - snforge test -p ${{ matrix.package }} --fuzzer-runs ${{ matrix.fuzzer_runs }} --coverage 2>&1 | tee /tmp/test.log - else - snforge test -p ${{ matrix.package }} "::${{ matrix.module }}::" --fuzzer-runs ${{ matrix.fuzzer_runs }} --coverage 2>&1 | tee /tmp/test.log + PARTITION_FLAG="" + if [ "${{ matrix.total_partitions }}" != "1" ]; then + PARTITION_FLAG="--partition ${{ matrix.partition }}/${{ matrix.total_partitions }}" fi + TEST_FILTER="" + if [ "${{ matrix.package }}" != "game_components_${{ matrix.module }}" ]; then + TEST_FILTER="::${{ matrix.module }}::" + fi + + snforge test -p ${{ matrix.package }} $TEST_FILTER --fuzzer-runs ${{ matrix.fuzzer_runs }} $PARTITION_FLAG --coverage 2>&1 | tee /tmp/test.log + - name: Check for compiler warnings if: always() && steps.cache-tools.outcome != 'failure' run: | diff --git a/.tool-versions b/.tool-versions index e9cb626..5cdf476 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ rust 1.89.0 scarb 2.15.1 -starknet-foundry 0.55.0 +starknet-foundry 0.57.0 voyager 2.2.0 \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 3149492..8cee5de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,7 @@ You are a **senior Starknet smart contract engineer** specializing in Cairo deve ## Technology Stack -- **Cairo**: 2.15.1 | **Starknet**: 2.15.1 | **snforge**: v0.55.0 | **OpenZeppelin**: v3.0.0 +- **Cairo**: 2.15.1 | **Starknet**: 2.15.1 | **snforge**: v0.57.0 | **OpenZeppelin**: v3.0.0 ## Build Commands @@ -110,44 +110,43 @@ When adding a new group package or changing a workspace-level dependency in the ### Adding a New Module -When adding a new module to a group package, update **both** files: +When adding a new module to a group package, update **three** files: -1. **`.github/workflows/main-ci.yml`** and **`.github/workflows/pr-ci.yml`** - Add the module to both matrices: +1. **`.github/workflows/module-catalog.sh`** — Add the module to the appropriate `add_*` function: - ```yaml - matrix: - include: - - package: game_components_GROUP_PACKAGE - module: NEW_MODULE - runner: ubuntu-latest - fuzzer_runs: 256 + ```bash + add game_components_GROUP_PACKAGE NEW_MODULE 256 8 # fuzzer_runs partitions ``` - For memory-intensive modules (like `token` or `minigame`), assign a larger runner (e.g., `ubuntu-latest-4` or `ubuntu-latest-32`). + All modules run on `ubuntu-latest` (standard 2-core runners). Compensate by increasing partition count: modules that previously needed 4-core runners get 4 partitions, 8-core get 8, etc. -2. **`codecov.yml`** - Update the build count: +2. **`codecov.yml`** — Update the build count: ```yaml notify: - after_n_builds: 15 # ← Must equal total module count in matrix + after_n_builds: 80 # ← Must equal total matrix entry count (including partitions) ``` -### Current Matrix (16 modules) - -| Group Package | Module | Runner | Fuzzer Runs | -|---------------|--------|--------|-------------| -| `embeddable_game_standard` | `token` | `ubuntu-latest-32` | 32 | -| `embeddable_game_standard` | `minigame` | `ubuntu-latest-32` | 32 | -| `embeddable_game_standard` | `metagame` | `ubuntu-latest-32` | 256 | -| `embeddable_game_standard` | `registry` | `ubuntu-latest-32` | 256 | -| `metagame` | `leaderboard` | `ubuntu-latest-4` | 256 | -| `metagame` | `registration` | `ubuntu-latest-4` | 256 | -| `metagame` | `entry_requirement` | `ubuntu-latest-4` | 256 | -| `metagame` | `entry_fee` | `ubuntu-latest-4` | 256 | -| `metagame` | `prize` | `ubuntu-latest-4` | 256 | -| `metagame` | `ticket_booth` | `ubuntu-latest-4` | 256 | -| `economy` | `tokenomics` | `ubuntu-latest-4` | 256 | -| `utilities` | `math` | `ubuntu-latest-4` | 256 | -| `utilities` | `distribution` | `ubuntu-latest-4` | 256 | -| `utilities` | `utils` | `ubuntu-latest-4` | 256 | -| `utilities` | `renderer` | `ubuntu-latest-4` | 256 | -| `presets` | `presets` | `ubuntu-latest-4` | 256 | +3. **`.github/workflows/pr-ci.yml`** — If adding a new group package, add it to the `compute-matrix` dependency graph and the `NEED_*` flags in the `build-matrix` step. + +### Current Matrix (80 jobs across 16 modules) + +All modules use `ubuntu-latest` (standard 2-core) runners with partitioning for parallelism. The shared module catalog is defined in `.github/workflows/module-catalog.sh`. + +| Group Package | Module | Fuzzer Runs | Partitions | +|---------------|--------|-------------|------------| +| `embeddable_game_standard` | `token` | 64 | 8 | +| `embeddable_game_standard` | `minigame` | 64 | 8 | +| `embeddable_game_standard` | `metagame` | 64 | 8 | +| `embeddable_game_standard` | `registry` | 64 | 8 | +| `metagame` | `leaderboard` | 256 | 4 | +| `metagame` | `registration` | 256 | 4 | +| `metagame` | `entry_requirement` | 256 | 4 | +| `metagame` | `entry_fee` | 256 | 4 | +| `metagame` | `prize` | 256 | 4 | +| `metagame` | `ticket_booth` | 256 | 4 | +| `economy` | `tokenomics` | 256 | 4 | +| `utilities` | `math` | 256 | 4 | +| `utilities` | `distribution` | 256 | 4 | +| `utilities` | `utils` | 256 | 4 | +| `utilities` | `renderer` | 256 | 4 | +| `presets` | `presets` | 256 | 4 | diff --git a/Scarb.toml b/Scarb.toml index 1cfd6a6..e38665c 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -31,7 +31,7 @@ keywords = [ [workspace.dependencies] starknet = "2.15.1" -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.55.0" } +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.57.0" } openzeppelin_access = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v3.0.0" } openzeppelin_introspection = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v3.0.0" } openzeppelin_token = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v3.0.0" } diff --git a/codecov.yml b/codecov.yml index 84001da..c52c513 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,9 +1,10 @@ codecov: require_ci_to_pass: true notify: - # Must equal package count in .github/workflows/main-ci.yml matrix + # Must equal matrix entry count in .github/workflows/main-ci.yml + # (partitioned modules count once per partition) # See AGENTS.md "CI Configuration" section when adding packages - after_n_builds: 16 + after_n_builds: 80 comment: layout: "diff, files, header, footer" diff --git a/packages/testing/src/constants.cairo b/packages/testing/src/constants.cairo index 87b13bb..208b243 100644 --- a/packages/testing/src/constants.cairo +++ b/packages/testing/src/constants.cairo @@ -41,7 +41,7 @@ pub fn CREATOR() -> ContractAddress { 'CREATOR'.try_into().unwrap() } -// Edge case values +// Edge-case values pub const MAX_U64: u64 = 18446744073709551615; pub const MAX_U32: u32 = 4294967295; // Max 35-bit timestamp - maximum value that fits in TokenMetadata lifecycle packing