From 62b1b55a2ef6e46f408303386068d7bd42edd91a Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:44:18 +0800 Subject: [PATCH 1/5] fix: repair monthly report workflow chain --- .github/workflows/ai_review.yml | 22 +++++++------ .github/workflows/monthly_report.yml | 20 ++++++++++-- tests/test_monthly_report_workflow_config.py | 34 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 tests/test_monthly_report_workflow_config.py diff --git a/.github/workflows/ai_review.yml b/.github/workflows/ai_review.yml index 6fcb661..3a9ca89 100644 --- a/.github/workflows/ai_review.yml +++ b/.github/workflows/ai_review.yml @@ -3,13 +3,19 @@ name: AI Monthly Review "on": issues: types: [opened] + workflow_dispatch: + inputs: + issue_number: + description: "Issue number to review" + required: true jobs: ai-review: - if: contains(github.event.issue.labels.*.name, 'monthly-review') + if: contains(github.event.issue.labels.*.name, 'monthly-review') || inputs.issue_number != '' runs-on: ubuntu-latest permissions: contents: read + id-token: write issues: write steps: @@ -20,16 +26,14 @@ jobs: uses: anthropics/claude-code-action@v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - model: claude-sonnet-4-6-20250514 + github_token: ${{ secrets.GITHUB_TOKEN }} use_bedrock: false use_vertex: false - allowed_tools: | - Read - Glob - Grep - Bash(git log:*) - Bash(git diff:*) - custom_instructions: | + prompt: | + Review GitHub issue #${{ inputs.issue_number || github.event.issue.number }} in this repository. + The issue body contains the full monthly execution review data. + Post your final bilingual review as a comment on that issue. + You are reviewing the monthly execution report for BinancePlatform, an automated crypto quantitative trading system for Binance Spot. It runs hourly, executing a BTC DCA core strategy plus altcoin trend diff --git a/.github/workflows/monthly_report.yml b/.github/workflows/monthly_report.yml index e2063a9..639abc6 100644 --- a/.github/workflows/monthly_report.yml +++ b/.github/workflows/monthly_report.yml @@ -13,6 +13,7 @@ jobs: report: runs-on: ubuntu-latest permissions: + actions: write contents: read issues: write @@ -56,15 +57,30 @@ jobs: run: | python scripts/run_monthly_report_bundle.py \ --month "${{ steps.month.outputs.month }}" \ + --hourly-dir "hourly/${{ steps.month.outputs.month }}" \ --output-dir data/output - name: Create monthly review issue if: steps.fetch.outputs.has_data == 'true' + id: issue run: | + set -euo pipefail MONTH="${{ steps.month.outputs.month }}" - gh issue create \ + gh label create monthly-review --description "Automated monthly execution AI review" --color "0E8A16" 2>/dev/null || true + ISSUE_URL=$(gh issue create \ --title "Monthly Execution Review: ${MONTH}" \ --label "monthly-review" \ - --body-file data/output/ai_review_input.md + --body-file data/output/ai_review_input.md) + echo "issue_url=${ISSUE_URL}" >> "$GITHUB_OUTPUT" + echo "issue_number=${ISSUE_URL##*/}" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Trigger AI monthly review + if: steps.fetch.outputs.has_data == 'true' + run: | + gh workflow run ai_review.yml \ + --ref "${GITHUB_REF_NAME}" \ + -f issue_number="${{ steps.issue.outputs.issue_number }}" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/tests/test_monthly_report_workflow_config.py b/tests/test_monthly_report_workflow_config.py new file mode 100644 index 0000000..0e0decd --- /dev/null +++ b/tests/test_monthly_report_workflow_config.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +import unittest +from pathlib import Path + + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +MONTHLY_REPORT_WORKFLOW = PROJECT_ROOT / ".github" / "workflows" / "monthly_report.yml" +AI_REVIEW_WORKFLOW = PROJECT_ROOT / ".github" / "workflows" / "ai_review.yml" + + +class MonthlyReportWorkflowConfigTests(unittest.TestCase): + def test_monthly_report_workflow_passes_hourly_dir_and_dispatches_ai_review(self) -> None: + workflow = MONTHLY_REPORT_WORKFLOW.read_text(encoding="utf-8") + + self.assertIn("actions: write", workflow) + self.assertIn('--hourly-dir "hourly/${{ steps.month.outputs.month }}"', workflow) + self.assertIn("gh label create monthly-review", workflow) + self.assertIn("gh workflow run ai_review.yml", workflow) + self.assertIn('issue_number="${{ steps.issue.outputs.issue_number }}"', workflow) + + def test_ai_review_workflow_supports_manual_dispatch(self) -> None: + workflow = AI_REVIEW_WORKFLOW.read_text(encoding="utf-8") + + self.assertIn("workflow_dispatch:", workflow) + self.assertIn("issue_number:", workflow) + self.assertIn("id-token: write", workflow) + self.assertIn("github_token: ${{ secrets.GITHUB_TOKEN }}", workflow) + self.assertIn("${{ inputs.issue_number || github.event.issue.number }}", workflow) + self.assertIn("Post your final bilingual review as a comment on that issue.", workflow) + + +if __name__ == "__main__": + unittest.main() From fdea6584a385f74b0ddb8d19c2de2c1cb2676c61 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:59:57 +0800 Subject: [PATCH 2/5] fix: post monthly AI review comment --- .github/workflows/ai_review.yml | 22 ++- scripts/post_monthly_ai_review_comment.py | 138 +++++++++++++++++++ tests/test_monthly_report_workflow_config.py | 7 +- tests/test_post_monthly_ai_review_comment.py | 50 +++++++ 4 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 scripts/post_monthly_ai_review_comment.py create mode 100644 tests/test_post_monthly_ai_review_comment.py diff --git a/.github/workflows/ai_review.yml b/.github/workflows/ai_review.yml index 3a9ca89..2a35ffa 100644 --- a/.github/workflows/ai_review.yml +++ b/.github/workflows/ai_review.yml @@ -23,16 +23,21 @@ jobs: uses: actions/checkout@v5 - name: Run Claude Code Review + id: claude_review uses: anthropics/claude-code-action@v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} github_token: ${{ secrets.GITHUB_TOKEN }} use_bedrock: false use_vertex: false + claude_args: | + --allowedTools "mcp__github__get_issue,mcp__github__get_issue_comments" prompt: | - Review GitHub issue #${{ inputs.issue_number || github.event.issue.number }} in this repository. - The issue body contains the full monthly execution review data. - Post your final bilingual review as a comment on that issue. + Use mcp__github__get_issue to read GitHub issue #${{ inputs.issue_number || github.event.issue.number }}. + Use mcp__github__get_issue_comments only if you need extra context from existing comments. + Do not use Bash or ask for additional approval. + Return only the final bilingual review in markdown. + The workflow will publish your final review as the issue comment. You are reviewing the monthly execution report for BinancePlatform, an automated crypto quantitative trading system for Binance Spot. @@ -119,3 +124,14 @@ jobs: ... ### 操作员待办事项 ... + + - name: Post AI review issue comment + if: steps.claude_review.outcome == 'success' + run: | + python3 scripts/post_monthly_ai_review_comment.py \ + --repo "${GITHUB_REPOSITORY}" \ + --issue-number "${{ inputs.issue_number || github.event.issue.number }}" \ + --execution-file "${{ steps.claude_review.outputs.execution_file }}" \ + --run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/scripts/post_monthly_ai_review_comment.py b/scripts/post_monthly_ai_review_comment.py new file mode 100644 index 0000000..5983c65 --- /dev/null +++ b/scripts/post_monthly_ai_review_comment.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +import argparse +import json +import os +import sys +import urllib.error +import urllib.request +from pathlib import Path +from typing import Any + + +COMMENT_MARKER = "" +DEFAULT_API_URL = "https://api.github.com" + + +def extract_latest_assistant_text(execution_log: list[dict[str, Any]]) -> str: + for turn in reversed(execution_log): + if turn.get("type") != "assistant": + continue + + content_items = turn.get("message", {}).get("content", []) + text_parts = [ + item.get("text", "").strip() + for item in content_items + if item.get("type") == "text" and item.get("text", "").strip() + ] + if text_parts: + return "\n\n".join(text_parts).strip() + + raise ValueError("No assistant review text found in Claude execution log") + + +def build_comment_body(review_text: str, run_url: str | None = None) -> str: + body = f"{COMMENT_MARKER}\n## Claude Monthly Review\n\n{review_text.strip()}" + if run_url: + body += f"\n\n---\n_Generated by AI Monthly Review workflow: {run_url}_" + return body + + +def github_request( + method: str, + url: str, + token: str, + payload: dict[str, Any] | None = None, +) -> Any: + data = None + headers = { + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "binanceplatform-monthly-ai-review", + } + if payload is not None: + data = json.dumps(payload).encode("utf-8") + headers["Content-Type"] = "application/json" + + request = urllib.request.Request(url, data=data, headers=headers, method=method) + with urllib.request.urlopen(request) as response: + charset = response.headers.get_content_charset("utf-8") + raw = response.read().decode(charset) + return json.loads(raw) if raw else None + + +def upsert_issue_comment( + *, + api_url: str, + repo: str, + issue_number: int, + token: str, + body: str, +) -> None: + comments_url = f"{api_url}/repos/{repo}/issues/{issue_number}/comments" + comments = github_request("GET", comments_url, token) + existing = next( + ( + comment + for comment in comments + if COMMENT_MARKER in comment.get("body", "") + ), + None, + ) + + if existing: + github_request( + "PATCH", + f"{api_url}/repos/{repo}/issues/comments/{existing['id']}", + token, + {"body": body}, + ) + print(f"Updated issue comment {existing['id']}") + return + + github_request("POST", comments_url, token, {"body": body}) + print(f"Created issue comment for issue #{issue_number}") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Extract Claude review text from execution output and upsert an issue comment.", + ) + parser.add_argument("--repo", required=True, help="owner/repo") + parser.add_argument("--issue-number", required=True, type=int) + parser.add_argument("--execution-file", required=True, type=Path) + parser.add_argument("--api-url", default=DEFAULT_API_URL) + parser.add_argument("--run-url", default="") + return parser.parse_args() + + +def main() -> int: + args = parse_args() + token = os.environ.get("GITHUB_TOKEN") + if not token: + print("GITHUB_TOKEN is required", file=sys.stderr) + return 1 + + execution_log = json.loads(args.execution_file.read_text(encoding="utf-8")) + review_text = extract_latest_assistant_text(execution_log) + body = build_comment_body(review_text, args.run_url or None) + + try: + upsert_issue_comment( + api_url=args.api_url.rstrip("/"), + repo=args.repo, + issue_number=args.issue_number, + token=token, + body=body, + ) + except urllib.error.HTTPError as exc: + detail = exc.read().decode("utf-8", errors="replace") + print(f"GitHub API request failed: {exc.code} {detail}", file=sys.stderr) + return 1 + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_monthly_report_workflow_config.py b/tests/test_monthly_report_workflow_config.py index 0e0decd..6c38a95 100644 --- a/tests/test_monthly_report_workflow_config.py +++ b/tests/test_monthly_report_workflow_config.py @@ -25,9 +25,14 @@ def test_ai_review_workflow_supports_manual_dispatch(self) -> None: self.assertIn("workflow_dispatch:", workflow) self.assertIn("issue_number:", workflow) self.assertIn("id-token: write", workflow) + self.assertIn("id: claude_review", workflow) self.assertIn("github_token: ${{ secrets.GITHUB_TOKEN }}", workflow) + self.assertIn('--allowedTools "mcp__github__get_issue,mcp__github__get_issue_comments"', workflow) self.assertIn("${{ inputs.issue_number || github.event.issue.number }}", workflow) - self.assertIn("Post your final bilingual review as a comment on that issue.", workflow) + self.assertIn("Do not use Bash or ask for additional approval.", workflow) + self.assertIn("The workflow will publish your final review as the issue comment.", workflow) + self.assertIn("post_monthly_ai_review_comment.py", workflow) + self.assertIn("steps.claude_review.outputs.execution_file", workflow) if __name__ == "__main__": diff --git a/tests/test_post_monthly_ai_review_comment.py b/tests/test_post_monthly_ai_review_comment.py new file mode 100644 index 0000000..f6a0be8 --- /dev/null +++ b/tests/test_post_monthly_ai_review_comment.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import unittest + +from scripts.post_monthly_ai_review_comment import ( + COMMENT_MARKER, + build_comment_body, + extract_latest_assistant_text, +) + + +class PostMonthlyAiReviewCommentTests(unittest.TestCase): + def test_extract_latest_assistant_text_returns_last_text_reply(self) -> None: + execution_log = [ + {"type": "system", "subtype": "init"}, + { + "type": "assistant", + "message": { + "content": [ + {"type": "text", "text": "Working on it."}, + ] + }, + }, + { + "type": "assistant", + "message": { + "content": [ + {"type": "tool_use", "name": "Read", "input": {"file_path": "x"}}, + {"type": "text", "text": "## English\nFinal review\n\n## 中文\n最终结论"}, + ] + }, + }, + {"type": "result", "subtype": "success"}, + ] + + review_text = extract_latest_assistant_text(execution_log) + + self.assertEqual(review_text, "## English\nFinal review\n\n## 中文\n最终结论") + + def test_build_comment_body_includes_marker_and_run_link(self) -> None: + body = build_comment_body("Review content", "https://github.com/example/repo/actions/runs/1") + + self.assertIn(COMMENT_MARKER, body) + self.assertIn("## Claude Monthly Review", body) + self.assertIn("Review content", body) + self.assertIn("actions/runs/1", body) + + +if __name__ == "__main__": + unittest.main() From 85df578c278b14192e005ef9f4e50562aa61d0b7 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:30:52 +0800 Subject: [PATCH 3/5] fix: clarify monthly execution report scope --- .github/workflows/ai_review.yml | 9 +++++++++ scripts/run_monthly_report_bundle.py | 18 ++++++++++++++++-- tests/test_monthly_report_bundle.py | 4 ++++ tests/test_monthly_report_workflow_config.py | 3 +++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ai_review.yml b/.github/workflows/ai_review.yml index 2a35ffa..ba9c7bf 100644 --- a/.github/workflows/ai_review.yml +++ b/.github/workflows/ai_review.yml @@ -44,6 +44,14 @@ jobs: It runs hourly, executing a BTC DCA core strategy plus altcoin trend rotation using symbols from an upstream CryptoLeaderRotation pool. + This is a downstream execution review, not a pure upstream pool review. + Upstream pool changes are only one input section from CryptoLeaderRotation. + Equity changes may include manual deposits, withdrawals, or other external + balance flows, so do not treat equity delta as pure strategy PnL unless + the report contains explicit cash-flow evidence. + Trade and earn sections in the report are based on recorded hourly + execution intents/actions, not a separate exchange fill reconciliation. + The Issue body contains the full monthly execution review data. Analyze it and provide your review in BOTH English and Chinese. @@ -68,6 +76,7 @@ jobs: - Overall portfolio performance for the month. - BTC core vs trend sleeve performance separately. - Any concerning drawdowns? + - Explicitly separate raw equity change from strategy-attributable PnL when cash-flow context is missing. 5. **Upstream Pool Change Impact** - Did pool symbol rotations cause significant position churn? diff --git a/scripts/run_monthly_report_bundle.py b/scripts/run_monthly_report_bundle.py index 079bcf1..2473cca 100644 --- a/scripts/run_monthly_report_bundle.py +++ b/scripts/run_monthly_report_bundle.py @@ -230,6 +230,16 @@ def format_review_markdown(bundle: dict[str, Any]) -> str: lines.append(f"_Generated: {generated}_") lines.append("") + # Scope / interpretation notes + lines.append("## Report Scope") + lines.append("") + lines.append("- This is BinancePlatform's downstream monthly execution review, not a pure upstream pool publication.") + lines.append("- It summarizes runtime health, recorded trade intents, earn buffer operations, circuit breaker activity, degraded mode, and upstream pool changes.") + lines.append("- Upstream pool changes are included as execution context from CryptoLeaderRotation, but they are only one input section of this report.") + lines.append("- Equity deltas in this report are raw month-start vs month-end snapshots and may include manual deposits, withdrawals, or other external balance flows.") + lines.append("- Trade and earn sections reflect execution intents/actions recorded in hourly reports, not a separate exchange fill reconciliation ledger.") + lines.append("") + # Run statistics lines.append("## Run Statistics") lines.append("") @@ -255,10 +265,14 @@ def format_review_markdown(bundle: dict[str, Any]) -> str: lines.append(f"| PnL (USDT) | {pnl['pnl_usdt']} |") lines.append(f"| PnL (%) | {pnl['pnl_pct']} |") lines.append("") + lines.append("> Note: Equity deltas may include external balance flows and should not be interpreted as pure strategy PnL without separate cash-flow reconciliation.") + lines.append("") # Trade summary lines.append("## Trade Summary") lines.append("") + lines.append("> Note: Trade counts below are based on recorded strategy intents in hourly execution reports, not exchange fill reconciliation.") + lines.append("") lines.append("### BTC Core (DCA)") lines.append("") lines.append("| Metric | Value |") @@ -348,11 +362,11 @@ def format_review_markdown(bundle: dict[str, Any]) -> str: # Review questions lines.append("## Review Questions") lines.append("") - lines.append("1. Is the PnL trend consistent with market conditions this month?") + lines.append("1. Does the equity trend look explainable once possible external deposits/withdrawals are considered?") lines.append("2. Were any circuit breaker events justified, or do thresholds need adjusting?") lines.append("3. Did upstream pool changes have a noticeable impact on performance?") lines.append("4. Are the failed runs isolated incidents or part of a pattern?") - lines.append("5. Should BTC DCA cadence or sizing be adjusted based on this month's data?") + lines.append("5. Do the recorded trade intents suggest BTC DCA cadence or trend sizing should be adjusted?") lines.append("6. Were earn buffer subscribe/redeem operations executed at appropriate times?") lines.append("") diff --git a/tests/test_monthly_report_bundle.py b/tests/test_monthly_report_bundle.py index 5a82dda..d7f1c51 100644 --- a/tests/test_monthly_report_bundle.py +++ b/tests/test_monthly_report_bundle.py @@ -137,3 +137,7 @@ def test_format_review_markdown(self): self.assertIn("Monthly Execution Review", md) self.assertIn("2026-03", md) + self.assertIn("downstream monthly execution review", md) + self.assertIn("not a pure upstream pool publication", md) + self.assertIn("external balance flows", md) + self.assertIn("recorded strategy intents", md) diff --git a/tests/test_monthly_report_workflow_config.py b/tests/test_monthly_report_workflow_config.py index 6c38a95..e7051fb 100644 --- a/tests/test_monthly_report_workflow_config.py +++ b/tests/test_monthly_report_workflow_config.py @@ -31,6 +31,9 @@ def test_ai_review_workflow_supports_manual_dispatch(self) -> None: self.assertIn("${{ inputs.issue_number || github.event.issue.number }}", workflow) self.assertIn("Do not use Bash or ask for additional approval.", workflow) self.assertIn("The workflow will publish your final review as the issue comment.", workflow) + self.assertIn("This is a downstream execution review, not a pure upstream pool review.", workflow) + self.assertIn("do not treat equity delta as pure strategy PnL", workflow) + self.assertIn("not a separate exchange fill reconciliation", workflow) self.assertIn("post_monthly_ai_review_comment.py", workflow) self.assertIn("steps.claude_review.outputs.execution_file", workflow) From 578b3bdd2eed5b30cba143fba81fd68f4b795513 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:35:36 +0800 Subject: [PATCH 4/5] fix: inline issue context for AI review --- .github/workflows/ai_review.yml | 48 ++++++++++++++++++-- tests/test_monthly_report_workflow_config.py | 5 +- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ai_review.yml b/.github/workflows/ai_review.yml index ba9c7bf..15cc2d7 100644 --- a/.github/workflows/ai_review.yml +++ b/.github/workflows/ai_review.yml @@ -22,6 +22,42 @@ jobs: - name: Checkout uses: actions/checkout@v5 + - name: Load review issue context + id: issue_context + run: | + python3 - <<'PY' + import json + import os + import urllib.request + + repo = os.environ["GITHUB_REPOSITORY"] + issue_number = os.environ["ISSUE_NUMBER"] + token = os.environ["GITHUB_TOKEN"] + api_url = f"https://api.github.com/repos/{repo}/issues/{issue_number}" + request = urllib.request.Request( + api_url, + headers={ + "Accept": "application/vnd.github+json", + "Authorization": f"Bearer {token}", + "X-GitHub-Api-Version": "2022-11-28", + "User-Agent": "binanceplatform-ai-review", + }, + ) + with urllib.request.urlopen(request) as response: + issue = json.load(response) + + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output: + print("issue_title< None: self.assertIn("workflow_dispatch:", workflow) self.assertIn("issue_number:", workflow) self.assertIn("id-token: write", workflow) + self.assertIn("Load review issue context", workflow) + self.assertIn("api.github.com/repos", workflow) + self.assertIn("steps.issue_context.outputs.issue_title", workflow) + self.assertIn("steps.issue_context.outputs.issue_body", workflow) self.assertIn("id: claude_review", workflow) self.assertIn("github_token: ${{ secrets.GITHUB_TOKEN }}", workflow) - self.assertIn('--allowedTools "mcp__github__get_issue,mcp__github__get_issue_comments"', workflow) self.assertIn("${{ inputs.issue_number || github.event.issue.number }}", workflow) self.assertIn("Do not use Bash or ask for additional approval.", workflow) self.assertIn("The workflow will publish your final review as the issue comment.", workflow) From 72fa86f9d24194b88765adf4dca963afd367ae5c Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:38:38 +0800 Subject: [PATCH 5/5] fix: soften zero-trade AI assumptions --- .github/workflows/ai_review.yml | 4 ++++ tests/test_monthly_report_workflow_config.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/ai_review.yml b/.github/workflows/ai_review.yml index 15cc2d7..9befb37 100644 --- a/.github/workflows/ai_review.yml +++ b/.github/workflows/ai_review.yml @@ -83,6 +83,9 @@ jobs: the report contains explicit cash-flow evidence. Trade and earn sections in the report are based on recorded hourly execution intents/actions, not a separate exchange fill reconciliation. + Do not assume zero trades are automatically anomalous: when deployable + capital is small, manual withdrawals reduced balance, or threshold/cooldown + gates are active, a no-trade month may be legitimate. The issue title and body are provided below. Analyze it and provide your review in BOTH English and Chinese. @@ -99,6 +102,7 @@ jobs: - Are buy/sell frequencies reasonable for the month? - Any abnormally dense trading periods suggesting misbehavior? - Is the BTC DCA pattern consistent with the expected valuation-based scaling? + - Treat a zero-trade month as context-dependent, not automatically a bug. 2. **Circuit Breaker Events** - How many times was the circuit breaker triggered? diff --git a/tests/test_monthly_report_workflow_config.py b/tests/test_monthly_report_workflow_config.py index 2f3607b..519546e 100644 --- a/tests/test_monthly_report_workflow_config.py +++ b/tests/test_monthly_report_workflow_config.py @@ -37,6 +37,8 @@ def test_ai_review_workflow_supports_manual_dispatch(self) -> None: self.assertIn("This is a downstream execution review, not a pure upstream pool review.", workflow) self.assertIn("do not treat equity delta as pure strategy PnL", workflow) self.assertIn("not a separate exchange fill reconciliation", workflow) + self.assertIn("Do not assume zero trades are automatically anomalous", workflow) + self.assertIn("Treat a zero-trade month as context-dependent", workflow) self.assertIn("post_monthly_ai_review_comment.py", workflow) self.assertIn("steps.claude_review.outputs.execution_file", workflow)