Long Horizon Shadow Signal #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Long Horizon Shadow Signal | |
| on: | |
| schedule: | |
| # Monthly shadow research run. This remains shadow-only and does not place | |
| # trades. | |
| - cron: "30 2 1 * *" | |
| workflow_dispatch: | |
| inputs: | |
| provider: | |
| description: "Bridge provider" | |
| required: false | |
| type: choice | |
| default: "auto" | |
| options: | |
| - auto | |
| - api | |
| - anthropic | |
| - codex | |
| - openai | |
| source_ref: | |
| description: "Ref to pass to CodexAuditBridge" | |
| required: false | |
| default: "main" | |
| permissions: | |
| contents: read | |
| issues: write | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref_name }} | |
| cancel-in-progress: false | |
| jobs: | |
| dispatch-shadow-signal: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| BRIDGE_REPOSITORY: ${{ vars.CODEX_AUDIT_BRIDGE_REPOSITORY || 'QuantStrategyLab/CodexAuditBridge' }} | |
| BRIDGE_REF: ${{ vars.CODEX_AUDIT_BRIDGE_REF || 'main' }} | |
| BRIDGE_TASK: long_horizon_signal_shadow | |
| BRIDGE_PROVIDER: ${{ github.event.inputs.provider || 'auto' }} | |
| SOURCE_REF: ${{ github.event.inputs.source_ref || 'main' }} | |
| SHADOW_SIGNAL_LABEL: long-horizon-shadow | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Validate existing latest signal if present | |
| run: python scripts/validate_latest_signal.py --allow-missing | |
| - name: Build point-in-time context bundle | |
| run: | | |
| python scripts/build_context_bundle.py \ | |
| --output data/output/context_bundle/latest_context_bundle.json \ | |
| --allow-download-errors | |
| - name: Create or update shadow signal issue | |
| id: shadow_issue | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| python scripts/post_shadow_signal_request.py \ | |
| --repo "${GITHUB_REPOSITORY}" \ | |
| --source-ref "${SOURCE_REF}" \ | |
| --provider "${BRIDGE_PROVIDER}" \ | |
| --bridge-repository "${BRIDGE_REPOSITORY}" \ | |
| --context-file data/output/context_bundle/latest_context_bundle.json \ | |
| --label "${SHADOW_SIGNAL_LABEL}" | |
| - name: Append shadow signal job summary | |
| run: | | |
| { | |
| echo "## Long-horizon shadow signal" | |
| echo "" | |
| echo "- Issue: [${{ steps.shadow_issue.outputs.issue_title }}](${{ steps.shadow_issue.outputs.issue_url }})" | |
| echo "- Issue action: \`${{ steps.shadow_issue.outputs.issue_action }}\`" | |
| echo "- Source ref: \`${SOURCE_REF}\`" | |
| echo "- Provider: \`${BRIDGE_PROVIDER}\`" | |
| echo "- Bridge: \`${BRIDGE_REPOSITORY}\`" | |
| echo "- Mode: \`shadow\`" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Detect GitHub App Credentials | |
| id: app_credentials | |
| env: | |
| APP_ID: ${{ vars.CROSS_REPO_GITHUB_APP_ID }} | |
| APP_PRIVATE_KEY: ${{ secrets.CROSS_REPO_GITHUB_APP_PRIVATE_KEY }} | |
| run: | | |
| set -euo pipefail | |
| if [ -n "${APP_ID:-}" ] && [ -n "${APP_PRIVATE_KEY:-}" ]; then | |
| echo "available=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "available=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create GitHub App Token For Bridge Repository | |
| id: bridge_app_token | |
| if: steps.app_credentials.outputs.available == 'true' | |
| continue-on-error: true | |
| uses: actions/create-github-app-token@v3 | |
| with: | |
| app-id: ${{ vars.CROSS_REPO_GITHUB_APP_ID }} | |
| private-key: ${{ secrets.CROSS_REPO_GITHUB_APP_PRIVATE_KEY }} | |
| owner: ${{ github.repository_owner }} | |
| repositories: | | |
| CodexAuditBridge | |
| permission-actions: write | |
| - name: Create shadow signal issue and dispatch bridge | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| APP_TOKEN: ${{ steps.bridge_app_token.outputs.token }} | |
| CODEX_AUDIT_DISPATCH_TOKEN: ${{ secrets.CODEX_AUDIT_DISPATCH_TOKEN }} | |
| ISSUE_NUMBER: ${{ steps.shadow_issue.outputs.issue_number }} | |
| run: | | |
| python - <<'PY' | |
| import json | |
| import os | |
| import urllib.request | |
| import urllib.error | |
| repo = os.environ["GITHUB_REPOSITORY"] | |
| bridge_repo = os.environ["BRIDGE_REPOSITORY"] | |
| token = os.environ["GH_TOKEN"] | |
| dispatch_token = os.environ.get("APP_TOKEN") or os.environ.get("CODEX_AUDIT_DISPATCH_TOKEN") | |
| if not dispatch_token: | |
| raise SystemExit("Bridge dispatch requires a GitHub App token or CODEX_AUDIT_DISPATCH_TOKEN") | |
| def request(method, url, payload=None, auth_token=token): | |
| data = json.dumps(payload).encode("utf-8") if payload is not None else None | |
| req = urllib.request.Request( | |
| url, | |
| data=data, | |
| method=method, | |
| headers={ | |
| "Authorization": f"Bearer {auth_token}", | |
| "Accept": "application/vnd.github+json", | |
| "Content-Type": "application/json", | |
| }, | |
| ) | |
| with urllib.request.urlopen(req, timeout=60) as response: | |
| body = response.read().decode("utf-8") | |
| return response.status, json.loads(body) if body else None | |
| dispatch_payload = { | |
| "ref": os.environ["BRIDGE_REF"], | |
| "inputs": { | |
| "source_repo": repo, | |
| "issue_number": os.environ["ISSUE_NUMBER"], | |
| "source_ref": os.environ["SOURCE_REF"], | |
| "mode": "review_and_fix", | |
| "provider": os.environ["BRIDGE_PROVIDER"], | |
| "task": os.environ["BRIDGE_TASK"], | |
| "auto_merge": "false", | |
| }, | |
| } | |
| status, _ = request( | |
| "POST", | |
| f"https://api.github.com/repos/{bridge_repo}/actions/workflows/codex_audit.yml/dispatches", | |
| dispatch_payload, | |
| auth_token=dispatch_token, | |
| ) | |
| if status not in (201, 204): | |
| raise RuntimeError(f"unexpected dispatch status: {status}") | |
| print(f"Dispatched {bridge_repo} for issue #{os.environ['ISSUE_NUMBER']}") | |
| PY | |
| - name: Upload context bundle | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: long-horizon-context-bundle | |
| path: data/output/context_bundle/latest_context_bundle.json |