diff --git a/.github/workflows/goal.lock.yml b/.github/workflows/goal.lock.yml index e087b11..2ac98b9 100644 --- a/.github/workflows/goal.lock.yml +++ b/.github/workflows/goal.lock.yml @@ -656,7 +656,7 @@ jobs: 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_0953b6d30e1cd558_EOF' - {"add_comment":{"hide_older_comments":false,"max":8,"target":"*"},"add_labels":{"max":2,"target":"*"},"create_pull_request":{"draft":true,"labels":["automation","goal"],"max":1,"max_patch_files":100,"max_patch_size":10240,"preserve_branch_name":true,"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":"fallback-to-issue"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":40960,"max_patch_size":10240}]},"push_to_pull_request_branch":{"if_no_changes":"warn","max":1,"max_patch_size":10240,"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"],"target":"*","title_prefix":"[Goal"},"remove_labels":{"max":2,"target":"*"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":3,"target":"*"}} + {"add_comment":{"hide_older_comments":false,"max":8,"target":"*"},"add_labels":{"max":2,"target":"*"},"create_pull_request":{"draft":true,"labels":["automation","goal"],"max":1,"max_patch_files":100,"max_patch_size":10240,"preserve_branch_name":true,"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":"fallback-to-issue"},"create_report_incomplete_issue":{"create_issue":false},"missing_data":{"create_issue":false},"missing_tool":{"create_issue":false},"noop":{"max":1,"report-as-issue":"false"},"push_repo_memory":{"memories":[{"dir":"/tmp/gh-aw/repo-memory/default","id":"default","max_file_count":100,"max_file_size":40960,"max_patch_size":10240}]},"push_to_pull_request_branch":{"if_no_changes":"warn","max":1,"max_patch_size":10240,"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"],"target":"*","title_prefix":"[Goal"},"remove_labels":{"max":2,"target":"*"},"report_incomplete":{"create_issue":false},"update_issue":{"allow_body":true,"max":3,"target":"*"}} GH_AW_SAFE_OUTPUTS_CONFIG_0953b6d30e1cd558_EOF - name: Generate Safe Outputs Tools env: @@ -1410,7 +1410,7 @@ jobs: GH_AW_WORKFLOW_SOURCE: "githubnext/goal" 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: "true" + 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 }} @@ -1444,7 +1444,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" + GH_AW_MISSING_TOOL_CREATE_ISSUE: "false" GH_AW_WORKFLOW_NAME: "Goal" GH_AW_WORKFLOW_SOURCE: "githubnext/goal" with: @@ -1459,7 +1459,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} - GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" + GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "false" GH_AW_WORKFLOW_NAME: "Goal" GH_AW_WORKFLOW_SOURCE: "githubnext/goal" with: @@ -1505,7 +1505,7 @@ jobs: GH_AW_REPO_MEMORY_VALIDATION_ERROR_default: ${{ needs.push_repo_memory.outputs.validation_error_default }} GH_AW_REPO_MEMORY_PATCH_SIZE_EXCEEDED_default: ${{ needs.push_repo_memory.outputs.patch_size_exceeded_default }} 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: "60" @@ -2042,7 +2042,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.gradle-enterprise.cloud,*.pythonhosted.org,*.vsblob.vsassets.io,adoptium.net,anaconda.org,api.adoptium.net,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.foojay.io,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.nuget.org,api.snapcraft.io,archive.apache.org,archive.ubuntu.com,azure.archive.ubuntu.com,azuresearch-usnc.nuget.org,azuresearch-ussc.nuget.org,binstar.org,bootstrap.pypa.io,builds.dotnet.microsoft.com,bun.sh,cdn.azul.com,cdn.jsdelivr.net,central.sonatype.com,ci.dot.net,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,dc.services.visualstudio.com,deb.nodesource.com,deno.land,develocity.apache.org,dist.nuget.org,dl.google.com,dlcdn.apache.org,dot.net,dotnet.microsoft.com,dotnetcli.blob.core.windows.net,download.eclipse.org,download.java.net,download.oracle.com,downloads.gradle-dn.com,esm.sh,files.pythonhosted.org,ge.spockframework.org,get.pnpm.io,github.com,googleapis.deno.dev,googlechromelabs.github.io,gradle.org,host.docker.internal,index.crates.io,jcenter.bintray.com,jdk.java.net,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,maven-central.storage-download.googleapis.com,maven.apache.org,maven.google.com,maven.oracle.com,maven.pkg.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,nuget.org,nuget.pkg.github.com,nugetregistryv2prod.blob.core.windows.net,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,oneocsp.microsoft.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,pkgs.dev.azure.com,plugins-artifacts.gradle.org,plugins.gradle.org,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.anaconda.com,repo.continuum.io,repo.gradle.org,repo.grails.org,repo.maven.apache.org,repo.spring.io,repo.yarnpkg.com,repo1.maven.org,repository.apache.org,s.symcb.com,s.symcd.com,scans-in.gradle.com,security.ubuntu.com,services.gradle.org,sh.rustup.rs,skimdb.npmjs.com,static.crates.io,static.rust-lang.org,storage.googleapis.com,telemetry.enterprise.githubcopilot.com,telemetry.vercel.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com,www.java.com,www.microsoft.com,www.npmjs.com,www.npmjs.org,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":false,\"max\":8,\"target\":\"*\"},\"add_labels\":{\"max\":2,\"target\":\"*\"},\"create_pull_request\":{\"draft\":true,\"labels\":[\"automation\",\"goal\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":10240,\"preserve_branch_name\":true,\"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\":\"fallback-to-issue\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":1,\"max_patch_size\":10240,\"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\"],\"target\":\"*\",\"title_prefix\":\"[Goal\"},\"remove_labels\":{\"max\":2,\"target\":\"*\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":3,\"target\":\"*\"}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":false,\"max\":8,\"target\":\"*\"},\"add_labels\":{\"max\":2,\"target\":\"*\"},\"create_pull_request\":{\"draft\":true,\"labels\":[\"automation\",\"goal\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":10240,\"preserve_branch_name\":true,\"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\":\"fallback-to-issue\"},\"create_report_incomplete_issue\":{\"create_issue\":false},\"missing_data\":{\"create_issue\":false},\"missing_tool\":{\"create_issue\":false},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max\":1,\"max_patch_size\":10240,\"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\"],\"target\":\"*\",\"title_prefix\":\"[Goal\"},\"remove_labels\":{\"max\":2,\"target\":\"*\"},\"report_incomplete\":{\"create_issue\":false},\"update_issue\":{\"allow_body\":true,\"max\":3,\"target\":\"*\"}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/goal.md b/.github/workflows/goal.md index e195a44..a6c04ad 100644 --- a/.github/workflows/goal.md +++ b/.github/workflows/goal.md @@ -30,11 +30,20 @@ network: - dotnet safe-outputs: + report-failure-as-issue: false max-patch-size: 10240 add-comment: max: 8 target: "*" hide-older-comments: false + missing-tool: + create-issue: false + missing-data: + create-issue: false + report-incomplete: + create-issue: false + noop: + report-as-issue: false create-pull-request: draft: true labels: [automation, goal] @@ -343,6 +352,10 @@ If the blocked stop condition is reached, stop substantive work and comment with Do not add `goal-completed` for a blocked goal. Keep the goal active unless the issue explicitly says a blocked report should end the workflow. +For missing tools, missing data, no-op/problem reports, protected-file +fallbacks, or any blocker tied to a selected goal, use `add_comment` on +`selected.number`. Do not open a new issue. + ## Common Mistakes To Avoid - Do not create a new branch per run. @@ -350,3 +363,5 @@ issue explicitly says a blocked report should end the workflow. - Do not mark complete without the issue's evidence. - Do not silently broaden scope when verification fails. - Do not repeat a failed path that the state file already ruled out. +- Do not open a separate issue for problems with the selected goal; comment on + the goal issue instead. diff --git a/tests/test_goal_scheduler.py b/tests/test_goal_scheduler.py index 38bb6f9..a528170 100644 --- a/tests/test_goal_scheduler.py +++ b/tests/test_goal_scheduler.py @@ -1,4 +1,6 @@ import importlib.util +import json +import re import unittest from pathlib import Path @@ -82,6 +84,48 @@ def test_select_goal_can_force_issue(self): self.assertEqual(selected["number"], 2) self.assertEqual([goal["number"] for goal in deferred], [1]) + def test_workflow_problem_reports_do_not_create_issues(self): + for workflow_path in (ROOT / "workflows" / "goal.md", ROOT / ".github" / "workflows" / "goal.md"): + with self.subTest(workflow_path=workflow_path): + workflow = workflow_path.read_text(encoding="utf-8") + + self.assertIn("report-failure-as-issue: false", workflow) + self.assertIn("missing-tool:\n create-issue: false", workflow) + self.assertIn("missing-data:\n create-issue: false", workflow) + self.assertIn("report-incomplete:\n create-issue: false", workflow) + self.assertIn("noop:\n report-as-issue: false", workflow) + self.assertIn("use `add_comment` on\n`selected.number`. Do not open a new issue.", workflow) + self.assertIn("comment on\n the goal issue instead.", workflow) + + lock = (ROOT / ".github" / "workflows" / "goal.lock.yml").read_text(encoding="utf-8") + handler_match = re.search(r'GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "(.+)"', lock) + config_line = next((line.strip() for line in lock.splitlines() if line.strip().startswith('{"add_comment"')), None) + self.assertIsNotNone(config_line) + self.assertIsNotNone(handler_match) + + configs = [ + json.loads(config_line), + json.loads(json.loads(f'"{handler_match.group(1)}"')), + ] + for config in configs: + with self.subTest(config=config): + self.assertIs(config["missing_tool"]["create_issue"], False) + self.assertIs(config["missing_data"]["create_issue"], False) + self.assertIs(config["report_incomplete"]["create_issue"], False) + self.assertEqual(str(config["noop"]["report-as-issue"]).lower(), "false") + + expected_false_flags = { + "GH_AW_NOOP_REPORT_AS_ISSUE", + "GH_AW_MISSING_TOOL_CREATE_ISSUE", + "GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE", + "GH_AW_FAILURE_REPORT_AS_ISSUE", + } + present_flags = set() + for match in re.finditer(r"(GH_AW_[A-Z_]*(?:REPORT_AS_ISSUE|CREATE_ISSUE)): \"([^\"]+)\"", lock): + present_flags.add(match.group(1)) + self.assertEqual(match.group(2), "false") + self.assertTrue(expected_false_flags.issubset(present_flags)) + if __name__ == "__main__": unittest.main() diff --git a/workflows/goal.md b/workflows/goal.md index 97730ec..a4c092f 100644 --- a/workflows/goal.md +++ b/workflows/goal.md @@ -30,11 +30,20 @@ network: - dotnet safe-outputs: + report-failure-as-issue: false max-patch-size: 10240 add-comment: max: 8 target: "*" hide-older-comments: false + missing-tool: + create-issue: false + missing-data: + create-issue: false + report-incomplete: + create-issue: false + noop: + report-as-issue: false create-pull-request: draft: true labels: [automation, goal] @@ -350,6 +359,10 @@ If the blocked stop condition is reached, stop substantive work and comment with Do not add `goal-completed` for a blocked goal. Keep the goal active unless the issue explicitly says a blocked report should end the workflow. +For missing tools, missing data, no-op/problem reports, protected-file +fallbacks, or any blocker tied to a selected goal, use `add_comment` on +`selected.number`. Do not open a new issue. + ## Common Mistakes To Avoid - Do not create a new branch per run. @@ -357,3 +370,5 @@ issue explicitly says a blocked report should end the workflow. - Do not mark complete without the issue's evidence. - Do not silently broaden scope when verification fails. - Do not repeat a failed path that the state file already ruled out. +- Do not open a separate issue for problems with the selected goal; comment on + the goal issue instead.