Skip to content

ci: stabilize verify workflow timeouts#1647

Merged
Th0rgal merged 11 commits intomainfrom
codex/ci-stability-watchdog
Mar 20, 2026
Merged

ci: stabilize verify workflow timeouts#1647
Th0rgal merged 11 commits intomainfrom
codex/ci-stability-watchdog

Conversation

@Th0rgal
Copy link
Member

@Th0rgal Th0rgal commented Mar 20, 2026

Summary

  • restore the exact .lake cache produced earlier in the same workflow run and shard macro-fuzz to reduce timeout pressure
  • replace the hand-maintained verify sync JSON with a generated artifact backed by a Python source module and enforce freshness in make check
  • add a lightweight CI timeout watchdog that warns when recent verify jobs trend too close to their timeout budget

Testing

  • python3 -m unittest -v scripts.test_generate_verify_sync_spec scripts.test_ci_timeout_watchdog
  • make check
  • lake build
  • python3 scripts/ci_timeout_watchdog.py --repo lfglabs-dev/verity --workflow verify.yml --branch main
  • started env MACRO_FUZZ_SHARD_COUNT=4 MACRO_FUZZ_SHARD_INDEX=0 lake exe macro-roundtrip-fuzz locally; it entered a cold dependency rebuild and did not finish within the working window

Note

Medium Risk
Medium risk because it significantly restructures CI caching/artifact flow and job dependencies, which could cause cache misses, stale artifacts, or unexpected rebuilds/timeouts if misconfigured. No production/runtime code paths are affected beyond CI and the fuzz harness sharding inputs.

Overview
Stabilizes verify.yml by reducing redundant Lean rebuilds and splitting long-running work across jobs/shards. The setup-lean composite action now supports sticky disks (elan, .lake/packages, optional .lake/build), configurable cache keys/restore fallbacks, and an opt-out for cache restore; it also skips lake exe cache get when dependencies are already hydrated.

Verify workflow changes: adds a workflow_dispatch clean build mode (disables sticky disks/cache restore and increases timeouts), restores the exact .lake cache saved earlier in the same run, and packages/uploads prepared .lake/build state so downstream jobs (build-audits, compiler steps, macro-fuzz prep) can reuse it. macro-fuzz is split into a prepare-macro-fuzz build stage and a 4-shard matrix run using MACRO_FUZZ_SHARD_INDEX/COUNT.

Workflow hygiene tooling: introduces scripts/ci_timeout_watchdog.py (new timeout-watchdog job) to warn when recent runs approach job timeouts, and replaces the hand-edited verify_sync_spec.json with a generated artifact (verify_sync_spec_source.py + generate_verify_sync_spec.py) enforced via make check; check_verify_sync.py is updated to load the Python spec and to better parse YAML block scalars and multi-job compiler expectations.

Written by Cursor Bugbot for commit 42d74fe. This will update automatically on new commits. Configure here.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4d221cbe9b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions
Copy link

\n### CI Failure Hints\n\nFailed jobs: `build`\n\nCopy-paste local triage:\n```bash\nmake check\nlake build\nFOUNDRY_PROFILE=difftest forge test -vv\n```

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf4a0048a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5bb37ee18

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0fdbd564c8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bfb315161a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6232ca36c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Th0rgal Th0rgal merged commit 5acd811 into main Mar 20, 2026
11 checks passed
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

raw = _extract_top_level_job_value(extract_job_body(workflow_text, job, workflow_path), "timeout-minutes")
if raw is None:
continue
timeouts[job] = int(raw)
Copy link

Choose a reason for hiding this comment

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

Watchdog crashes on dynamic timeout expressions

High Severity

load_timeouts_from_text calls int(raw) on every extracted timeout-minutes value. Several jobs now use dynamic expressions like ${{ fromJSON(github.event_name == 'workflow_dispatch' && inputs.clean_build && '60' || '35') }}, which are not valid integer strings. This causes an unhandled ValueError that crashes the watchdog script. The except urllib.error.URLError handler in main() does not catch ValueError, so the timeout-watchdog CI job will fail on every workflow run.

Additional Locations (1)
Fix in Cursor Fix in Web

Th0rgal added a commit to Th0rgal/morpho-verity that referenced this pull request Mar 20, 2026
Inspired by lfglabs-dev/verity#1647. Instead of each downstream job
rebuilding from cache, verity-proofs now uploads the verified .lake
workspace as an artifact. verity-compiler-artifacts downloads it
directly, eliminating redundant Lean compilation.

Also save the Lean/Lake cache only on master to avoid cache pollution
from PR branches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Th0rgal added a commit to Th0rgal/morpho-verity that referenced this pull request Mar 20, 2026
#363)

