3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-19 15:16:29 +00:00

Merge branch 'Z3Prover:master' into master

This commit is contained in:
davedets 2026-06-15 13:38:38 -07:00 committed by GitHub
commit b96f61654e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 4889 additions and 1486 deletions

View file

@ -1,24 +1,68 @@
---
name: agentic-workflows
description: Route gh-aw workflow create/debug/upgrade requests to the right prompts.
description: Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
---
# Agentic Workflows Router
Use this skill when a user asks to create, update, debug, or upgrade GitHub Agentic Workflows in this repository.
Use this skill when a user asks to design, create, update, debug, or upgrade GitHub Agentic Workflows in this repository.
This skill is a dispatcher: identify the task type, load the matching `.github/aw/*.md` file, and follow it directly. Keep responses concise and ask a clarifying question if the correct prompt is unclear.
This skill is a dispatcher: identify the task type, load the matching workflow prompt/skill file, and follow it directly. Keep responses concise and ask a clarifying question if the correct prompt is unclear.
Read only the files you need:
Load these files from `github/gh-aw` (they are not available locally).
- `.github/aw/agentic-chat.md`
- `.github/aw/agentic-workflows-mcp.md`
- `.github/aw/asciicharts.md`
- `.github/aw/campaign.md`
- `.github/aw/charts-trending.md`
- `.github/aw/charts.md`
- `.github/aw/cli-commands.md`
- `.github/aw/context.md`
- `.github/aw/create-agentic-workflow.md`
- `.github/aw/create-shared-agentic-workflow.md`
- `.github/aw/debug-agentic-workflow.md`
- `.github/aw/dependabot.md`
- `.github/aw/deployment-status.md`
- `.github/aw/experiments.md`
- `.github/aw/github-agentic-workflows.md`
- `.github/aw/github-mcp-server.md`
- `.github/aw/llms.md`
- `.github/aw/mcp-clis.md`
- `.github/aw/memory.md`
- `.github/aw/messages.md`
- `.github/aw/network.md`
- `.github/aw/patterns.md`
- `.github/aw/pr-reviewer.md`
- `.github/aw/report.md`
- `.github/aw/reuse.md`
- `.github/aw/safe-outputs-automation.md`
- `.github/aw/safe-outputs-content.md`
- `.github/aw/safe-outputs-management.md`
- `.github/aw/safe-outputs-runtime.md`
- `.github/aw/safe-outputs.md`
- `.github/aw/serena-tool.md`
- `.github/aw/shared-safe-jobs.md`
- `.github/aw/skills.md`
- `.github/aw/subagents.md`
- `.github/aw/syntax-agentic.md`
- `.github/aw/syntax-core.md`
- `.github/aw/syntax-tools-imports.md`
- `.github/aw/syntax.md`
- `.github/aw/test-coverage.md`
- `.github/aw/test-expression.md`
- `.github/aw/token-optimization.md`
- `.github/aw/triggers.md`
- `.github/aw/update-agentic-workflow.md`
- `.github/aw/upgrade-agentic-workflows.md`
- `.github/aw/visual-regression.md`
- `.github/aw/workflow-constraints.md`
- `.github/aw/workflow-editing.md`
- `.github/aw/workflow-patterns.md`
After loading the matching workflow prompt, follow it directly:
- `.github/skills/agentic-workflow-designer/SKILL.md`
After loading the matching workflow prompt or skill, follow it directly:
- Design workflows from scratch via interview: `skills/agentic-workflow-designer/SKILL.md`
- Create new workflows: `.github/aw/create-agentic-workflow.md`
- Update existing workflows: `.github/aw/update-agentic-workflow.md`
- Debug, audit, or investigate workflows: `.github/aw/debug-agentic-workflow.md`
@ -32,4 +76,4 @@ After loading the matching workflow prompt, follow it directly:
- Choose workflow architecture and patterns: `.github/aw/patterns.md`
- Optimize token usage and cost: `.github/aw/token-optimization.md`
When the task involves OTEL, OTLP, traces, observability backends, or telemetry-driven analysis, also read and follow `skills/otel-queries/SKILL.md` after loading the matching workflow prompt.
When the task involves OTEL, OTLP, traces, observability backends, or telemetry-driven analysis, also read and follow `skills/otel-queries/SKILL.md` after loading the matching workflow prompt or skill.

View file

@ -37,9 +37,10 @@ jobs:
${{ matrix.cmd1 }}
${{ matrix.cmd2 }}
${{ matrix.cmd3 }}
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }}
cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../
nmake
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} || exit /b 1
cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ || exit /b 1
nmake || exit /b 1
cd ..
shell: cmd
- name: Run Regressions
@ -52,7 +53,8 @@ jobs:
if: ${{ matrix.test }}
run: |
pushd build
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }}
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} || exit /b 1
pushd build\python
python z3test.py z3
python z3test.py z3num

245
.github/workflows/a3-python.lock.yml generated vendored

File diff suppressed because one or more lines are too long

View file

@ -9,6 +9,7 @@ permissions:
network:
allowed: [defaults, python]
safe-outputs:
report-failure-as-issue: false
create-issue:
labels:
- bug

File diff suppressed because one or more lines are too long

View file

@ -29,6 +29,7 @@ tools:
bash: [":*"]
safe-outputs:
report-failure-as-issue: false
mentions: false
allowed-github-references: []
max-bot-mentions: 1

View file

