From 0039515fac4fe6f4fc599dda088c747c03ffcb92 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:19:25 +0800 Subject: [PATCH] feat: add no-order IBKR reconciliation collector Co-Authored-By: Codex --- .../collect-reconciliation-evidence.yml | 90 +++++++++++++++++++ ...econciliation_baseline_enrollment.zh-CN.md | 11 +++ 2 files changed, 101 insertions(+) create mode 100644 .github/workflows/collect-reconciliation-evidence.yml diff --git a/.github/workflows/collect-reconciliation-evidence.yml b/.github/workflows/collect-reconciliation-evidence.yml new file mode 100644 index 0000000..c08ed9c --- /dev/null +++ b/.github/workflows/collect-reconciliation-evidence.yml @@ -0,0 +1,90 @@ +name: Collect IBKR Reconciliation Evidence + +on: + workflow_dispatch: + inputs: + target: + description: "Frozen live target to read; this workflow has no order path." + required: true + default: all + type: choice + options: + - all + - soxl_soxx_trend_income + - tqqq_growth_income + - global_etf_rotation + - russell_top50_leader_rotation + +permissions: + contents: read + id-token: write + +env: + GCP_PROJECT_ID: interactivebrokersquant + GCP_REGION: us-central1 + GCP_WORKLOAD_IDENTITY_PROVIDER: projects/303168642265/locations/global/workloadIdentityPools/github-actions/providers/github-main + GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT: ibkr-platform-deploy@interactivebrokersquant.iam.gserviceaccount.com + +concurrency: + group: ibkr-reconciliation-evidence-${{ inputs.target }} + cancel-in-progress: false + +jobs: + collect: + name: Read ${{ matrix.profile }} baseline evidence + if: ${{ inputs.target == 'all' || inputs.target == matrix.profile }} + runs-on: ubuntu-latest + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + include: + - profile: soxl_soxx_trend_income + service: interactive-brokers-quant-live-u15998061-service + - profile: tqqq_growth_income + service: interactive-brokers-quant-live-u16608560-service + - profile: global_etf_rotation + service: interactive-brokers-quant-live-u18308207-service + - profile: russell_top50_leader_rotation + service: interactive-brokers-quant-live-u18336562-service + steps: + - name: Authenticate to Google Cloud + uses: google-github-actions/auth@v3 + with: + workload_identity_provider: ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ env.GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT }} + + - name: Set up gcloud + uses: google-github-actions/setup-gcloud@v3 + + - name: Collect no-order reconciliation candidate + env: + SERVICE: ${{ matrix.service }} + PROFILE: ${{ matrix.profile }} + run: | + set -euo pipefail + service_url="$(gcloud run services describe "$SERVICE" --project "$GCP_PROJECT_ID" --region "$GCP_REGION" --format='value(status.url)')" + test -n "$service_url" + identity_token="$(gcloud auth print-identity-token --audiences="$service_url")" + mkdir -p reports + curl --fail --silent --show-error --max-time 90 \ + --request POST \ + --header "Authorization: Bearer ${identity_token}" \ + --output "reports/${PROFILE}.json" \ + "${service_url}/reconcile" + jq -e --arg profile "$PROFILE" ' + .schema_version == "ibkr_reconciliation_candidate.v1" + and .evidence.platform_id == "ibkr" + and .evidence.strategy_profile == $profile + and (.recovery_blockers | type == "array") + ' "reports/${PROFILE}.json" >/dev/null + jq -r '[.permits_active_lkg, .expected_digests_configured, (.recovery_blockers | length)] | @tsv' \ + "reports/${PROFILE}.json" | awk -F '\t' '{print "candidate_collected permits_active_lkg=" $1 ", expected_digests_configured=" $2 ", blockers=" $3}' + + - name: Retain redacted candidate + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: ibkr-reconciliation-${{ matrix.profile }}-${{ github.run_id }} + path: reports/${{ matrix.profile }}.json + if-no-files-found: error + retention-days: 30 diff --git a/docs/ibkr_reconciliation_baseline_enrollment.zh-CN.md b/docs/ibkr_reconciliation_baseline_enrollment.zh-CN.md index c13dd4e..6f67371 100644 --- a/docs/ibkr_reconciliation_baseline_enrollment.zh-CN.md +++ b/docs/ibkr_reconciliation_baseline_enrollment.zh-CN.md @@ -87,3 +87,14 @@ URI、部署 Cloud Run、连接券商或提交订单。实际启用仍需要单 令牌被试图发送到普通管理站路径。每一种情况都必须抛出拒绝或返回没有 `transition_plan` 的结果;测试同时断言 `state_write_attempted=false`。这让后续接入 最小权限 CAS 时能持续证明“异常只能保持冻结,不能意外恢复实盘”。 + +## 收集两份候选收据 + +`Collect IBKR Reconciliation Evidence` 是显式手动工作流。它仅以部署身份调用每个 +冻结 Cloud Run 服务的 `POST /reconcile`,并在 30 天内保留脱敏 +`ibkr_reconciliation_candidate.v1` artifact。它不调用 `/run`、不修改 GitHub 变量、 +不发布状态账本,也不发送任何订单。 + +同一目标至少应在相隔一分钟的两次手动运行中得到候选,才能交给 +`build_reconciliation_baseline_candidate.py`。工作流的成功只说明读取和收据格式正常; +候选仍可能因为未配置预期摘要或账本差异而正确保持阻断。