* Mark accrueInterestPublic as macro-migrated

The EDSL accrueInterest function already implements both the public entry
point (id computation, market-exists check) and the internal
_accrueInterest logic. Update obligation to reflect this — all 18/18
obligations are now macroMigrated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix CI parity target tuple check failures

- Revert accrueInterestPublic macroMigrated to false since the function
  does not exist as a separate entry point in MacroSlice.lean (the check
  scripts enforce name-level correspondence)
- Add test_uniquify_yul_shadows.py to satisfy script-test-pairs check

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add toUint128 overflow checks, callback invocations, and complete macro migration

- Add uint128 overflow guards (require <= 2^128-1) before all packed-uint128
  field writes in supply, borrow, supplyCollateral, and accrueInterest
- Add callback invocations via ecmDo for onMorphoSupply, onMorphoRepay,
  onMorphoSupplyCollateral, onMorphoLiquidate, and onMorphoFlashLoan
- Mark accrueInterestPublic as macro-migrated (maps to accrueInterest via
  macroAlias); all 18/18 obligations now macro-migrated
- Add macroAlias support to check_spec_correspondence.py and
  check_semantic_bridge_obligations.py for operations that share a
  MacroSlice function under a different name
- Update SemanticBridgeReadiness.lean proofs: 18/18 migrated, 0 pending
- Update EQUIVALENCE_OBLIGATIONS.md: zero remaining blockers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix CI: inline uint128Max, remove ecmDo callbacks, fix duplicate variable

- Replace uint128Max references with inline literal (macro doesn't resolve external defs)
- Remove ecmDo callback invocations (elaboration function not implemented in current Verity)
- Revert callback obligation texts to original wording
- Fix duplicate newTotalBorrowAssets binding in borrow function

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix review issues: event indexed fields, alias-aware coverage, Yul shadow rewrites

- Set correct indexed/unindexed event param kinds in Generated.lean to match
  Solidity EventsLib.sol (P1: preserves ABI topic/data layout)
- Make check_primitive_coverage.py alias-aware so macroAlias operations
  (e.g. accrueInterestPublic → accrueInterest) resolve correctly (P2)
- Fix uniquify_yul_shadows.py: limit brace scope tracking to before the let
  declaration, and rewrite same-line references after renamed declarations (P2+Medium)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Drop manual SupportedStmtList witnesses, delegate Links 2+3 to Verity

The verity_contract macro generates code exclusively from supported patterns,
so SupportedStmtList/SupportedSpec witnesses should be constructive — produced
by the macro, not proven manually per-contract. This commit removes the manual
witness files and makes the trust assumption explicit across all surfaces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Add constructor to Verity contract for owner initialization

The verity_contract macro fully supports constructors. Add a constructor
that takes initialOwner and stores it via setStorageAddr, matching the
original Morpho Blue constructor behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Optimize CI: upload Lean workspace artifact, reuse in downstream jobs

Inspired by lfglabs-dev/verity#1647. Instead of each downstream job
rebuilding from cache, verity-proofs now uploads the verified .lake
workspace as an artifact. verity-compiler-artifacts downloads it
directly, eliminating redundant Lean compilation.

Also save the Lean/Lake cache only on master to avoid cache pollution
from PR branches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42d74feda7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

raw = _extract_top_level_job_value(extract_job_body(workflow_text, job, workflow_path), "timeout-minutes")
if raw is None:
continue
timeouts[job] = int(raw)

Choose a reason for hiding this comment

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

P1 Badge Handle expression-based timeout-minutes values

Once this workflow lands on the branch being inspected (for example, pushes to main, or PRs after main has this commit), client.get_file_text() will read jobs whose timeout-minutes are expressions such as ${{ fromJSON(...) }}. Converting that string with int(raw) raises ValueError, so the new timeout-watchdog job fails before it can emit any warning on every such run.

Useful? React with 👍 / 👎.

Comment on lines +102 to +105
payload = self.get_json(
f"/actions/workflows/{workflow}/runs",
{"branch": branch, "status": "completed", "per_page": limit},
)

Choose a reason for hiding this comment

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

P2 Badge Filter workflow_dispatch clean builds out of watchdog data

If someone runs verify.yml via workflow_dispatch with clean_build=true, later normal runs on the same branch will still pull that run into the sample set here because list_workflow_runs() only filters by branch and status. Those manual clean builds intentionally have larger timeouts than the default path (for example build is 60 minutes instead of 35), so their durations can be counted as "risky" against the normal budget and produce misleading timeout-trend warnings until they age out of the window.

Useful? React with 👍 / 👎.

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.

1 participant