@ -12,7 +12,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.77.5). DO NOT EDIT.
# This file was automatically generated by pkg/workflow/maintenance_workflow.go (v0.79.6). DO NOT EDIT.
#
# To regenerate this workflow, run:
# gh aw compile
@ -34,7 +34,7 @@ name: Agentic Maintenance
on:
schedule:
- cron: "37 */2 * * *" # Every 2 hours (based on minimum expires: 1 days)
- cron: "37 0 * * *" # Daily (based on minimum expires: 7 days)
workflow_dispatch:
inputs:
operation:
@ -93,7 +93,7 @@ jobs:
pull-requests: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -131,7 +131,7 @@ jobs:
actions: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -155,12 +155,12 @@ jobs:
operation: ${{ steps.record.outputs.operation }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -175,9 +175,9 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
uses: github/gh-aw-actions/setup-cli@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
version: v0.77.5
version: v0.79.6
- name: Run operation
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@ -205,7 +205,7 @@ jobs:
pull-requests: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -244,14 +244,14 @@ jobs:
run_url: ${{ steps.record.outputs.run_url }}
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -290,12 +290,12 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -310,9 +310,9 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
uses: github/gh-aw-actions/setup-cli@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
version: v0.77.5
version: v0.79.6
- name: Create missing labels
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@ -336,12 +336,12 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -356,9 +356,9 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
uses: github/gh-aw-actions/setup-cli@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
version: v0.77.5
version: v0.79.6
- name: Restore activity report logs cache
id: activity_report_logs_cache
@ -441,12 +441,12 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -461,15 +461,15 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
uses: github/gh-aw-actions/setup-cli@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
version: v0.77.5
version: v0.79.6
- name: Restore forecast report logs cache
id: forecast_report_logs_cache
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: .github/aw/logs
path: ./.github/aw/logs
key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-forecast-report-logs-${{ github.repository }}-
@ -477,24 +477,21 @@ jobs:
- name: Generate forecast report
id: generate_forecast_report
timeout-minutes: 30
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEBUG: "*"
GH_AW_CMD_PREFIX: gh aw
run: |
mkdir -p ./.cache/gh-aw/forecast
${GH_AW_CMD_PREFIX} logs --repo "${{ github.repository }}" --start-date -30d --count 1500 > /dev/null
if ! compgen -G ".github/aw/logs/run-*/run_summary.json" > /dev/null; then
echo "::error::Missing run summary cache in .github/aw/logs after gh aw logs warm-up; cannot run forecast."
exit 1
fi
set +e
${GH_AW_CMD_PREFIX} forecast --repo "${{ github.repository }}" --timeout 10 --json 2> >(grep -Fv "forecast is an experimental command and may change without notice" >&2) > ./.cache/gh-aw/forecast/report.json
${GH_AW_CMD_PREFIX} forecast --repo "${{ github.repository }}" --timeout 30 --verbose --json > ./.cache/gh-aw/forecast/report.json
forecast_exit_code=$?
set -e
if [ "${forecast_exit_code}" -eq 124 ]; then
echo '{"outcome":"timeout","message":"Forecast computation timed out after 10 minutes."}' > ./.cache/gh-aw/forecast/error.json
echo "::error::Forecast computation timed out after 10 minutes."
echo '{"outcome":"timeout","message":"Forecast computation timed out after 30 minutes."}' > ./.cache/gh-aw/forecast/error.json
echo "::error::Forecast computation timed out after 30 minutes."
exit 1
fi
if [ "${forecast_exit_code}" -ne 0 ]; then
@ -503,12 +500,23 @@ jobs:
exit 1
fi
- name: Debug forecast logs folder
if: ${{ always() }}
shell: bash
run: |
if [ ! -d ./.github/aw/logs ]; then
echo "Logs directory not found: ./.github/aw/logs"
exit 0
fi
echo "Files under ./.github/aw/logs:"
find ./.github/aw/logs -type f | sort
- name: Save forecast report logs cache
if: ${{ always() }}
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: .github/aw/logs
key: ${{ steps.forecast_report_logs_cache.outputs.cache-primary-key }}
path: ./.github/aw/logs
key: ${{ runner.os }}-forecast-report-logs-${{ github.repository }}-${{ github.ref_name }}-${{ github.run_id }}
- name: Generate forecast issue
if: ${{ always() }}
@ -530,7 +538,7 @@ jobs:
issues: write
steps:
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -562,12 +570,12 @@ jobs:
issues: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Setup Scripts
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
@ -582,9 +590,9 @@ jobs:
await main();
- name: Install gh-aw
uses: github/gh-aw-actions/setup-cli@v0.77.5
uses: github/gh-aw-actions/setup-cli@5c2fe865bb4dc46e1450f6ee0d0541d759aea73a # v0.79.6
with:
version: v0.77.5
version: v0.79.6
- name: Validate workflows and file issue on findings
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0

View file

@ -33,7 +33,7 @@ jobs:
tar -cvf z3-build-${{ matrix.android-abi }}.tar *.jar *.so
- name: Archive production artifacts
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: android-build-${{ matrix.android-abi }}
path: build/z3-build-${{ matrix.android-abi }}.tar

File diff suppressed because one or more lines are too long

View file

@ -20,6 +20,7 @@ tools:
web-search: {}
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[API Coherence] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -8,6 +8,7 @@ tools:
edit:
bash: true
safe-outputs:
report-failure-as-issue: false
create-pull-request:
if-no-changes: ignore
missing-tool:

File diff suppressed because one or more lines are too long

View file

@ -15,6 +15,7 @@ tools:
- "git diff:*"
- "git show:*"
safe-outputs:
report-failure-as-issue: false
create-issue:
title-prefix: "[Conventions] "
labels: [code-quality, automated]

View file

@ -1,5 +1,5 @@
# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"a50e58358dfcf5d6e6e0b92707925040a7b1ad4f29c08cfce11cfa8c9756f876","body_hash":"368645de189baaa1bf33102a20d4c9ea646e5ed15d3d2bffaf4b221f6c97b73b","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/github-script","sha":"v9","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"v0.77.5","version":"v0.77.5"}],"resolution_failures":[{"repo":"actions/github-script","ref":"v9","error_type":"dynamic_resolution_failed"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"43d46b9fb0525b484e4cd15d3251010e0b2b854cb91a250eb32c44c5402c5985","body_hash":"368645de189baaa1bf33102a20d4c9ea646e5ed15d3d2bffaf4b221f6c97b73b","compiler_version":"v0.79.6","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.60"}}
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/github-script","sha":"v9","version":"v9"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"v0.79.6","version":"v0.79.6"}],"resolution_failures":[{"repo":"actions/github-script","ref":"v9","error_type":"dynamic_resolution_failed"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2","digest":"sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2","digest":"sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2","digest":"sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.25","digest":"sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa"},{"image":"ghcr.io/github/github-mcp-server:v1.1.2","digest":"sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c","pinned_image":"ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
# This file was automatically generated by gh-aw (v0.79.6). DO NOT EDIT.
#
# To update this file, edit github/gh-aw/.github/workflows/code-simplifier.md@6762bfba6ae426a03aac46e8f68701461c667404 and run:
# gh aw compile
@ -34,21 +34,20 @@
# - GITHUB_TOKEN
#
# Custom actions used:
# - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# - actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
# - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
# - actions/github-script@v9
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
# - github/gh-aw-actions/setup@v0.77.5
# - github/gh-aw-actions/setup@v0.79.6
#
# Container images used:
# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
# - ghcr.io/github/gh-aw-mcpg:v0.3.22
# - ghcr.io/github/github-mcp-server:v1.1.0
# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
# - ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6
# - ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4
# - ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591
# - ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa
# - ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c
name: "Code Simplifier"
on:
@ -79,9 +78,14 @@ jobs:
permissions:
actions: read
contents: read
env:
GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
outputs:
comment_id: ""
comment_repo: ""
daily_effective_workflow_exceeded: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_exceeded == 'true' }}
daily_effective_workflow_threshold: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_threshold || '' }}
daily_effective_workflow_total_effective_tokens: ${{ steps.daily-effective-workflow-guardrail.outputs.daily_effective_workflow_total_effective_tokens || '' }}
engine_id: ${{ steps.generate_aw_info.outputs.engine_id }}
lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
model: ${{ steps.generate_aw_info.outputs.model }}
@ -93,17 +97,18 @@ jobs:
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }}
parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }}
safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Code Simplifier"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-simplifier.lock.yml@${{ github.ref }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_BODY_MODIFIED: "false"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
@ -112,16 +117,16 @@ jobs:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AGENT_VERSION: "1.0.55"
GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AGENT_VERSION: "1.0.60"
GH_AW_INFO_CLI_VERSION: "v0.79.6"
GH_AW_INFO_WORKFLOW_NAME: "Code Simplifier"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["go"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_INFO_FRONTMATTER_SOURCE: "github/gh-aw/.github/workflows/code-simplifier.md@6762bfba6ae426a03aac46e8f68701461c667404"
@ -134,13 +139,31 @@ jobs:
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
await main(core, context);
- name: Check daily workflow token guardrail
id: daily-effective-workflow-guardrail
if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }}
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_WORKFLOW_NAME: "Code Simplifier"
GH_AW_WORKFLOW_ID: "code-simplifier"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }}
GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_daily_aic_workflow_guardrail.cjs');
await main();
- name: Validate COPILOT_GITHUB_TOKEN secret
id: validate-secret
run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- name: Checkout .github and .agents folders
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
sparse-checkout: |
@ -176,7 +199,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_COMPILED_VERSION: "v0.77.5"
GH_AW_COMPILED_VERSION: "v0.79.6"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@ -199,23 +222,23 @@ jobs:
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
{
cat << 'GH_AW_PROMPT_b6435d392c5b00fb_EOF'
cat << 'GH_AW_PROMPT_ddf86d6f4f3fea64_EOF'
<system>
GH_AW_PROMPT_b6435d392c5b00fb_EOF
GH_AW_PROMPT_ddf86d6f4f3fea64_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
cat << 'GH_AW_PROMPT_b6435d392c5b00fb_EOF'
cat << 'GH_AW_PROMPT_ddf86d6f4f3fea64_EOF'
<safe-output-tools>
Tools: create_pull_request, missing_tool, missing_data, noop
GH_AW_PROMPT_b6435d392c5b00fb_EOF
GH_AW_PROMPT_ddf86d6f4f3fea64_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md"
cat << 'GH_AW_PROMPT_b6435d392c5b00fb_EOF'
cat << 'GH_AW_PROMPT_ddf86d6f4f3fea64_EOF'
</safe-output-tools>
GH_AW_PROMPT_b6435d392c5b00fb_EOF
GH_AW_PROMPT_ddf86d6f4f3fea64_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
cat << 'GH_AW_PROMPT_b6435d392c5b00fb_EOF'
cat << 'GH_AW_PROMPT_ddf86d6f4f3fea64_EOF'
<github-context>
The following GitHub context information is available for this workflow:
{{#if github.actor}}
@ -244,12 +267,12 @@ jobs:
{{/if}}
</github-context>
GH_AW_PROMPT_b6435d392c5b00fb_EOF
GH_AW_PROMPT_ddf86d6f4f3fea64_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
cat << 'GH_AW_PROMPT_b6435d392c5b00fb_EOF'
cat << 'GH_AW_PROMPT_ddf86d6f4f3fea64_EOF'
</system>
{{#runtime-import .github/workflows/code-simplifier.md}}
GH_AW_PROMPT_b6435d392c5b00fb_EOF
GH_AW_PROMPT_ddf86d6f4f3fea64_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@ -320,6 +343,7 @@ jobs:
path: |
/tmp/gh-aw/aw_info.json
/tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/models.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
@ -332,6 +356,7 @@ jobs:
agent:
needs: activation
if: needs.activation.outputs.daily_effective_workflow_exceeded != 'true'
runs-on: ubuntu-latest
permissions:
contents: read
@ -349,9 +374,11 @@ jobs:
GH_AW_WORKFLOW_ID_SANITIZED: codesimplifier
outputs:
agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }}
aic: ${{ steps.parse-mcp-gateway.outputs.aic }}
ambient_context: ${{ steps.parse-mcp-gateway.outputs.ambient_context }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
@ -362,10 +389,11 @@ jobs:
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
setup-span-id: ${{ steps.setup.outputs.span-id }}
setup-trace-id: ${{ steps.setup.outputs.trace-id }}
unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@ -374,8 +402,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Code Simplifier"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-simplifier.lock.yml@${{ github.ref }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_BODY_MODIFIED: "false"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
@ -387,7 +415,7 @@ jobs:
echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
} >> "$GITHUB_OUTPUT"
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
- name: Create gh-aw temp directory
@ -412,7 +440,7 @@ jobs:
- name: Checkout PR branch
id: checkout-pr
if: |
github.event.pull_request || github.event.issue.pull_request
github.event.pull_request || github.event.issue.pull_request || github.event_name == 'workflow_dispatch' && fromJSON(github.event.inputs.aw_context || '{}').item_type == 'pull_request'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
@ -424,11 +452,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.60
env:
GH_HOST: github.com
- name: Install AWF binary
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.2
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@v9
@ -460,15 +488,15 @@ jobs:
GH_AW_SKILL_DIR: ".github/skills"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591 ghcr.io/github/gh-aw-mcpg:v0.3.25@sha256:c10331ad17668ef89f38f5e356678788a40b0cd5fef96e8f92e1d9c1de47cbaa ghcr.io/github/github-mcp-server:v1.1.2@sha256:30197479d8036c7811892bc07e06f9a05c9ef3cdd79bc59f256d50647f95788c
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_9974579f3008b6e7_EOF'
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_7eb77ba1d1f9c017_EOF'
{"create_pull_request":{"expires":24,"labels":["refactoring","code-quality","automation"],"max":1,"max_patch_files":100,"max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","reviewers":["copilot"],"title_prefix":"[code-simplifier] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"false"},"report_incomplete":{}}
GH_AW_SAFE_OUTPUTS_CONFIG_9974579f3008b6e7_EOF
GH_AW_SAFE_OUTPUTS_CONFIG_7eb77ba1d1f9c017_EOF
- name: Generate Safe Outputs Tools
env:
GH_AW_TOOLS_META_JSON: |
@ -677,16 +705,16 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.25'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
cat << GH_AW_MCP_CONFIG_14204ee419df0c42_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
cat << GH_AW_MCP_CONFIG_c6fee03c27b97257_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
{
"mcpServers": {
"github": {
"type": "stdio",
"container": "ghcr.io/github/github-mcp-server:v1.1.0",
"container": "ghcr.io/github/github-mcp-server:v1.1.2",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@ -722,7 +750,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
GH_AW_MCP_CONFIG_14204ee419df0c42_EOF
GH_AW_MCP_CONFIG_c6fee03c27b97257_EOF
- name: Mount MCP servers as CLIs
id: mount-mcp-clis
continue-on-error: true
@ -751,14 +779,19 @@ jobs:
run: |
set -o pipefail
printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
trap 'rm -f /home/runner/.copilot/settings.json' EXIT
mkdir -p /home/runner/.copilot
printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > /home/runner/.copilot/settings.json
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","go.dev","golang.org","goproxy.io","host.docker.internal","pkg.go.dev","proxy.golang.org","raw.githubusercontent.com","registry.npmjs.org","storage.googleapis.com","sum.golang.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}"
printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.2/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"go.dev\",\"golang.org\",\"goproxy.io\",\"host.docker.internal\",\"pkg.go.dev\",\"proxy.golang.org\",\"raw.githubusercontent.com\",\"registry.npmjs.org\",\"storage.googleapis.com\",\"sum.golang.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-5.4\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"large\":[\"sonnet\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"vision\":[\"copilot/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.27.2,squid=sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591,agent=sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6,api-proxy=sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4,cli-proxy=sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
@ -774,18 +807,20 @@ jobs:
fi
# shellcheck disable=SC1003
sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
-- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
-- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
GH_AW_VERSION: v0.77.5
GH_AW_TIMEOUT_MINUTES: 30
GH_AW_VERSION: v0.79.6
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@ -968,7 +1003,7 @@ jobs:
- safe_outputs
if: >
always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
needs.activation.outputs.stale_lock_file_failed == 'true')
needs.activation.outputs.stale_lock_file_failed == 'true' || needs.activation.outputs.daily_effective_workflow_exceeded == 'true')
runs-on: ubuntu-slim
permissions:
contents: write
@ -986,7 +1021,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@ -995,8 +1030,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Code Simplifier"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-simplifier.lock.yml@${{ github.ref }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_BODY_MODIFIED: "false"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
@ -1013,6 +1048,40 @@ jobs:
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- name: Collect usage artifact files
if: always()
continue-on-error: true
run: |
mkdir -p /tmp/gh-aw/usage/agent /tmp/gh-aw/usage/detection
echo "Usage artifact source file status:"
for file in /tmp/gh-aw/aw-info.jsonl /tmp/gh-aw/agent_usage.jsonl /tmp/gh-aw/detection_usage.jsonl /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl; do
[ -f "$file" ] && echo "FOUND: $file" || echo "MISSING: $file"
done
[ -f /tmp/gh-aw/aw-info.jsonl ] && cp /tmp/gh-aw/aw-info.jsonl /tmp/gh-aw/usage/aw-info.jsonl || true
[ -f /tmp/gh-aw/agent_usage.jsonl ] && cp /tmp/gh-aw/agent_usage.jsonl /tmp/gh-aw/usage/agent_usage.jsonl || true
[ -f /tmp/gh-aw/detection_usage.jsonl ] && cp /tmp/gh-aw/detection_usage.jsonl /tmp/gh-aw/usage/detection_usage.jsonl || true
[ -f /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true
[ -f /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true
[ -f /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/agent/token_usage.jsonl || true
[ -f /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true
[ -f /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true
[ -f /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl ] && cp /tmp/gh-aw/threat-detection/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl /tmp/gh-aw/usage/detection/token_usage.jsonl || true
[ -f /tmp/gh-aw/usage/agent/token_usage.jsonl ] || : > /tmp/gh-aw/usage/agent/token_usage.jsonl
[ -f /tmp/gh-aw/usage/detection/token_usage.jsonl ] || : > /tmp/gh-aw/usage/detection/token_usage.jsonl
find /tmp/gh-aw/usage -type f -print | sort
- name: Upload usage artifact
if: always()
continue-on-error: true
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: usage
path: |
/tmp/gh-aw/usage/aw-info.jsonl
/tmp/gh-aw/usage/agent_usage.jsonl
/tmp/gh-aw/usage/detection_usage.jsonl
/tmp/gh-aw/usage/agent/token_usage.jsonl
/tmp/gh-aw/usage/detection/token_usage.jsonl
if-no-files-found: ignore
- name: Process no-op messages
id: noop
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@ -1026,6 +1095,10 @@ jobs:
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "false"
GH_AW_AIC: ${{ needs.agent.outputs.aic }}
GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
GH_AW_WORKFLOW_ID: "code-simplifier"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@ -1104,7 +1177,11 @@ jobs:
GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }}
GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }}
GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }}
GH_AW_UNKNOWN_MODEL_AI_CREDITS: ${{ needs.agent.outputs.unknown_model_ai_credits || 'false' }}
GH_AW_AIC: ${{ needs.agent.outputs.aic }}
GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }}
GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}
GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}
@ -1114,12 +1191,14 @@ jobs:
GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
GH_AW_DAILY_EFFECTIVE_WORKFLOW_EXCEEDED: ${{ needs.activation.outputs.daily_effective_workflow_exceeded }}
GH_AW_DAILY_EFFECTIVE_WORKFLOW_TOTAL_EFFECTIVE_TOKENS: ${{ needs.activation.outputs.daily_effective_workflow_total_effective_tokens }}
GH_AW_DAILY_EFFECTIVE_WORKFLOW_THRESHOLD: ${{ needs.activation.outputs.daily_effective_workflow_threshold }}
GH_AW_GROUP_REPORTS: "false"
GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
GH_AW_FAILURE_REPORT_AS_ISSUE: "false"
GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true"
GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true"
GH_AW_TIMEOUT_MINUTES: "30"
GH_AW_MAX_EFFECTIVE_TOKENS: "25000000"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@ -1138,13 +1217,14 @@ jobs:
permissions:
contents: read
outputs:
aic: ${{ steps.parse_detection_token_usage.outputs.aic }}
detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
detection_reason: ${{ steps.detection_conclusion.outputs.reason }}
detection_success: ${{ steps.detection_conclusion.outputs.success }}
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@ -1153,8 +1233,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Code Simplifier"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-simplifier.lock.yml@${{ github.ref }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_BODY_MODIFIED: "false"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
@ -1173,7 +1253,7 @@ jobs:
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
- name: Checkout repository for patch context
if: needs.agent.outputs.has_patch == 'true'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false
# --- Threat Detection ---
@ -1182,7 +1262,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.27.2@sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6 ghcr.io/github/gh-aw-firewall/api-proxy:0.27.2@sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4 ghcr.io/github/gh-aw-firewall/squid:0.27.2@sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591
- name: Check if detection needed
id: detection_guard
if: always()
@ -1207,6 +1287,7 @@ jobs:
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
rm -f /tmp/gh-aw/agent_usage.json
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
@ -1244,11 +1325,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.60
env:
GH_HOST: github.com
- name: Install AWF binary
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.27.2
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@ -1258,14 +1339,19 @@ jobs:
run: |
set -o pipefail
printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
trap 'rm -f /home/runner/.copilot/settings.json' EXIT
mkdir -p /home/runner/.copilot
printf '%s' '{"builtInAgents":{"rubberDuck":false}}' > /home/runner/.copilot/settings.json
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
GH_AW_MAX_AI_CREDITS="${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}"
printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.27.2/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.business.githubcopilot.com\",\"api.enterprise.githubcopilot.com\",\"api.github.com\",\"api.githubcopilot.com\",\"api.individual.githubcopilot.com\",\"github.com\",\"host.docker.internal\",\"registry.npmjs.org\",\"telemetry.enterprise.githubcopilot.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS}},\"container\":{\"imageTag\":\"0.27.2,squid=sha256:2e3a717e5f19a654cd9a2263beb52012b56bcb68562ec5ae2e42f9d156b49591,agent=sha256:f88e5b17b6b7a600117bc121114d6ce2155c88c983c0c939c5df884f730fa1d6,api-proxy=sha256:ee39841d980878ebbb87592903b06d31a1af500c71525c9616f7e8e2a27041a4,cli-proxy=sha256:02f3ec08f32dc26c5427920c6a2e2f3036238fce44802f2f11ef49ed8621b5d0\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json"
GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json"
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
@ -1281,16 +1367,18 @@ jobs:
fi
# shellcheck disable=SC1003
sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
-- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
-- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_VERSION: v0.77.5
GH_AW_TIMEOUT_MINUTES: 20
GH_AW_VERSION: v0.79.6
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@ -1305,6 +1393,19 @@ jobs:
GIT_COMMITTER_NAME: github-actions[bot]
RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Parse threat detection token usage for step summary
id: parse_detection_token_usage
if: always()
continue-on-error: true
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs');
await main();
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@ -1356,15 +1457,15 @@ jobs:
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Code Simplifier"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-simplifier.lock.yml@${{ github.ref }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_BODY_MODIFIED: "false"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Check team membership for workflow
@ -1404,15 +1505,19 @@ jobs:
contents: write
issues: write
pull-requests: write
timeout-minutes: 15
timeout-minutes: 45
env:
GH_AW_AGENT_AIC: ${{ needs.agent.outputs.aic }}
GH_AW_AIC: ${{ needs.agent.outputs.aic }}
GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }}
GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/code-simplifier"
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_ENGINE_VERSION: "1.0.60"
GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }}
GH_AW_TRACKER_ID: "code-simplifier"
GH_AW_WORKFLOW_ID: "code-simplifier"
GH_AW_WORKFLOW_NAME: "Code Simplifier"
@ -1430,7 +1535,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
uses: github/gh-aw-actions/setup@v0.77.5
uses: github/gh-aw-actions/setup@v0.79.6
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@ -1439,8 +1544,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Code Simplifier"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/code-simplifier.lock.yml@${{ github.ref }}
GH_AW_INFO_VERSION: "1.0.55"
GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_VERSION: "1.0.60"
GH_AW_INFO_AWF_VERSION: "v0.27.2"
GH_AW_INFO_BODY_MODIFIED: "false"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
@ -1475,7 +1580,7 @@ jobs:
await main();
- name: Checkout repository (trusted default branch for comment events)
if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') && (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment')
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ github.event.repository.default_branch }}
token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
@ -1483,7 +1588,7 @@ jobs:
fetch-depth: 1
- name: Checkout repository
if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') && github.event_name != 'issue_comment' && github.event_name != 'pull_request_review_comment'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
ref: ${{ steps.extract-base-branch.outputs.base-branch || github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
@ -1506,6 +1611,7 @@ jobs:
- name: Configure GH_HOST for enterprise compatibility
id: ghes-host-config
shell: bash
# zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input.
run: |
# Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
# GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.

View file

@ -14,6 +14,7 @@ tracker-id: code-simplifier
safe-outputs:
report-failure-as-issue: false
create-pull-request:
title-prefix: "[code-simplifier] "
labels: [refactoring, code-quality, automation]

File diff suppressed because one or more lines are too long

View file

@ -22,6 +22,7 @@ tools:
toolsets: [default]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[Compare Stats] "
category: "agentic workflows"

View file

@ -89,13 +89,13 @@ jobs:
id: date
run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v7.0.1
- uses: actions/upload-artifact@v7
with:
name: coverage-${{steps.date.outputs.date}}
path: ${{github.workspace}}/coverage.html
retention-days: 4
- uses: actions/upload-artifact@v7.0.1
- uses: actions/upload-artifact@v7
with:
name: coverage-details-${{steps.date.outputs.date}}
path: ${{env.COV_DETAILS_PATH}}

File diff suppressed because one or more lines are too long

View file

@ -18,6 +18,7 @@ tools:
bash: [":*"]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[CSA] "
category: "Agentic Workflows"

View file

@ -34,7 +34,7 @@ jobs:
python3 mk_go_doc.py --output-dir=api/html/go --go-api-path=../src/api/go
- name: Upload Go Documentation
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: go-docs
path: doc/api/html/go/

View file

@ -147,7 +147,7 @@ jobs:
- name: Upload generated SMT2 artifact
id: upload_smt2
if: always() && steps.collect_smt2.outputs.has_files == 'true'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fstar-generated-smt2-${{ github.run_id }}
path: /tmp/gh-aw/agent/smt2-artifact

File diff suppressed because one or more lines are too long

View file

@ -13,6 +13,7 @@ tools:
toolsets: [default]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[Issue Backlog] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -31,6 +31,7 @@ tools:
bash: [":*"]
safe-outputs:
report-failure-as-issue: false
mentions: false
allowed-github-references: []
max-bot-mentions: 1

View file

@ -104,7 +104,7 @@ jobs:
- name: Upload ASan reports
if: always()
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: asan-reports
path: /tmp/asan-reports/
@ -194,7 +194,7 @@ jobs:
- name: Upload UBSan reports
if: always()
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ubsan-reports
path: /tmp/ubsan-reports/

View file

@ -59,7 +59,7 @@ jobs:
echo "OK: macOS x64 artifacts are x86_64"
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: macOsBuild
path: dist/*.zip
@ -95,7 +95,7 @@ jobs:
echo "OK: macOS arm64 artifacts are arm64"
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: MacArm64
path: dist/*.zip
@ -246,7 +246,7 @@ jobs:
run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: UbuntuBuild
path: dist/*.zip
@ -281,7 +281,7 @@ jobs:
python scripts/mk_unix_dist.py --nodotnet --arch=arm64
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: UbuntuArm64
path: dist/*.zip
@ -336,7 +336,7 @@ jobs:
run: zip -r z3doc.zip doc/api
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: UbuntuDoc
path: z3doc.zip
@ -374,7 +374,7 @@ jobs:
run: pip install ./src/api/python/wheelhouse/*.whl && python - <src/api/python/z3test.py z3 && python - <src/api/python/z3test.py z3num
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ManyLinuxPythonBuildAMD64
path: src/api/python/wheelhouse/*.whl
@ -422,7 +422,7 @@ jobs:
run: cd src/api/python && CC=aarch64-none-linux-gnu-gcc CXX=aarch64-none-linux-gnu-g++ AR=aarch64-none-linux-gnu-ar LD=aarch64-none-linux-gnu-ld Z3_CROSS_COMPILING=aarch64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ManyLinuxPythonBuildArm64
path: src/api/python/wheelhouse/*.whl
@ -477,7 +477,7 @@ jobs:
run: cd src/api/python && CC=riscv64-unknown-linux-gnu-gcc CXX=riscv64-unknown-linux-gnu-g++ AR=riscv64-unknown-linux-gnu-ar LD=riscv64-unknown-linux-gnu-ld Z3_CROSS_COMPILING=riscv64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ManyLinuxPythonBuildRiscv64
path: src/api/python/wheelhouse/*.whl
@ -530,7 +530,7 @@ jobs:
~/env-pyodide/bin/python src/api/python/z3test.py z3
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: PyodidePythonBuild
path: src/api/python/dist/*.whl
@ -552,11 +552,12 @@ jobs:
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 || exit /b 1
python scripts\mk_win_dist.py --x64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: WindowsBuild-x64
path: dist/*.zip
@ -578,11 +579,12 @@ jobs:
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x86 || exit /b 1
python scripts\mk_win_dist.py --x86-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: WindowsBuild-x86
path: dist/*.zip
@ -604,11 +606,12 @@ jobs:
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64 || exit /b 1
python scripts\mk_win_dist_cmake.py --arm64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }} --zip
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: WindowsBuild-arm64
path: dist/arm64/*.zip
@ -685,7 +688,7 @@ jobs:
nuget pack out\Microsoft.Z3.sym.nuspec -Version ${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}.${{ github.run_number }} -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: NuGet
path: |
@ -730,7 +733,7 @@ jobs:
nuget pack out\Microsoft.Z3.x86.sym.nuspec -Version ${{ env.MAJOR }}.${{ env.MINOR }}.${{ env.PATCH }}.${{ github.run_number }} -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: NuGet32
path: |
@ -835,7 +838,7 @@ jobs:
cp artifacts/*.whl src/api/python/dist/.
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: PythonPackages
path: src/api/python/dist/*

View file

@ -30,11 +30,12 @@ jobs:
- name: Build Windows x64
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 || exit /b 1
python scripts\mk_win_dist.py --x64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ github.event.inputs.version || '4.17.0' }} --zip
- name: Upload Windows x64 artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: windows-x64
path: dist/*.zip
@ -54,11 +55,12 @@ jobs:
- name: Build Windows x86
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x86 || exit /b 1
python scripts\mk_win_dist.py --x86-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ github.event.inputs.version || '4.17.0' }} --zip
- name: Upload Windows x86 artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: windows-x86
path: dist/*.zip
@ -78,11 +80,12 @@ jobs:
- name: Build Windows ARM64
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64 || exit /b 1
python scripts\mk_win_dist_cmake.py --arm64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ github.event.inputs.version || '4.17.0' }} --zip
- name: Upload Windows ARM64 artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: windows-arm64
path: build-dist\arm64\dist\*.zip
@ -103,7 +106,7 @@ jobs:
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk
- name: Upload Ubuntu artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ubuntu
path: dist/*.zip
@ -124,7 +127,7 @@ jobs:
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk
- name: Upload macOS x64 artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: macos-x64
path: dist/*.zip
@ -145,7 +148,7 @@ jobs:
run: python scripts/mk_unix_dist.py --dotnet-key=$GITHUB_WORKSPACE/resources/z3.snk --arch=arm64
- name: Upload macOS ARM64 artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: macos-arm64
path: dist/*.zip
@ -198,7 +201,7 @@ jobs:
nuget pack out\Microsoft.Z3.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
- name: Upload NuGet package
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: nuget-x64
path: |
@ -247,7 +250,7 @@ jobs:
nuget pack out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
- name: Upload NuGet package
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: nuget-x86
path: |

File diff suppressed because one or more lines are too long

View file

@ -19,6 +19,7 @@ tools:
toolsets: [default]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[Ostrich Benchmark] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -16,6 +16,7 @@ tools:
toolsets: [default]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[QF_S Benchmark] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -18,6 +18,7 @@ tools:
edit: {}
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[Release Notes] "
category: "Announcements"

View file

@ -66,7 +66,7 @@ jobs:
run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: macOsBuild
path: dist/*.zip
@ -105,7 +105,7 @@ jobs:
run: git clone https://github.com/z3prover/z3test z3test
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: MacArm64
path: dist/*.zip
@ -256,7 +256,7 @@ jobs:
run: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: UbuntuBuild
path: dist/*.zip
@ -291,7 +291,7 @@ jobs:
python scripts/mk_unix_dist.py --nodotnet --arch=arm64
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: UbuntuArm64
path: dist/*.zip
@ -346,7 +346,7 @@ jobs:
run: zip -r z3doc.zip doc/api
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: UbuntuDoc
path: z3doc.zip
@ -384,7 +384,7 @@ jobs:
run: pip install ./src/api/python/wheelhouse/*.whl && python - <src/api/python/z3test.py z3 && python - <src/api/python/z3test.py z3num
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ManyLinuxPythonBuildAMD64
path: src/api/python/wheelhouse/*.whl
@ -432,7 +432,7 @@ jobs:
run: cd src/api/python && CC=aarch64-none-linux-gnu-gcc CXX=aarch64-none-linux-gnu-g++ AR=aarch64-none-linux-gnu-ar LD=aarch64-none-linux-gnu-ld Z3_CROSS_COMPILING=aarch64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ManyLinuxPythonBuildArm64
path: src/api/python/wheelhouse/*.whl
@ -487,7 +487,7 @@ jobs:
run: cd src/api/python && CC=riscv64-unknown-linux-gnu-gcc CXX=riscv64-unknown-linux-gnu-g++ AR=riscv64-unknown-linux-gnu-ar LD=riscv64-unknown-linux-gnu-ld Z3_CROSS_COMPILING=riscv64 python -m build && AUDITWHEEL_PLAT= auditwheel repair --best-plat dist/*.whl && cd ../../..
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: ManyLinuxPythonBuildRiscv64
path: src/api/python/wheelhouse/*.whl
@ -540,7 +540,7 @@ jobs:
~/env-pyodide/bin/python src/api/python/z3test.py z3
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: PyodidePythonBuild
path: src/api/python/dist/*.whl
@ -562,11 +562,12 @@ jobs:
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 || exit /b 1
python scripts\mk_win_dist.py --x64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: WindowsBuild-x64
path: dist/*.zip
@ -588,11 +589,12 @@ jobs:
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x86 || exit /b 1
python scripts\mk_win_dist.py --x86-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --zip
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: WindowsBuild-x86
path: dist/*.zip
@ -614,11 +616,12 @@ jobs:
- name: Build
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
for /f "usebackq delims=" %%i in (`"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSPATH=%%i"
call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64 || exit /b 1
python scripts\mk_win_dist_cmake.py --arm64-only --dotnet-key=%GITHUB_WORKSPACE%\resources\z3.snk --assembly-version=${{ env.RELEASE_VERSION }} --zip
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: WindowsBuild-arm64
path: dist/arm64/*.zip
@ -695,7 +698,7 @@ jobs:
nuget pack out\Microsoft.Z3.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: NuGet
path: |
@ -740,7 +743,7 @@ jobs:
nuget pack out\Microsoft.Z3.x86.sym.nuspec -OutputDirectory . -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -BasePath out
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: NuGet32
path: |
@ -842,7 +845,7 @@ jobs:
cp artifacts/*.whl src/api/python/dist/.
- name: Upload artifact
uses: actions/upload-artifact@v7.0.1
uses: actions/upload-artifact@v7
with:
name: PythonPackage
path: src/api/python/dist/*

File diff suppressed because one or more lines are too long

View file

@ -30,6 +30,7 @@ tools:
bash: [":*"]
safe-outputs:
report-failure-as-issue: false
mentions: false
allowed-github-references: []
max-bot-mentions: 1

File diff suppressed because one or more lines are too long

View file

@ -20,6 +20,7 @@ tools:
edit: {}
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[Specbot] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -21,6 +21,7 @@ tools:
bash: [":*"]
safe-outputs:
report-failure-as-issue: false
create-issue:
labels:
- enhancement

File diff suppressed because one or more lines are too long

View file

@ -23,6 +23,7 @@ tools:
toolsets: [default]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[TPTP Benchmark] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -17,6 +17,7 @@ tools:
bash: [":*"]
safe-outputs:
report-failure-as-issue: false
create-discussion:
title-prefix: "[Workflow Suggestions] "
category: "Agentic Workflows"

File diff suppressed because one or more lines are too long

View file

@ -27,6 +27,7 @@ tools:
- "clang-format:*"
safe-outputs:
report-failure-as-issue: false
create-issue:
title-prefix: "[zipt-review] "
labels: [code-quality, automated, string-solver]

View file

@ -6112,10 +6112,17 @@
}
},
"node_modules/shell-quote": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz",
"integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==",
"dev": true
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
"integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/side-channel": {
"version": "1.0.4",

View file

@ -41,6 +41,7 @@ z3_add_component(rewriter
seq_eq_solver.cpp
seq_subset.cpp
seq_rewriter.cpp
seq_regex_bisim.cpp
seq_skolem.cpp
th_rewriter.cpp
value_sweep.cpp

View file

@ -0,0 +1,269 @@
/*++
Copyright (c) 2026 Microsoft Corporation
Module Name:
seq_regex_bisim.cpp
Abstract:
See seq_regex_bisim.h.
Author:
Margus Veanes (veanes)
Nikolaj Bjorner (nbjorner)
--*/
#include "ast/rewriter/seq_regex_bisim.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "ast/for_each_expr.h"
namespace seq {
regex_bisim::regex_bisim(seq_rewriter& rw):
m(rw.m()),
m_rw(rw),
m_util(rw.u()),
m_pinned(m),
m_worklist(m) {
}
void regex_bisim::reset() {
m_uf.reset();
m_node_of.reset();
m_pinned.reset();
m_worklist.reset();
m_steps = 0;
}
/*
Map an expression to a union-find node, allocating a fresh node on
first encounter.
*/
unsigned regex_bisim::node_of(expr* r) {
unsigned id = 0;
if (m_node_of.find(r, id))
return id;
id = m_uf.mk_var();
m_node_of.insert(r, id);
m_pinned.push_back(r);
return id;
}
/*
Compute a definite nullability answer for r.
If the seq_rewriter is unable to produce a literal true/false (for
example because r contains an uninterpreted symbol), return l_undef.
*/
lbool regex_bisim::nullability(expr* r) {
expr_ref n = m_rw.is_nullable(r);
if (m.is_true(n))
return l_true;
if (m.is_false(n))
return l_false;
return l_undef;
}
/*
Test whether a regex expression is a kind that the bisimulation
procedure can reason about. We require it to be a syntactic ground
term (no free variables) and that its info reports min_length info
(which implies that it parses cleanly as a regex constructor).
*/
bool regex_bisim::is_supported(expr* r) {
if (!m_util.is_re(r))
return false;
if (!m_util.re.get_info(r).is_known())
return false;
// Reject regexes mentioning free variables; the symbolic
// derivative engine introduces (:var 0) only after we call it
// ourselves, so any pre-existing variable would be a free var.
return is_ground(r);
}
/*
Collect the leaves of a t-regex der (an ITE-tree whose leaves are
regex expressions) into the output vector. Empty (re.empty) leaves
are dropped.
Each leaf is treated as a single bisimulation state regardless of
its top-level shape (including re.union and re.antimirov_union):
descending into a union at the leaf would split one state into
several, which is semantically unsound for the bisimulation /
union-find merging that follows.
Returns false if we encountered an unexpected node (e.g. a free
variable creeping in) in that case the caller should bail out.
*/
bool regex_bisim::collect_leaves(expr* der, expr_ref_vector& leaves) {
ptr_vector<expr> work;
obj_hashtable<expr> seen;
work.push_back(der);
seen.insert(der);
while (!work.empty()) {
expr* e = work.back();
work.pop_back();
expr* c = nullptr, * t = nullptr, * f = nullptr;
if (m.is_ite(e, c, t, f)) {
if (seen.insert_if_not_there(t))
work.push_back(t);
if (seen.insert_if_not_there(f))
work.push_back(f);
continue;
}
if (m_util.re.is_empty(e))
continue;
if (!m_util.is_re(e))
return false;
leaves.push_back(e);
}
return true;
}
/*
Fast inequivalence check based on the get_info().classical flag.
Invariant: if r is well-formed and get_info(r).classical is true,
then L(r) is non-empty. The flag is set for regexes built only
from str.to_re, re.all, union, concat, star, plus, opt, loop;
it excludes complement, intersection, diff, xor, and the empty
regex.
A bare regex leaf l (i.e. not a XOR pair) represents the implicit
pair (empty XOR l). If l is classical, L(l) is non-empty so the
pair is non-empty: the original two regexes have a distinguishing
prefix and are inequivalent.
For an XOR leaf xor(a, b): if both a and b are classical and have
different min_length, then the shortest word of one is not in the
other, so the pair is non-empty and we can short-circuit. (The
case a == b syntactically is already handled by mk_re_xor0.)
Returns true if the leaf proves inequivalence; false if no
conclusion can be drawn.
*/
bool regex_bisim::classical_distinguishing(expr* l) {
expr* a = nullptr, * b = nullptr;
if (m_util.re.is_xor(l, a, b)) {
auto ia = m_util.re.get_info(a);
auto ib = m_util.re.get_info(b);
if (ia.is_known() && ib.is_known() &&
ia.classical && ib.classical &&
ia.min_length != ib.min_length)
return true;
return false;
}
if (m_util.re.is_empty(l))
return false;
auto info = m_util.re.get_info(l);
return info.is_known() && info.classical;
}
/*
Merge the two sides of the XOR pair, returning true if a fresh
merge happened (i.e. the pair must still be processed) and false
if the two sides were already in the same union-find class.
For non-XOR leaves we treat the leaf l as the pair (empty XOR l).
*/
bool regex_bisim::merge_leaf(expr* leaf) {
expr* a = nullptr, * b = nullptr;
if (!m_util.re.is_xor(leaf, a, b)) {
a = m_util.re.mk_empty(leaf->get_sort());
b = leaf;
m_pinned.push_back(a);
}
unsigned ia = node_of(a);
unsigned ib = node_of(b);
if (m_uf.find(ia) == m_uf.find(ib))
return false;
m_uf.merge(ia, ib);
return true;
}
/*
Decide equivalence by bisimulation on D(p XOR q).
*/
lbool regex_bisim::are_equivalent(expr* p, expr* q) {
return are_equivalent_core(p, q);
}
lbool regex_bisim::are_equivalent_core(expr* p, expr* q) {
if (!is_supported(p) || !is_supported(q))
return l_undef;
if (p == q)
return l_true;
reset();
// Build the initial pair r0 = p XOR q applying the structural
// XOR rewrites (r XOR r = empty, AC normalisation, etc.).
expr_ref r0 = m_rw.mk_re_xor_simplified(p, q);
// If r0 simplified to empty, the two regexes are equivalent.
if (m_util.re.is_empty(r0))
return l_true;
lbool n0 = nullability(r0);
if (n0 == l_true)
return l_false; // distinguishing empty word
if (n0 == l_undef)
return l_undef;
// Classical-leaf shortcut applied to r0 (covers the case where
// mk_re_xor_simplified collapsed p XOR q to a bare classical
// residual, e.g. when one side reduced to empty).
if (classical_distinguishing(r0))
return l_false;
if (!merge_leaf(r0))
return l_true; // already merged: trivially equivalent
m_worklist.push_back(r0);
while (!m_worklist.empty()) {
if (++m_steps > m_step_bound)
return l_undef;
expr_ref r(m_worklist.back(), m);
m_worklist.pop_back();
// Compute the symbolic derivative wrt the canonical variable
// (:var 0). The result is a transition regex (ITE tree) whose
// leaves are regex expressions. We use the classical Brzozowski
// entry point so the derivative stays as a single TRegex and
// does not lift unions to the top via antimirov nodes — this
// preserves the XOR-pair invariant the bisimulation relies on.
expr_ref d(m_rw.mk_brz_derivative(r), m);
expr_ref_vector leaves(m);
if (!collect_leaves(d, leaves))
return l_undef;
// First pass: check for any nullable leaf (definitive
// distinguishing empty-continuation word) or any classically
// non-empty leaf (definitive distinguishing non-empty prefix).
for (expr* l : leaves) {
lbool nl = nullability(l);
if (nl == l_true)
return l_false;
if (nl == l_undef)
return l_undef;
if (classical_distinguishing(l))
return l_false;
}
// Second pass: merge each leaf into the union-find; new
// merges go onto the worklist.
for (expr* l : leaves) {
if (merge_leaf(l)) {
m_pinned.push_back(l);
m_worklist.push_back(l);
}
}
}
return l_true;
}
}

View file

@ -0,0 +1,100 @@
/*++
Copyright (c) 2026 Microsoft Corporation
Module Name:
seq_regex_bisim.h
Abstract:
Union-find based bisimulation algorithm for symbolic regular expression
equivalence, based on the construction described in:
"Symbolic Extended Regular Expression Equivalence"
Ian, Kathi, Margus
The algorithm decides equivalence of two regexes p, q by performing
a bisimulation search on the symbolic derivative of p XOR q. A
union-find structure tracks pairs of regex states that should be
bisimilar, and the worklist is initialised with the singleton
{p XOR q}.
The algorithm returns:
l_true p and q are equivalent (bisimilar)
l_false p and q are inequivalent (a distinguishing prefix exists)
l_undef the algorithm could not decide within the configured bound
or encountered a non-ground regex it cannot reason about
Author:
Nikolaj Bjorner (nbjorner)
Margus Veanes (veanes)
--*/
#pragma once
#include "ast/seq_decl_plugin.h"
#include "util/lbool.h"
#include "util/obj_hashtable.h"
#include "util/union_find.h"
class seq_rewriter;
namespace seq {
/*
Union-find based bisimulation algorithm for deciding equivalence
of two ground (closed) regular expressions in ERE.
Usage:
seq::regex_bisim bisim(rewriter);
lbool r = bisim.are_equivalent(p, q);
if (r == l_true) // p ≡ q
if (r == l_false) // p ≢ q
if (r == l_undef) // cannot decide
The implementation only attempts the equivalence check on ground
regexes (no free variables) that use the standard symbolic regex
constructors. For non-ground or unsupported inputs the procedure
conservatively returns l_undef.
*/
class regex_bisim {
private:
ast_manager& m;
seq_rewriter& m_rw;
seq_util m_util;
basic_union_find m_uf;
obj_map<expr, unsigned> m_node_of;
expr_ref_vector m_pinned;
expr_ref_vector m_worklist;
unsigned m_step_bound { 50000 };
unsigned m_steps { 0 };
unsigned node_of(expr* r);
bool merge_leaf(expr* xor_pair);
bool collect_leaves(expr* der, expr_ref_vector& leaves);
lbool nullability(expr* r);
bool is_supported(expr* r);
// Returns true if the leaf l proves that the original pair is
// inequivalent and the bisim can short-circuit to l_false.
// Uses the get_info().classical invariant: a classical regex
// has non-empty language, so a bare classical leaf (implicitly
// empty XOR r) is a distinguishing prefix. Similarly an XOR of
// two classical regexes with different min_length is
// distinguishing.
bool classical_distinguishing(expr* l);
void reset();
lbool are_equivalent_core(expr* p, expr* q);
public:
regex_bisim(seq_rewriter& rw);
void set_step_bound(unsigned n) { m_step_bound = n; }
lbool are_equivalent(expr* p, expr* q);
};
}

View file

@ -20,6 +20,7 @@ Authors:
#include "util/uint_set.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/rewriter/seq_regex_bisim.h"
#include "ast/arith_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/ast_pp.h"
@ -267,6 +268,14 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
st = BR_DONE;
}
break;
case OP_RE_XOR:
if (num_args == 2)
st = mk_re_xor(args[0], args[1], result);
else if (num_args == 1) {
result = args[0];
st = BR_DONE;
}
break;
case OP_RE_INTERSECT:
if (num_args == 1) {
result = args[0];
@ -2622,6 +2631,23 @@ expr_ref seq_rewriter::is_nullable_rec(expr* r) {
m_br.mk_not(is_nullable(r2), result);
m_br.mk_and(result, is_nullable(r1), result);
}
else if (re().is_xor(r, r1, r2)) {
// Null(r1 XOR r2) = Null(r1) XOR Null(r2)
expr_ref n1(is_nullable(r1), m());
expr_ref n2(is_nullable(r2), m());
// Simplify when either operand is a boolean literal so the
// bisimulation procedure can use the answer directly.
if (m().is_true(n1))
result = mk_not(m(), n2);
else if (m().is_false(n1))
result = n2;
else if (m().is_true(n2))
result = mk_not(m(), n1);
else if (m().is_false(n2))
result = n1;
else
result = m().mk_xor(n1, n2);
}
else if (re().is_star(r) ||
re().is_opt(r) ||
re().is_full_seq(r) ||
@ -2742,6 +2768,12 @@ br_status seq_rewriter::mk_re_reverse(expr* r, expr_ref& result) {
result = re().mk_diff(a, b);
return BR_REWRITE2;
}
else if (re().is_xor(r, r1, r2)) {
auto a = re().mk_reverse(r1);
auto b = re().mk_reverse(r2);
result = re().mk_xor(a, b);
return BR_REWRITE2;
}
else if (m().is_ite(r, p, r1, r2)) {
result = m().mk_ite(p, re().mk_reverse(r1), re().mk_reverse(r2));
return BR_REWRITE2;
@ -2882,6 +2914,7 @@ bool seq_rewriter::check_deriv_normal_form(expr* r, int level) {
re().is_concat(r, r1, r2) ||
re().is_union(r, r1, r2) ||
re().is_intersection(r, r1, r2) ||
re().is_xor(r, r1, r2) ||
m().is_ite(r, p, r1, r2)) {
check_deriv_normal_form(r1, new_level);
check_deriv_normal_form(r2, new_level);
@ -2921,6 +2954,14 @@ expr_ref seq_rewriter::mk_derivative(expr* r) {
return mk_antimirov_deriv(v, r, m().mk_true());
}
expr_ref seq_rewriter::mk_brz_derivative(expr* r) {
sort* seq_sort = nullptr, * ele_sort = nullptr;
VERIFY(m_util.is_re(r, seq_sort));
VERIFY(m_util.is_seq(seq_sort, ele_sort));
expr_ref v(m().mk_var(0, ele_sort), m());
return mk_derivative_rec(v, r);
}
expr_ref seq_rewriter::mk_derivative(expr* ele, expr* r) {
return mk_antimirov_deriv(ele, r, m().mk_true());
}
@ -3120,6 +3161,10 @@ void seq_rewriter::mk_antimirov_deriv_rec(expr* e, expr* r, expr* path, expr_ref
result = mk_antimirov_deriv_intersection(e,
mk_antimirov_deriv(e, r1, path),
mk_antimirov_deriv_negate(e, mk_antimirov_deriv(e, r2, path)), m().mk_true());
else if (re().is_xor(r, r1, r2))
// D(e, r1 XOR r2) = D(e, r1) XOR D(e, r2)
result = mk_der_xor(mk_antimirov_deriv(e, r1, path),
mk_antimirov_deriv(e, r2, path));
else if (re().is_of_pred(r, r1)) {
array_util array(m());
expr* args[2] = { r1, e };
@ -3269,11 +3314,20 @@ expr_ref seq_rewriter::mk_antimirov_deriv_restrict(expr* e, expr* d, expr* cond)
expr_ref seq_rewriter::mk_regex_union_normalize(expr* r1, expr* r2) {
expr_ref _r1(r1, m()), _r2(r2, m());
expr *a1, *b1, *a2, *b2;
SASSERT(m_util.is_re(r1));
SASSERT(m_util.is_re(r2));
expr_ref result(m());
std::function<bool(expr*, expr*&, expr*&)> test = [&](expr* t, expr*& a, expr*& b) { return re().is_union(t, a, b); };
std::function<expr* (expr*, expr*)> compose = [&](expr* r1, expr* r2) { return (is_subset(r1, r2) ? r2 : (is_subset(r2, r1) ? r1 : re().mk_union(r1, r2))); };
std::function<bool(expr *, expr *)> is_complement = [&](expr *a, expr *b) {
expr *s;
if (re().is_complement(a, s) && s == b)
return true;
if (re().is_complement(b, s) && s == a)
return true;
return false;
};
if (r1 == r2 || re().is_empty(r2) || re().is_full_seq(r1))
result = r1;
else if (re().is_empty(r1) || re().is_full_seq(r2))
@ -3282,6 +3336,15 @@ expr_ref seq_rewriter::mk_regex_union_normalize(expr* r1, expr* r2) {
result = r1;
else if (re().is_dot_plus(r2) && re().get_info(r1).min_length > 0)
result = r2;
// (R1 \ R2) U (R2 \ R1) = R1 xor R2
else if (false && re().is_intersection(r1, a1, a2) && re().is_intersection(r2, b1, b2) &&
is_complement(a1, b2) && is_complement(a2, b1)) {
result = re().mk_xor(a1, re().mk_complement(a2));
}
else if (false && re().is_intersection(r1, a1, a2) && re().is_intersection(r2, b1, b2) &&
is_complement(a1, b1) && is_complement(a2, b2)) {
result = re().mk_xor(a1, re().mk_complement(a2));
}
else
result = merge_regex_sets(r1, r2, re().mk_full_seq(r1->get_sort()), test, compose);
return result;
@ -3451,6 +3514,11 @@ expr_ref seq_rewriter::mk_regex_reverse(expr* r) {
auto b1 = mk_regex_reverse(r2);
result = re().mk_diff(a1, b1);
}
else if (re().is_xor(r, r1, r2)) {
auto a1 = mk_regex_reverse(r1);
auto b1 = mk_regex_reverse(r2);
result = re().mk_xor(a1, b1);
}
else if (re().is_star(r, r1))
result = re().mk_star(mk_regex_reverse(r1));
else if (re().is_plus(r, r1))
@ -3546,7 +3614,6 @@ expr_ref seq_rewriter::simplify_path(expr* elem, expr* path) {
expr_ref seq_rewriter::mk_der_antimirov_union(expr* r1, expr* r2) {
verbose_stream() << "union " << r1->get_id() << " " << r2->get_id() << "\n";
return mk_der_op(_OP_RE_ANTIMIROV_UNION, r1, r2);
}
@ -3558,6 +3625,10 @@ expr_ref seq_rewriter::mk_der_inter(expr* r1, expr* r2) {
return mk_der_op(OP_RE_INTERSECT, r1, r2);
}
expr_ref seq_rewriter::mk_der_xor(expr* r1, expr* r2) {
return mk_der_op(OP_RE_XOR, r1, r2);
}
expr_ref seq_rewriter::mk_der_concat(expr* r1, expr* r2) {
return mk_der_op(OP_RE_CONCAT, r1, r2);
}
@ -3729,7 +3800,7 @@ expr_ref seq_rewriter::mk_der_op_rec(decl_kind k, expr* a, expr* b) {
return result;
}
// Order with higher IDs on the outside
bool is_symmetric = k == OP_RE_UNION || k == OP_RE_INTERSECT;
bool is_symmetric = k == OP_RE_UNION || k == OP_RE_INTERSECT || k == OP_RE_XOR;
if (is_symmetric && get_id(ca) < get_id(cb)) {
std::swap(a, b);
std::swap(ca, cb);
@ -3776,6 +3847,10 @@ expr_ref seq_rewriter::mk_der_op_rec(decl_kind k, expr* a, expr* b) {
if (BR_FAILED == mk_re_concat(a, b, result))
result = re().mk_concat(a, b);
break;
case OP_RE_XOR:
if (BR_FAILED == mk_re_xor(a, b, result))
result = re().mk_xor(a, b);
break;
default:
UNREACHABLE();
break;
@ -3806,6 +3881,10 @@ expr_ref seq_rewriter::mk_der_op(decl_kind k, expr* a, expr* b) {
if (BR_FAILED != mk_re_concat(a, b, result))
return result;
break;
case OP_RE_XOR:
if (BR_FAILED != mk_re_xor0(a, b, result))
return result;
break;
default:
break;
}
@ -3909,6 +3988,13 @@ expr_ref seq_rewriter::mk_der_cond(expr* cond, expr* ele, sort* seq_sort) {
return result;
}
/*
Classical Brzozowski derivative used by the regex_bisim equivalence
procedure. Unlike `mk_antimirov_deriv`, this variant never creates
_OP_RE_ANTIMIROV_UNION nodes it stays in a classical (single regex
tree) form. The bisimulation algorithm relies on this so that each
leaf of D(p XOR q) is a coherent XOR pair (D_v p) XOR (D_v q).
*/
expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
expr_ref result(m());
sort* seq_sort = nullptr, *ele_sort = nullptr;
@ -3920,57 +4006,59 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
unsigned lo = 0, hi = 0;
if (re().is_concat(r, r1, r2)) {
expr_ref is_n = is_nullable(r1);
expr_ref dr1 = mk_derivative(ele, r1);
expr_ref dr1 = mk_derivative_rec(ele, r1);
result = mk_der_concat(dr1, r2);
if (m().is_false(is_n)) {
return result;
}
expr_ref dr2 = mk_derivative(ele, r2);
expr_ref dr2 = mk_derivative_rec(ele, r2);
is_n = re_predicate(is_n, seq_sort);
if (re().is_empty(dr2)) {
//do not concatenate [], it is a deade-end
return result;
}
else {
// Instead of mk_der_union here, we use mk_der_antimirov_union to
// force the two cases to be considered separately and lifted to
// the top level. This avoids blowup in cases where determinization
// is expensive.
return mk_der_antimirov_union(result, mk_der_concat(is_n, dr2));
// Classical Brzozowski union: keep the derivative tree free of
// antimirov-union nodes so the bisimulation procedure sees a
// single regex tree whose leaves are XOR pairs.
return mk_der_union(result, mk_der_concat(is_n, dr2));
}
}
else if (re().is_star(r, r1)) {
return mk_der_concat(mk_derivative(ele, r1), r);
return mk_der_concat(mk_derivative_rec(ele, r1), r);
}
else if (re().is_plus(r, r1)) {
expr_ref star(re().mk_star(r1), m());
return mk_derivative(ele, star);
return mk_derivative_rec(ele, star);
}
else if (re().is_union(r, r1, r2)) {
return mk_der_union(mk_derivative(ele, r1), mk_derivative(ele, r2));
return mk_der_union(mk_derivative_rec(ele, r1), mk_derivative_rec(ele, r2));
}
else if (re().is_intersection(r, r1, r2)) {
return mk_der_inter(mk_derivative(ele, r1), mk_derivative(ele, r2));
return mk_der_inter(mk_derivative_rec(ele, r1), mk_derivative_rec(ele, r2));
}
else if (re().is_diff(r, r1, r2)) {
return mk_der_inter(mk_derivative(ele, r1), mk_der_compl(mk_derivative(ele, r2)));
return mk_der_inter(mk_derivative_rec(ele, r1), mk_der_compl(mk_derivative_rec(ele, r2)));
}
else if (re().is_xor(r, r1, r2)) {
return mk_der_xor(mk_derivative_rec(ele, r1), mk_derivative_rec(ele, r2));
}
else if (m().is_ite(r, p, r1, r2)) {
// there is no BDD normalization here
result = m().mk_ite(p, mk_derivative(ele, r1), mk_derivative(ele, r2));
result = m().mk_ite(p, mk_derivative_rec(ele, r1), mk_derivative_rec(ele, r2));
return result;
}
else if (re().is_opt(r, r1)) {
return mk_derivative(ele, r1);
return mk_derivative_rec(ele, r1);
}
else if (re().is_complement(r, r1)) {
return mk_der_compl(mk_derivative(ele, r1));
return mk_der_compl(mk_derivative_rec(ele, r1));
}
else if (re().is_loop(r, r1, lo)) {
if (lo > 0) {
lo--;
}
result = mk_derivative(ele, r1);
result = mk_derivative_rec(ele, r1);
//do not concatenate with [] (emptyset)
if (re().is_empty(result)) {
return result;
@ -3988,7 +4076,7 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
if (lo > 0) {
lo--;
}
result = mk_derivative(ele, r1);
result = mk_derivative_rec(ele, r1);
//do not concatenate with [] (emptyset) or handle the rest of the loop if no more iterations remain
if (re().is_empty(result) || hi == 0) {
return result;
@ -4756,6 +4844,91 @@ br_status seq_rewriter::mk_re_diff(expr* a, expr* b, expr_ref& result) {
return BR_REWRITE2;
}
/*
Symmetric difference / XOR of regexes.
LANG(a XOR b) = (LANG(a) \ LANG(b)) U (LANG(b) \ LANG(a))
Equivalence preserving rewrites applied here (paper Section 5):
r XOR r = []
r XOR [] = r
[] XOR r = r
comp(r) XOR comp(s) = r XOR s
r XOR comp(s) = comp(r XOR s)
comp(r) XOR s = comp(r XOR s)
full_seq XOR r = comp(r)
r XOR full_seq = comp(r)
We also normalize the argument order using expression ids so that the
structure is canonical for AC.
*/
br_status seq_rewriter::mk_re_xor0(expr* a, expr* b, expr_ref& result) {
// Reduction-only variant of mk_re_xor for use inside mk_der_op.
// Avoids any transformation that would create a top-level re.xor
// node (e.g. AC normalisation or complement absorption), because
// mk_der_op needs to keep distributing the operation through ITE
// BDDs. Only structural simplifications that produce a non-XOR
// result are applied here.
if (a == b) {
result = re().mk_empty(a->get_sort());
return BR_DONE;
}
if (re().is_empty(a)) {
result = b;
return BR_DONE;
}
if (re().is_empty(b)) {
result = a;
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_re_xor(expr* a, expr* b, expr_ref& result) {
if (a == b) {
result = re().mk_empty(a->get_sort());
return BR_DONE;
}
if (re().is_empty(a)) {
result = b;
return BR_DONE;
}
if (re().is_empty(b)) {
result = a;
return BR_DONE;
}
if (re().is_full_seq(a)) {
result = re().mk_complement(b);
return BR_REWRITE1;
}
if (re().is_full_seq(b)) {
result = re().mk_complement(a);
return BR_REWRITE1;
}
expr* ra = nullptr, * rb = nullptr;
bool ca = re().is_complement(a, ra);
bool cb = re().is_complement(b, rb);
if (ca && cb) {
// comp(ra) XOR comp(rb) = ra XOR rb
result = re().mk_xor(ra, rb);
return BR_REWRITE1;
}
if (ca) {
// comp(ra) XOR b = comp(ra XOR b)
result = re().mk_complement(re().mk_xor(ra, b));
return BR_REWRITE2;
}
if (cb) {
// a XOR comp(rb) = comp(a XOR rb)
result = re().mk_complement(re().mk_xor(a, rb));
return BR_REWRITE2;
}
// Normalize order using expression ids (AC normalization).
if (a->get_id() > b->get_id()) {
result = re().mk_xor(b, a);
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_re_loop(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) {
rational n1, n2;
@ -5177,6 +5350,30 @@ br_status seq_rewriter::reduce_re_eq(expr* l, expr* r, expr_ref& result) {
if (re().is_empty(r)) {
return reduce_re_is_empty(l, result);
}
if (l == r) {
result = m().mk_true();
return BR_DONE;
}
/*
* Try the union-find bisimulation procedure for ground regex equality.
* Guarded against re-entry because the bisim may construct equalities
* indirectly. On l_undef the rewriter falls through to the existing
* axiomatisation path.
*/
if (!m_in_bisim && is_ground(l) && is_ground(r)) {
flet<bool> _block(m_in_bisim, true);
seq::regex_bisim bisim(*this);
switch (bisim.are_equivalent(l, r)) {
case l_true:
result = m().mk_true();
return BR_DONE;
case l_false:
result = m().mk_false();
return BR_DONE;
case l_undef:
break;
}
}
return BR_FAILED;
}

View file

@ -135,7 +135,8 @@ class seq_rewriter {
// re2automaton m_re2aut;
op_cache m_op_cache;
expr_ref_vector m_es, m_lhs, m_rhs;
bool m_coalesce_chars;
bool m_coalesce_chars;
bool m_in_bisim { false };
enum length_comparison {
shorter_c,
@ -180,6 +181,7 @@ class seq_rewriter {
expr_ref mk_der_concat(expr* a, expr* b);
expr_ref mk_der_union(expr* a, expr* b);
expr_ref mk_der_inter(expr* a, expr* b);
expr_ref mk_der_xor(expr* a, expr* b);
expr_ref mk_der_compl(expr* a);
expr_ref mk_der_cond(expr* cond, expr* ele, sort* seq_sort);
expr_ref mk_der_antimirov_union(expr* r1, expr* r2);
@ -262,6 +264,8 @@ class seq_rewriter {
br_status mk_re_complement(expr* a, expr_ref& result);
br_status mk_re_star(expr* a, expr_ref& result);
br_status mk_re_diff(expr* a, expr* b, expr_ref& result);
br_status mk_re_xor(expr* a, expr* b, expr_ref& result);
br_status mk_re_xor0(expr* a, expr* b, expr_ref& result);
br_status mk_re_plus(expr* a, expr_ref& result);
br_status mk_re_opt(expr* a, expr_ref& result);
br_status mk_re_power(func_decl* f, expr* a, expr_ref& result);
@ -381,6 +385,18 @@ public:
return result;
}
/*
* Construct r1 XOR r2 applying the structural rewrites in
* mk_re_xor (r XOR r = empty, comp/empty/full normalisation, AC
* ordering). Used by the bisimulation procedure.
*/
expr_ref mk_re_xor_simplified(expr* r1, expr* r2) {
expr_ref result(m());
if (mk_re_xor(r1, r2, result) == BR_FAILED)
result = re().mk_xor(r1, r2);
return result;
}
/**
* check if regular expression is of the form all ++ s ++ all ++ t + u ++ all, where, s, t, u are sequences
*/
@ -410,6 +426,17 @@ public:
*/
expr_ref mk_derivative(expr* r);
/*
Classical (non-antimirov) Brzozowski derivative wrt the canonical
variable v0 = (:var 0). Unlike `mk_derivative` this entry point keeps
the symbolic derivative as a single transition regex (TRegex): boolean
operators are pushed into the ITE leaves rather than lifted to the top
via _OP_RE_ANTIMIROV_UNION. Used by the regex_bisim equivalence
procedure which relies on each leaf of D(p XOR q) being a coherent
XOR pair (D_v p) XOR (D_v q).
*/
expr_ref mk_brz_derivative(expr* r);
// heuristic elimination of element from condition that comes form a derivative.
// special case optimization for conjunctions of equalities, disequalities and ranges.
void elim_condition(expr* elem, expr_ref& cond);

View file

@ -230,6 +230,7 @@ void seq_decl_plugin::init() {
m_sigs[OP_RE_UNION] = alloc(psig, m, "re.union", 1, 2, reAreA, reA);
m_sigs[OP_RE_INTERSECT] = alloc(psig, m, "re.inter", 1, 2, reAreA, reA);
m_sigs[OP_RE_DIFF] = alloc(psig, m, "re.diff", 1, 2, reAreA, reA);
m_sigs[OP_RE_XOR] = alloc(psig, m, "re.xor", 1, 2, reAreA, reA);
m_sigs[OP_RE_LOOP] = alloc(psig, m, "re.loop", 1, 1, &reA, reA);
m_sigs[OP_RE_POWER] = alloc(psig, m, "re.^", 1, 1, &reA, reA);
m_sigs[OP_RE_COMPLEMENT] = alloc(psig, m, "re.comp", 1, 1, &reA, reA);
@ -507,6 +508,7 @@ func_decl* seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, p
case OP_RE_CONCAT:
case OP_RE_INTERSECT:
case OP_RE_DIFF:
case OP_RE_XOR:
m_has_re = true;
return mk_left_assoc_fun(k, arity, domain, range, k, k);
@ -1513,6 +1515,13 @@ std::ostream& seq_util::rex::pp::print(std::ostream& out, expr* e) const {
print(out, r2);
out << ")";
}
else if (re.is_xor(e, r1, r2)) {
out << "(";
print(out, r1);
out << ")XOR(";
print(out, r2);
out << ")";
}
else if (re.m.is_ite(e, s, r1, r2)) {
out << (html_encode ? "(&#x1D422;&#x1D41F; " : "(if ");
print(out, s);
@ -1704,6 +1713,10 @@ seq_util::rex::info seq_util::rex::mk_info_rec(app* e) const {
i1 = get_info_rec(e->get_arg(0));
i2 = get_info_rec(e->get_arg(1));
return i1.diff(i2);
case OP_RE_XOR:
i1 = get_info_rec(e->get_arg(0));
i2 = get_info_rec(e->get_arg(1));
return i1.xor_(i2);
}
return unknown_info;
}
@ -1829,6 +1842,25 @@ seq_util::rex::info seq_util::rex::info::diff(seq_util::rex::info const& rhs) co
return *this;
}
seq_util::rex::info seq_util::rex::info::xor_(seq_util::rex::info const& rhs) const {
if (is_known()) {
if (rhs.is_known()) {
// Null(p XOR q) = Null(p) XOR Null(q)
lbool xor_nullable = l_undef;
if (nullable != l_undef && rhs.nullable != l_undef)
xor_nullable = (nullable == rhs.nullable) ? l_false : l_true;
return info(interpreted & rhs.interpreted,
xor_nullable,
0,
false);
}
else
return rhs;
}
else
return *this;
}
seq_util::rex::info seq_util::rex::info::orelse(seq_util::rex::info const& i) const {
if (is_known()) {
if (i.is_known()) {

View file

@ -68,6 +68,7 @@ enum seq_op_kind {
OP_RE_UNION,
OP_RE_DIFF,
OP_RE_INTERSECT,
OP_RE_XOR,
OP_RE_LOOP,
OP_RE_POWER,
OP_RE_COMPLEMENT,
@ -491,6 +492,7 @@ public:
info disj(info const& rhs) const;
info conj(info const& rhs) const;
info diff(info const& rhs) const;
info xor_(info const& rhs) const;
info orelse(info const& rhs) const;
info loop(unsigned lower, unsigned upper) const;
@ -523,6 +525,7 @@ public:
app* mk_union(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_UNION, r1, r2); }
app* mk_inter(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_INTERSECT, r1, r2); }
app* mk_diff(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_DIFF, r1, r2); }
app* mk_xor(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_XOR, r1, r2); }
app* mk_complement(expr* r) { return m.mk_app(m_fid, OP_RE_COMPLEMENT, r); }
app* mk_star(expr* r) { return m.mk_app(m_fid, OP_RE_STAR, r); }
app* mk_plus(expr* r) { return m.mk_app(m_fid, OP_RE_PLUS, r); }
@ -546,6 +549,7 @@ public:
bool is_union(expr const* n) const { return is_app_of(n, m_fid, OP_RE_UNION); }
bool is_intersection(expr const* n) const { return is_app_of(n, m_fid, OP_RE_INTERSECT); }
bool is_diff(expr const* n) const { return is_app_of(n, m_fid, OP_RE_DIFF); }
bool is_xor(expr const* n) const { return is_app_of(n, m_fid, OP_RE_XOR); }
bool is_complement(expr const* n) const { return is_app_of(n, m_fid, OP_RE_COMPLEMENT); }
bool is_star(expr const* n) const { return is_app_of(n, m_fid, OP_RE_STAR); }
bool is_plus(expr const* n) const { return is_app_of(n, m_fid, OP_RE_PLUS); }
@ -578,6 +582,7 @@ public:
MATCH_BINARY(is_union);
MATCH_BINARY(is_intersection);
MATCH_BINARY(is_diff);
MATCH_BINARY(is_xor);
MATCH_BINARY(is_range);
MATCH_UNARY(is_complement);
MATCH_UNARY(is_star);

View file

@ -511,6 +511,7 @@ namespace sls {
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_DIFF:
case OP_RE_XOR:
case OP_RE_INTERSECT:
case OP_RE_LOOP:
case OP_RE_POWER:
@ -1294,6 +1295,7 @@ namespace sls {
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_DIFF:
case OP_RE_XOR:
case OP_RE_INTERSECT:
case OP_RE_LOOP:
case OP_RE_POWER:

View file

@ -16,6 +16,9 @@ Author:
Revision History:
--*/
#include <algorithm>
#include <unordered_map>
#include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h"
#include "math/lp/int_cube.h"
@ -81,6 +84,252 @@ namespace lp {
SASSERT(lp_status::OPTIMAL == lra.get_status() || lp_status::FEASIBLE == lra.get_status());
}
// The largest cube test of Bromberger and Weidenbach:
// maximize x_e subject to Ax + a'(x_e/2) <= b, x_e >= 0, where a'_i = ||a_i||_1,
// with the 1-norm taken over the integer variables of the row.
// The solution is the center z of a largest cube contained in the polyhedron.
// If the maximal edge length is at least 1, then the rounding of z is
// an integer solution; otherwise the rounding is checked, and possibly repaired,
// against the original constraints.
lia_move int_cube::find_largest_cube() {
lia.settings().stats().m_lcube_calls++;
TRACE(cube,
for (unsigned j = 0; j < lra.number_of_vars(); ++j)
lia.display_column(tout, j);
tout << lra.constraints();
);
lra.push();
// The edge rows are ephemeral: suppress the add-term callback,
// dioph_eq's reaction to it is not undone by pop().
auto add_term_cb = lra.m_add_term_callback;
lra.m_add_term_callback = nullptr;
unsigned x_e = lra.add_var(UINT_MAX, false); // the edge length of the cube
lra.add_var_bound(x_e, lconstraint_kind::GE, mpq(0));
bool ok = add_cube_edge_rows(x_e);
lra.m_add_term_callback = add_term_cb;
if (!ok) {
lra.pop();
lra.set_status(lp_status::OPTIMAL);
return lia_move::undef;
}
lp_status st = lra.find_feasible_solution();
if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) {
TRACE(cube, tout << "cannot find a feasible solution";);
lra.pop();
lra.move_non_basic_columns_to_bounds();
// it can happen that we found an integer solution here
return !lra.r_basis_has_inf_int()? lia_move::sat: lia_move::undef;
}
impq e; // the maximal edge length
st = lra.maximize_term(x_e, e, /*fix_int_cols*/ false);
if (lia.settings().get_cancel_flag()) {
lra.pop();
return lia_move::undef;
}
if (st == lp_status::UNBOUNDED) {
// infinite lattice width: the polyhedron contains cubes of arbitrary edge length
lra.add_var_bound(x_e, lconstraint_kind::GE, mpq(1));
st = lra.find_feasible_solution();
if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) {
lra.pop();
return lia_move::undef;
}
lra.pop();
return sat_after_rounding();
}
TRACE(cube, tout << "max edge length = " << e << "\n";);
if (e >= impq(mpq(1))) {
lra.pop();
return sat_after_rounding();
}
// the largest cube is smaller than the unit cube:
// the rounded center is only a candidate
lra.pop();
return round_and_repair();
}
bool int_cube::add_cube_edge_rows(unsigned x_e) {
// snapshot the term columns: add_edge_rows_for_term appends to lra.terms()
svector<unsigned> term_columns;
for (const lar_term* t : lra.terms())
term_columns.push_back(t->j());
for (unsigned j : term_columns)
if (!add_edge_rows_for_term(j, x_e)) {
TRACE(cube, tout << "cannot add the edge rows";);
return false;
}
return true;
}
// i is the column index having the term
bool int_cube::add_edge_rows_for_term(unsigned i, unsigned x_e) {
if (!lra.column_associated_with_row(i))
return true;
const lar_term& t = lra.get_term(i);
impq delta = get_cube_delta_for_term(t);
TRACE(cube, lra.print_term_as_indices(t, tout); tout << ", delta = " << delta << "\n";);
if (is_zero(delta))
return true;
if (!is_zero(delta.y))
// the infinitesimal delta does not scale with x_e: tighten statically,
// it is sound for any edge length
return lra.tighten_term_bounds_by_delta(i, delta);
if (lra.column_has_upper_bound(i)) {
impq u = lra.get_upper_bound(i); // copy: add_term invalidates bound references
vector<std::pair<mpq, unsigned>> coeffs;
coeffs.push_back(std::make_pair(mpq(1), i));
coeffs.push_back(std::make_pair(delta.x, x_e));
unsigned s = lra.add_term(coeffs, UINT_MAX);
lra.add_var_bound(s, is_zero(u.y) ? lconstraint_kind::LE : lconstraint_kind::LT, u.x);
}
if (lra.column_has_lower_bound(i)) {
impq l = lra.get_lower_bound(i); // copy: add_term invalidates bound references
vector<std::pair<mpq, unsigned>> coeffs;
coeffs.push_back(std::make_pair(mpq(1), i));
coeffs.push_back(std::make_pair(-delta.x, x_e));
unsigned s = lra.add_term(coeffs, UINT_MAX);
lra.add_var_bound(s, is_zero(l.y) ? lconstraint_kind::GE : lconstraint_kind::GT, l.x);
}
return true;
}
lia_move int_cube::sat_after_rounding() {
lra.round_to_integer_solution();
lra.set_status(lp_status::FEASIBLE);
SASSERT(lia.settings().get_cancel_flag() || lia.is_feasible());
TRACE(cube, tout << "largest cube success";);
lia.settings().stats().m_lcube_success++;
return lia_move::sat;
}
lia_move int_cube::round_and_repair() {
lra.backup_x(); // remember the cube center
vector<flip_candidate> flips;
for (unsigned j = 0; j < lra.column_count(); ++j) {
if (!lra.column_is_int(j) || lra.column_has_term(j))
continue;
const impq& v = lra.get_column_value(j);
if (v.is_int())
continue;
flip_candidate f;
f.m_j = j;
f.m_lo = floor(v);
flips.push_back(f);
}
lra.round_to_integer_solution();
for (auto& f : flips)
f.m_at_hi = lra.get_column_value(f.m_j).x > f.m_lo;
if (repair_rounded_candidate(flips)) {
lra.set_status(lp_status::FEASIBLE);
SASSERT(lia.settings().get_cancel_flag() || lia.is_feasible());
TRACE(cube, tout << "largest cube success";);
lia.settings().stats().m_lcube_success++;
return lia_move::sat;
}
// return to the cube center: an interior point of the polyhedron
lra.restore_x();
lra.set_status(lp_status::FEASIBLE);
return lia_move::undef;
}
// Checks the rounded center against the original constraints. On failure
// searches the vertices of the lattice cell around the center greedily:
// flip a coordinate between floor and ceiling to maximally decrease the
// total bound violation, within a budget.
bool int_cube::repair_rounded_candidate(vector<flip_candidate>& flips) {
vector<bounded_row> rows;
for (const lar_term* t : lra.terms()) {
unsigned j = t->j();
if (!lra.column_associated_with_row(j))
continue;
if (!lra.column_has_upper_bound(j) && !lra.column_has_lower_bound(j))
continue;
bounded_row r;
r.m_j = j;
r.m_val = t->apply(lra.r_x());
rows.push_back(r);
}
auto row_violation = [&](unsigned ri, const impq& v) {
impq w;
unsigned j = rows[ri].m_j;
if (lra.column_has_upper_bound(j) && v > lra.get_upper_bound(j))
w += v - lra.get_upper_bound(j);
if (lra.column_has_lower_bound(j) && v < lra.get_lower_bound(j))
w += lra.get_lower_bound(j) - v;
return w;
};
impq violation;
for (unsigned ri = 0; ri < rows.size(); ++ri)
violation += row_violation(ri, rows[ri].m_val);
if (is_zero(violation))
return true; // the rounded center fits as it is
if (flips.empty())
return false;
std::unordered_map<unsigned, unsigned> flip_of_var;
for (unsigned fi = 0; fi < flips.size(); ++fi)
flip_of_var[flips[fi].m_j] = fi;
// occurrences of the flip candidates in the bounded rows
vector<vector<std::pair<unsigned, mpq>>> occs;
occs.resize(flips.size());
for (unsigned ri = 0; ri < rows.size(); ++ri) {
const lar_term& t = lra.get_term(rows[ri].m_j);
for (lar_term::ival p : t) {
auto it = flip_of_var.find(p.j());
if (it != flip_of_var.end())
occs[it->second].push_back(std::make_pair(ri, p.coeff()));
}
}
unsigned budget = std::min(2 * flips.size(), lia.settings().lcube_flips());
bool flipped = false;
while (!is_zero(violation) && budget-- > 0) {
unsigned best_fi = UINT_MAX;
impq best_gain;
for (unsigned fi = 0; fi < flips.size(); ++fi) {
if (occs[fi].empty())
continue;
mpq step = flips[fi].m_at_hi ? mpq(-1) : mpq(1);
impq gain;
for (const auto& o : occs[fi]) {
const impq& v = rows[o.first].m_val;
gain += row_violation(o.first, v + impq(step * o.second)) - row_violation(o.first, v);
}
if (gain < best_gain) {
best_gain = gain;
best_fi = fi;
}
}
if (best_fi == UINT_MAX)
return false; // no flip decreases the violation
mpq step = flips[best_fi].m_at_hi ? mpq(-1) : mpq(1);
for (const auto& o : occs[best_fi])
rows[o.first].m_val += impq(step * o.second);
flips[best_fi].m_at_hi = !flips[best_fi].m_at_hi;
violation += best_gain;
flipped = true;
TRACE(cube, tout << "flipped column " << flips[best_fi].m_j << ", violation = " << violation << "\n";);
}
if (!is_zero(violation))
return false;
// apply the repaired candidate
for (const auto& f : flips)
lra.set_column_value(f.m_j, impq(f.m_at_hi ? f.m_lo + 1 : f.m_lo));
for (const lar_term* t : lra.terms()) {
unsigned j = t->j();
if (!lra.column_associated_with_row(j))
continue;
lra.set_column_value(j, t->apply(lra.r_x()));
}
if (flipped)
lia.settings().stats().m_lcube_flip_success++;
return true;
}
impq int_cube::get_cube_delta_for_term(const lar_term& t) const {
if (t.size() == 2) {
bool seen_minus = false;

View file

@ -10,9 +10,15 @@ Abstract:
Cube finder
This routine attempts to find a feasible integer solution
by tightnening bounds and running an LRA solver on the
by tightnening bounds and running an LRA solver on the
tighter system.
find_largest_cube() implements the largest cube test of
Bromberger and Weidenbach (Fast Cube Tests for LIA Constraint
Solving, IJCAR 2016): a fresh variable x_e for the cube edge
length is introduced and maximized; the center of the largest
cube is rounded to a candidate integer solution.
Author:
Nikolaj Bjorner (nbjorner)
Lev Nachmanson (levnach)
@ -21,7 +27,10 @@ Revision History:
--*/
#pragma once
#include "util/vector.h"
#include "math/lp/lia_move.h"
#include "math/lp/numeric_pair.h"
#include "math/lp/lar_term.h"
namespace lp {
class int_solver;
@ -29,12 +38,30 @@ namespace lp {
class int_cube {
class int_solver& lia;
class lar_solver& lra;
// a fractional integer coordinate of the cube center:
// the candidate value is m_lo or m_lo + 1
struct flip_candidate {
unsigned m_j = 0;
mpq m_lo;
bool m_at_hi = false;
};
// a term column with at least one bound, tracked during the repair
struct bounded_row {
unsigned m_j = 0;
impq m_val;
};
bool tighten_term_for_cube(unsigned i);
bool tighten_terms_for_cube();
void find_feasible_solution();
impq get_cube_delta_for_term(const lar_term& t) const;
bool add_edge_rows_for_term(unsigned i, unsigned x_e);
bool add_cube_edge_rows(unsigned x_e);
lia_move sat_after_rounding();
lia_move round_and_repair();
bool repair_rounded_candidate(vector<flip_candidate>& flips);
public:
int_cube(int_solver& lia);
lia_move operator()();
lia_move find_largest_cube();
};
}

View file

@ -44,7 +44,8 @@ namespace lp {
dioph_eq m_dio;
int_gcd_test m_gcd;
unsigned m_initial_dio_calls_period;
unsigned m_lcube_period;
bool column_is_int_inf(unsigned j) const {
return lra.column_is_int(j) && (!lia.value_is_int(j));
}
@ -52,7 +53,8 @@ namespace lp {
imp(int_solver& lia): lia(lia), lra(lia.lra), lrac(lia.lrac), m_hnf_cutter(lia), m_dio(lia), m_gcd(lia) {
m_hnf_cut_period = settings().hnf_cut_period();
m_initial_dio_calls_period = settings().dio_calls_period();
}
m_lcube_period = settings().m_int_find_cube_period;
}
bool has_lower(unsigned j) const {
switch (lrac.m_column_types()[j]) {
@ -196,6 +198,25 @@ namespace lp {
return m_number_of_calls % settings().m_int_find_cube_period == 0;
}
// The largest cube test is throttled exponentially: when the polyhedron
// does not contain a large enough cube it is unlikely to contain one
// later, after more constraints are added, so each failure doubles the
// period and a success resets it.
bool should_find_lcube() {
return settings().lcube() && m_number_of_calls % m_lcube_period == 0;
}
lia_move find_lcube() {
lia_move r = int_cube(lia).find_largest_cube();
if (r == lia_move::undef) {
if (m_lcube_period < (1u << 30))
m_lcube_period *= 2;
}
else
m_lcube_period = settings().m_int_find_cube_period;
return r;
}
bool should_gomory_cut() {
bool dio_allows_gomory = !settings().dio() || settings().dio_enable_gomory_cuts() ||
m_dio.some_terms_are_ignored();
@ -246,6 +267,7 @@ namespace lp {
++m_number_of_calls;
if (r == lia_move::undef) r = patch_basic_columns();
if (r == lia_move::undef && should_find_cube()) r = int_cube(lia)();
if (r == lia_move::undef && should_find_lcube()) r = find_lcube();
if (r == lia_move::undef) lra.move_non_basic_columns_to_bounds();
if (r == lia_move::undef && should_hnf_cut()) r = hnf_cut();
if (r == lia_move::undef && should_gomory_cut()) r = gomory(lia).get_gomory_cuts(2);

View file

@ -864,7 +864,7 @@ namespace lp {
}
lp_status lar_solver::maximize_term(unsigned j,
impq& term_max) {
impq& term_max, bool fix_int_cols) {
TRACE(lar_solver, print_values(tout););
SASSERT(get_core_solver().m_r_solver.calc_current_x_is_feasible_include_non_basis());
lar_term term = get_term_to_maximize(j);
@ -879,6 +879,11 @@ namespace lp {
return lp_status::UNBOUNDED;
}
if (!fix_int_cols) {
set_status(lp_status::OPTIMAL);
return lp_status::OPTIMAL;
}
impq opt_val = term_max;
bool change = false;

View file

@ -205,7 +205,9 @@ public:
set_column_value(j, v);
}
lp_status maximize_term(unsigned j_or_term, impq& term_max);
// fix_int_cols: after maximizing try to move the integer columns to integer values;
// pass false to keep the optimal (possibly fractional) vertex intact, e.g., for the largest cube test
lp_status maximize_term(unsigned j_or_term, impq& term_max, bool fix_int_cols);
core_solver_pretty_printer<lp::mpq, lp::impq> pp(std::ostream& out) const;

View file

@ -8,6 +8,8 @@ def_module_params(module_name='lp',
('dio_cuts_enable_hnf', BOOL, True, 'enable hnf cuts together with Diophantine cuts, only relevant when dioph_eq is true'),
('dio_ignore_big_nums', BOOL, True, 'Ignore the terms with big numbers in the Diophantine handler, only relevant when dioph_eq is true'),
('dio_calls_period', UINT, 1, 'Period of calling the Diophantine handler in the final_check()'),
('dio_run_gcd', BOOL, False, 'Run the GCD heuristic if dio is on, if dio is disabled the option is not used'),
('dio_run_gcd', BOOL, False, 'Run the GCD heuristic if dio is on, if dio is disabled the option is not used'),
('lcube', BOOL, True, 'use the largest cube test for integer feasibility'),
('lcube_flips', UINT, 16, 'maximal number of coordinate flips when repairing the rounded largest cube center, only relevant when lcube is true'),
))

View file

@ -43,5 +43,7 @@ void lp::lp_settings::updt_params(params_ref const& _p) {
m_dio_ignore_big_nums = lp_p.dio_ignore_big_nums();
m_dio_calls_period = lp_p.dio_calls_period();
m_dio_run_gcd = lp_p.dio_run_gcd();
m_lcube = lp_p.lcube();
m_lcube_flips = lp_p.lcube_flips();
m_max_conflicts = p.max_conflicts();
}

View file

@ -112,6 +112,9 @@ struct statistics {
unsigned m_gcd_conflicts = 0;
unsigned m_cube_calls = 0;
unsigned m_cube_success = 0;
unsigned m_lcube_calls = 0;
unsigned m_lcube_success = 0;
unsigned m_lcube_flip_success = 0;
unsigned m_patches = 0;
unsigned m_patches_success = 0;
unsigned m_hnf_cutter_calls = 0;
@ -152,6 +155,9 @@ struct statistics {
st.update("arith-gcd-conflict", m_gcd_conflicts);
st.update("arith-cube-calls", m_cube_calls);
st.update("arith-cube-success", m_cube_success);
st.update("arith-lcube-calls", m_lcube_calls);
st.update("arith-lcube-success", m_lcube_success);
st.update("arith-lcube-flip-success", m_lcube_flip_success);
st.update("arith-patches", m_patches);
st.update("arith-patches-success", m_patches_success);
st.update("arith-hnf-calls", m_hnf_cutter_calls);
@ -258,7 +264,11 @@ private:
bool m_dio_ignore_big_nums = false;
unsigned m_dio_calls_period = 4;
bool m_dio_run_gcd = true;
bool m_lcube = true;
unsigned m_lcube_flips = 16;
public:
bool lcube() const { return m_lcube; }
unsigned lcube_flips() const { return m_lcube_flips; }
unsigned dio_calls_period() const { return m_dio_calls_period; }
unsigned & dio_calls_period() { return m_dio_calls_period; }
bool print_external_var_name() const { return m_print_external_var_name; }

View file

@ -3,6 +3,7 @@ def_module_params('fp',
export=True,
params=(('engine', SYMBOL, 'auto-config',
'Select: auto-config, datalog, bmc, spacer'),
('rlimit', UINT, 0, "deterministic resource limit (0 means no limit)"),
('datalog.default_table', SYMBOL, 'sparse',
'default table implementation: sparse, hashtable, bitvector, interval'),
('datalog.default_relation', SYMBOL, 'pentagon',

View file

@ -58,8 +58,8 @@ namespace smt2 {
if (m_at_eof)
return;
if (c == '\n') {
new_line();
next();
new_line();
return;
}
next();
@ -74,8 +74,8 @@ namespace smt2 {
if (m_at_eof)
return;
if (c == '\n') {
new_line();
next();
new_line();
continue;
}
next();

View file

@ -21,6 +21,7 @@ Author:
#include "ast/expr_abstract.h"
#include "ast/ast_util.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/seq_regex_bisim.h"
#include <ast/rewriter/expr_safe_replace.h>
namespace smt {
@ -460,6 +461,23 @@ namespace smt {
if (re().is_empty(r))
//trivially true
return;
// Try the bisimulation procedure on ground regexes first. If it
// returns a definite answer, dispatch the corresponding axiom and
// bypass the symbolic emptiness/derivative closure.
if (is_ground(r1) && is_ground(r2)) {
seq::regex_bisim bisim(seq_rw());
switch (bisim.are_equivalent(r1, r2)) {
case l_true:
STRACE(seq_regex_brief, tout << "bisim:eq ";);
return; // trivially true
case l_false:
STRACE(seq_regex_brief, tout << "bisim:neq ";);
th.add_axiom(~th.mk_eq(r1, r2, false), false_literal);
return;
case l_undef:
break;
}
}
expr_ref emp(re().mk_empty(r->get_sort()), m);
expr_ref f(m.mk_fresh_const("re.char", seq_sort), m);
expr_ref is_empty = sk().mk_is_empty(r, r, f);
@ -478,6 +496,20 @@ namespace smt {
sort* seq_sort = nullptr;
VERIFY(u().is_re(r1, seq_sort));
expr_ref r = symmetric_diff(r1, r2);
if (is_ground(r1) && is_ground(r2)) {
seq::regex_bisim bisim(seq_rw());
switch (bisim.are_equivalent(r1, r2)) {
case l_true:
STRACE(seq_regex_brief, tout << "bisim:eq ";);
th.add_axiom(th.mk_eq(r1, r2, false), false_literal);
return;
case l_false:
STRACE(seq_regex_brief, tout << "bisim:neq ";);
return; // trivially satisfied
case l_undef:
break;
}
}
expr_ref emp(re().mk_empty(r->get_sort()), m);
expr_ref n(m.mk_fresh_const("re.char", seq_sort), m);
expr_ref is_non_empty = sk().mk_is_non_empty(r, r, n);

View file

@ -4029,7 +4029,7 @@ public:
if (!lp().is_feasible() || lp().has_changed_columns())
make_feasible();
vi = get_lpvar(v);
auto st = lp().maximize_term(vi, term_max);
auto st = lp().maximize_term(vi, term_max, /*fix_int_cols*/ true);
if (has_int() && lp().has_inf_int()) {
st = lp::lp_status::FEASIBLE;
lp().restore_x();

View file

@ -19,6 +19,7 @@ Notes:
#include "tactic/tactical.h"
#include "ast/converters/generic_model_converter.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/recfun_decl_plugin.h"
@ -803,10 +804,10 @@ class elim_uncnstr_tactic : public tactic {
// x ++ y -> z, x -> z, y -> eps
app * process_seq_app(func_decl * f, unsigned num, expr * const * args) {
app *r = nullptr;
switch (f->get_decl_kind()) {
case _OP_STRING_CONCAT:
case OP_SEQ_CONCAT: {
app * r = nullptr;
expr* x, *y;
if (uncnstr(args[0]) && num == 2 &&
args[1]->get_ref_count() == 1 &&
@ -833,6 +834,27 @@ class elim_uncnstr_tactic : public tactic {
return r;
}
case OP_SEQ_IN_RE:
return nullptr;
if (uncnstr(args[0]) && m_seq_util.re.is_ground(args[1]) && m_seq_util.is_string(args[0]->get_sort())) {
zstring s1;
expr *re = args[1];
seq_rewriter rw(m());
if (l_true != rw.some_string_in_re(re, s1))
return nullptr;
zstring s2;
expr_ref not_re(m_seq_util.re.mk_complement(re), m());
if (l_true != rw.some_string_in_re(not_re, s2))
return nullptr;
mk_fresh_uncnstr_var_for(f, num, args, r);
expr_ref witness1 = expr_ref(m_seq_util.str.mk_string(s1), m());
expr_ref witness2 = expr_ref(m_seq_util.str.mk_string(s2), m());
if (m_mc)
add_def(args[0], m().mk_ite(r, witness1, witness2));
return r;
}
return nullptr;
default:
return nullptr;
}

View file

@ -79,6 +79,7 @@ add_executable(test-z3
"${CMAKE_CURRENT_BINARY_DIR}/install_tactic.cpp"
interval.cpp
karr.cpp
lcube.cpp
list.cpp
main.cpp
map.cpp

261
src/test/lcube.cpp Normal file
View file

@ -0,0 +1,261 @@
/*++
Copyright (c) 2020 Microsoft Corporation
Module Name:
lcube.cpp
Abstract:
Tests for the largest cube test of Bromberger and Weidenbach
(Fast Cube Tests for LIA Constraint Solving, IJCAR 2016),
implemented in int_cube::find_largest_cube().
This file lives directly under src/test (not src/test/lp) so that the
scripts/mk_make.py build, which only compiles the top-level test
directory, links tst_lcube().
Author:
Lev Nachmanson (levnach)
--*/
#include <initializer_list>
#include <iostream>
#include <utility>
#include "util/debug.h"
#include "util/params.h"
#include "math/lp/int_cube.h"
#include "math/lp/int_solver.h"
#include "math/lp/lar_solver.h"
#include "math/lp/numeric_pair.h"
namespace lp {
// tests for the largest cube test of Bromberger and Weidenbach
namespace lcube_test {
struct ineq {
vector<std::pair<mpq, unsigned>> m_coeffs;
lconstraint_kind m_kind;
mpq m_rs;
};
// builds for every inequality a term with the bound and solves
static void setup(lar_solver& solver, const vector<ineq>& ineqs, svector<unsigned>* term_columns = nullptr) {
unsigned term_ext = 1000;
for (const auto& in : ineqs) {
unsigned t = solver.add_term(in.m_coeffs, term_ext++);
solver.add_var_bound(t, in.m_kind, in.m_rs);
if (term_columns)
term_columns->push_back(t);
}
auto st = solver.solve();
VERIFY(st == lp_status::OPTIMAL || st == lp_status::FEASIBLE);
}
static void verify_model(const lar_solver& solver, const vector<ineq>& ineqs) {
for (const auto& in : ineqs) {
impq v;
for (const auto& p : in.m_coeffs)
v += solver.get_column_value(p.second) * p.first;
switch (in.m_kind) {
case lconstraint_kind::LE: VERIFY(v <= impq(in.m_rs)); break;
case lconstraint_kind::GE: VERIFY(v >= impq(in.m_rs)); break;
default: VERIFY(false);
}
}
}
static void verify_int_values(const lar_solver& solver, std::initializer_list<unsigned> vars) {
for (unsigned j : vars)
VERIFY(solver.get_column_value(j).is_int());
}
// The example of Bromberger and Weidenbach: 3x1 - x2 <= 0, -2x1 - x2 <= -2, -2x1 + x2 <= 1.
// The largest cube is smaller than the unit cube, the rounded center is not a solution,
// no coordinate flip repairs it (the only integer solution lies outside the lattice cell
// of the center): expect undef and an intact solver state.
static void test_paper_example_undef() {
std::cout << "lcube: paper example, expecting undef\n";
lar_solver solver;
unsigned x1 = solver.add_named_var(0, true, "x1");
unsigned x2 = solver.add_named_var(1, true, "x2");
vector<ineq> ineqs;
ineqs.push_back(ineq{{{mpq(3), x1}, {mpq(-1), x2}}, lconstraint_kind::LE, mpq(0)});
ineqs.push_back(ineq{{{mpq(-2), x1}, {mpq(-1), x2}}, lconstraint_kind::LE, mpq(-2)});
ineqs.push_back(ineq{{{mpq(-2), x1}, {mpq(1), x2}}, lconstraint_kind::LE, mpq(1)});
setup(solver, ineqs);
int_solver i_s(solver);
solver.set_int_solver(&i_s);
lia_move m = int_cube(i_s).find_largest_cube();
std::cout << "lcube returned " << lia_move_to_string(m) << "\n";
VERIFY(m == lia_move::undef);
VERIFY(solver.ax_is_correct());
}
// 3x1 - x2 <= 0, -2x1 - x2 <= -1, -2x1 + x2 <= 1: the largest cube has
// edge 4/17 with the center (3/17, 1) that rounds to the solution (0, 1),
// while the unit cube test fails: the largest cube test is stronger here.
static void test_beats_unit_cube() {
std::cout << "lcube: beating the unit cube test\n";
lar_solver solver;
unsigned x1 = solver.add_named_var(0, true, "x1");
unsigned x2 = solver.add_named_var(1, true, "x2");
vector<ineq> ineqs;
ineqs.push_back(ineq{{{mpq(3), x1}, {mpq(-1), x2}}, lconstraint_kind::LE, mpq(0)});
ineqs.push_back(ineq{{{mpq(-2), x1}, {mpq(-1), x2}}, lconstraint_kind::LE, mpq(-1)});
ineqs.push_back(ineq{{{mpq(-2), x1}, {mpq(1), x2}}, lconstraint_kind::LE, mpq(1)});
svector<unsigned> tcols;
setup(solver, ineqs, &tcols);
// move the solution to a fractional feasible point: the cube tests only
// run when the current solution has fractional integer variables
solver.set_column_value_test(x1, impq(mpq(1, 4)));
solver.set_column_value_test(x2, impq(mpq(5, 4)));
solver.set_column_value_test(tcols[0], impq(mpq(-1, 2)));
solver.set_column_value_test(tcols[1], impq(mpq(-7, 4)));
solver.set_column_value_test(tcols[2], impq(mpq(3, 4)));
int_solver i_s(solver);
solver.set_int_solver(&i_s);
lia_move m = int_cube(i_s)();
std::cout << "unit cube returned " << lia_move_to_string(m) << "\n";
VERIFY(m == lia_move::undef);
m = int_cube(i_s).find_largest_cube();
std::cout << "lcube returned " << lia_move_to_string(m) << "\n";
VERIFY(m == lia_move::sat);
verify_int_values(solver, {x1, x2});
verify_model(solver, ineqs);
}
// 9/10 <= x + y + r <= 11/10, -11/10 <= x - y + r <= 1/10, 0 <= r <= 1/10,
// x, y integer, r real. The real variable keeps the terms and their bounds
// non-integer. A fractional center, e.g. (1/2, 1/2), rounds to an infeasible
// point that is repaired by flipping one coordinate: expect sat.
static void test_flip_repair() {
std::cout << "lcube: rounding repair\n";
lar_solver solver;
unsigned x = solver.add_named_var(0, true, "x");
unsigned y = solver.add_named_var(1, true, "y");
unsigned r = solver.add_named_var(2, false, "r");
solver.add_var_bound(r, lconstraint_kind::GE, mpq(0));
solver.add_var_bound(r, lconstraint_kind::LE, mpq(1, 10));
vector<ineq> ineqs;
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(1), y}, {mpq(1), r}}, lconstraint_kind::GE, mpq(9, 10)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(1), y}, {mpq(1), r}}, lconstraint_kind::LE, mpq(11, 10)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(-1), y}, {mpq(1), r}}, lconstraint_kind::GE, mpq(-11, 10)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(-1), y}, {mpq(1), r}}, lconstraint_kind::LE, mpq(1, 10)});
setup(solver, ineqs);
int_solver i_s(solver);
solver.set_int_solver(&i_s);
lia_move m = int_cube(i_s).find_largest_cube();
std::cout << "lcube returned " << lia_move_to_string(m)
<< ", flip successes: " << solver.settings().stats().m_lcube_flip_success << "\n";
VERIFY(m == lia_move::sat);
verify_int_values(solver, {x, y});
verify_model(solver, ineqs);
}
// 3x + 5y >= 7 alone has infinite lattice width: the edge length is
// unbounded and any cube center of edge >= 1 rounds to a solution.
static void test_infinite_lattice_width() {
std::cout << "lcube: infinite lattice width\n";
lar_solver solver;
unsigned x = solver.add_named_var(0, true, "x");
unsigned y = solver.add_named_var(1, true, "y");
vector<ineq> ineqs;
ineqs.push_back(ineq{{{mpq(3), x}, {mpq(5), y}}, lconstraint_kind::GE, mpq(7)});
setup(solver, ineqs);
int_solver i_s(solver);
solver.set_int_solver(&i_s);
lia_move m = int_cube(i_s).find_largest_cube();
std::cout << "lcube returned " << lia_move_to_string(m) << "\n";
VERIFY(m == lia_move::sat);
verify_int_values(solver, {x, y});
verify_model(solver, ineqs);
}
// 0 <= x + 2y + r <= 8, 0 <= x - 2y + r <= 8: the maximal edge length is
// 8/3 >= 1, so the rounded center is guaranteed to be a solution.
static void test_edge_at_least_one() {
std::cout << "lcube: edge length at least 1\n";
lar_solver solver;
unsigned x = solver.add_named_var(0, true, "x");
unsigned y = solver.add_named_var(1, true, "y");
unsigned r = solver.add_named_var(2, false, "r");
solver.add_var_bound(r, lconstraint_kind::GE, mpq(0));
solver.add_var_bound(r, lconstraint_kind::LE, mpq(1, 10));
vector<ineq> ineqs;
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(2), y}, {mpq(1), r}}, lconstraint_kind::GE, mpq(0)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(2), y}, {mpq(1), r}}, lconstraint_kind::LE, mpq(8)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(-2), y}, {mpq(1), r}}, lconstraint_kind::GE, mpq(0)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(-2), y}, {mpq(1), r}}, lconstraint_kind::LE, mpq(8)});
setup(solver, ineqs);
int_solver i_s(solver);
solver.set_int_solver(&i_s);
lia_move m = int_cube(i_s).find_largest_cube();
std::cout << "lcube returned " << lia_move_to_string(m) << "\n";
VERIFY(m == lia_move::sat);
verify_int_values(solver, {x, y});
verify_model(solver, ineqs);
}
// runs the flip-repair instance through int_solver::check() with the
// lp.lcube parameter set and the cube period lowered to 1: verifies the
// dispatch and the parameter plumbing
static void test_dispatch() {
std::cout << "lcube: dispatch through int_solver::check\n";
lar_solver solver;
params_ref p;
p.set_bool("lcube", true);
solver.settings().updt_params(p);
VERIFY(solver.settings().lcube());
solver.settings().m_int_find_cube_period = 1;
unsigned x = solver.add_named_var(0, true, "x");
unsigned y = solver.add_named_var(1, true, "y");
unsigned r = solver.add_named_var(2, false, "r");
solver.add_var_bound(r, lconstraint_kind::GE, mpq(0));
solver.add_var_bound(r, lconstraint_kind::LE, mpq(1, 10));
vector<ineq> ineqs;
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(1), y}, {mpq(1), r}}, lconstraint_kind::GE, mpq(9, 10)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(1), y}, {mpq(1), r}}, lconstraint_kind::LE, mpq(11, 10)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(-1), y}, {mpq(1), r}}, lconstraint_kind::GE, mpq(-11, 10)});
ineqs.push_back(ineq{{{mpq(1), x}, {mpq(-1), y}, {mpq(1), r}}, lconstraint_kind::LE, mpq(1, 10)});
svector<unsigned> tcols;
setup(solver, ineqs, &tcols);
// a fractional feasible point, so that check() does not return sat right away
solver.set_column_value_test(x, impq(mpq(1, 2)));
solver.set_column_value_test(y, impq(mpq(1, 2)));
solver.set_column_value_test(r, impq(mpq(1, 10)));
solver.set_column_value_test(tcols[0], impq(mpq(11, 10)));
solver.set_column_value_test(tcols[1], impq(mpq(11, 10)));
solver.set_column_value_test(tcols[2], impq(mpq(1, 10)));
solver.set_column_value_test(tcols[3], impq(mpq(1, 10)));
int_solver i_s(solver);
solver.set_int_solver(&i_s);
explanation ex;
lia_move m = i_s.check(&ex);
std::cout << "check returned " << lia_move_to_string(m)
<< ", lcube calls: " << solver.settings().stats().m_lcube_calls << "\n";
VERIFY(m == lia_move::sat);
VERIFY(solver.settings().stats().m_lcube_calls >= 1);
verify_int_values(solver, {x, y});
verify_model(solver, ineqs);
}
static void run() {
test_paper_example_undef();
test_beats_unit_cube();
test_flip_repair();
test_infinite_lattice_width();
test_edge_at_least_one();
test_dispatch();
std::cout << "lcube tests passed\n";
}
} // namespace lcube_test
} // namespace lp
void tst_lcube() {
lp::lcube_test::run();
}

View file

@ -1645,7 +1645,7 @@ void test_maximize_term() {
lia_move lm = i_solver.check(&ex);
VERIFY(lm == lia_move::sat);
impq term_max;
lp_status st = solver.maximize_term(term_2x_pl_2y, term_max);
lp_status st = solver.maximize_term(term_2x_pl_2y, term_max, /*fix_int_cols*/ true);
std::cout << "status = " << lp_status_to_string(st) << std::endl;
std::cout << "term_max = " << term_max << std::endl;

View file

@ -193,7 +193,8 @@
X(ho_matcher) \
X(finite_set) \
X(finite_set_rewriter) \
X(fpa)
X(fpa) \
X(lcube)
#define FOR_EACH_TEST(X, X_ARGV) \
FOR_EACH_ALL_TEST(X, X_ARGV) \

View file

@ -1904,8 +1904,11 @@ std::string mpz_manager<SYNCH>::to_string(mpz const & a) const {
template<bool SYNCH>
unsigned mpz_manager<SYNCH>::hash(mpz const & a) {
if (is_small(a))
return ::abs(a.m_val);
if (is_small(a)) {
// compute abs in unsigned arithmetic: ::abs(INT_MIN) is undefined
unsigned u = static_cast<unsigned>(a.m_val);
return a.m_val < 0 ? 0u - u : u;
}
#ifndef _MP_GMP
unsigned sz = size(a);
if (sz == 1)

View file

@ -62,6 +62,10 @@ public:
struct key_data {
Key * m_key = nullptr;
Value m_value;
key_data() = default;
key_data(Key* k): m_key(k) {}
key_data(Key* k, Value const& v): m_key(k), m_value(v) {}
key_data(Key* k, Value&& v): m_key(k), m_value(std::move(v)) {}
Value const & get_value() const { return m_value; }
Key & get_key () const { return *m_key; }
unsigned hash() const { return m_key->hash(); }
@ -239,5 +243,3 @@ void erase_dealloc_value(obj_map<Key, Value*> & m, Key * k) {
dealloc(v);
}
}