synapse-hub 2.2.3 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/agents/failure-analyst.md +11 -0
- package/.agents/agents/live-explorer.md +28 -0
- package/.agents/agents/orchestrator.md +20 -4
- package/.agents/agents/pom-crafter.md +12 -0
- package/.agents/agents/quality-gatekeeper.md +19 -4
- package/.agents/agents/test-runner.md +11 -0
- package/.agents/rules/communication-style.md +40 -0
- package/.agents/rules/context-engineering.md +23 -0
- package/.agents/rules/git-push-protocol.md +11 -17
- package/.agents/rules/graphify.md +14 -14
- package/.agents/rules/lessons-learned.md +3 -3
- package/.agents/rules/mandatory-playwright-live.md +29 -29
- package/.agents/rules/mobile_appium_rules.md +132 -0
- package/.agents/rules/performance_testing_rules.md +74 -0
- package/.agents/rules/skill-precedence.md +1 -1
- package/.agents/rules/systematic-debugging.md +6 -6
- package/.agents/skills/agent-orchestration-multi-agent-optimize/SKILL.md +64 -215
- package/.agents/skills/agent-orchestration-multi-agent-optimize/examples/swarm_workload_config.json +12 -0
- package/.agents/skills/antigravity-test-sentinel/SKILL.md +3 -3
- package/.agents/skills/antigravity-test-sentinel/examples/dod_gate_policy.json +11 -0
- package/.agents/skills/api-network-mocking-interception/SKILL.md +1 -1
- package/.agents/skills/api-network-mocking-interception/examples/network_route_stub.json +9 -0
- package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +9 -9
- package/.agents/skills/api-spec-to-e2e-matrix/examples/sample_openapi.json +19 -0
- package/.agents/skills/architecture-decision-records/SKILL.md +35 -412
- package/.agents/skills/architecture-decision-records/examples/0001-record-architecture-decisions.md +12 -0
- package/.agents/skills/auth-session-and-cookie-manager/SKILL.md +4 -1
- package/.agents/skills/auth-session-and-cookie-manager/examples/storage_state_sample.json +11 -0
- package/.agents/skills/backend-load-and-stress-patterns/SKILL.md +80 -186
- package/.agents/skills/backend-load-and-stress-patterns/examples/k6_load_test_sample.js +13 -0
- package/.agents/skills/bats-testing-patterns/SKILL.md +1 -1
- package/.agents/skills/bats-testing-patterns/examples/cli_runner_test.bats +6 -0
- package/.agents/skills/bats-testing-patterns/resources/implementation-playbook.md +614 -614
- package/.agents/skills/clean-pom-crafter/SKILL.md +21 -3
- package/.agents/skills/clean-pom-crafter/examples/standard_test_case.groovy +28 -28
- package/.agents/skills/clean-pom-crafter/references/pom_patterns.groovy +138 -138
- package/.agents/skills/code-refactoring-refactor-clean/SKILL.md +2 -2
- package/.agents/skills/code-refactoring-refactor-clean/examples/refactored_page_sample.groovy +9 -0
- package/.agents/skills/code-refactoring-refactor-clean/resources/implementation-playbook.md +9 -7
- package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +5 -5
- package/.agents/skills/db-state-verifier-and-seeder/examples/db_fixture_seed.json +12 -0
- package/.agents/skills/e2e-testing-patterns/SKILL.md +1 -1
- package/.agents/skills/e2e-testing-patterns/examples/playwright_sharded_config.ts +12 -0
- package/.agents/skills/e2e-testing-patterns/resources/implementation-playbook.md +522 -522
- package/.agents/skills/failure-autopsy-and-healing/SKILL.md +17 -3
- package/.agents/skills/failure-autopsy-and-healing/examples/sample_junit_failure.xml +8 -0
- package/.agents/skills/failure-autopsy-and-healing/references/healing_matrix.md +64 -64
- package/.agents/skills/failure-autopsy-and-healing/references/qa_investigation_protocol.md +56 -56
- package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +98 -98
- package/.agents/skills/file-and-report-validator/SKILL.md +1 -1
- package/.agents/skills/file-and-report-validator/examples/sample_export_schema.json +14 -0
- package/.agents/skills/flaky-test-sentinel-and-quarantine/SKILL.md +3 -3
- package/.agents/skills/flaky-test-sentinel-and-quarantine/examples/quarantine_registry.json +11 -0
- package/.agents/skills/gherkin-to-suite/SKILL.md +103 -0
- package/.agents/skills/gherkin-to-suite/examples/checkout.feature +39 -0
- package/.agents/skills/gherkin-to-suite/examples/suite_report_sample.json +334 -0
- package/.agents/skills/github-actions-templates/SKILL.md +47 -304
- package/.agents/skills/github-actions-templates/examples/matrix_test_pipeline.yml +8 -0
- package/.agents/skills/graphify-impact-analyzer/SKILL.md +6 -6
- package/.agents/skills/graphify-impact-analyzer/examples/dependency_blast_radius.json +8 -0
- package/.agents/skills/katalon-cli-runner/SKILL.md +2 -2
- package/.agents/skills/katalon-cli-runner/examples/headless_kre_exec.sh +3 -0
- package/.agents/skills/katalon-cli-runner/references/groovy-patterns.md +209 -209
- package/.agents/skills/katalon-cli-runner/references/katalon-api.md +155 -155
- package/.agents/skills/katalon-cli-runner/references/runner_commands.md +67 -67
- package/.agents/skills/lam-script-generator/SKILL.md +42 -1
- package/.agents/skills/lam-script-generator/examples/user_story_sample.md +8 -0
- package/.agents/skills/lean-code-ladder/SKILL.md +83 -0
- package/.agents/skills/lean-code-ladder/examples/ladder_walkthrough.md +37 -0
- package/.agents/skills/meta-prompt-crafter/SKILL.md +107 -0
- package/.agents/skills/meta-prompt-crafter/examples/qa_prompt_template.md +35 -0
- package/.agents/skills/persistent-planning-files/SKILL.md +108 -0
- package/.agents/skills/persistent-planning-files/examples/task_plan_example.md +56 -0
- package/.agents/skills/playwright-live-interaction/SKILL.md +49 -1
- package/.agents/skills/playwright-live-interaction/examples/live_probe_script.js +5 -0
- package/.agents/skills/playwright-live-interaction/references/advanced_superpowers.md +160 -160
- package/.agents/skills/playwright-live-interaction/references/compact_accessibility_snapshots.md +75 -75
- package/.agents/skills/playwright-live-interaction/references/recipes.md +388 -388
- package/.agents/skills/playwright-live-interaction/references/swarm_orchestration.md +134 -134
- package/.agents/skills/playwright-webapp-testing/SKILL.md +93 -0
- package/.agents/skills/playwright-webapp-testing/examples/server_lifecycle_playwright.py +63 -0
- package/.agents/skills/rbt-manual-testing/SKILL.md +150 -0
- package/.agents/skills/rbt-manual-testing/examples/checkout_rbt_manual_suite.md +25 -0
- package/.agents/skills/security-dast-sentinel/SKILL.md +57 -135
- package/.agents/skills/security-dast-sentinel/examples/dast_scan_config.json +10 -0
- package/.agents/skills/self-healing-locator/SKILL.md +24 -10
- package/.agents/skills/self-healing-locator/examples/aom_diff_sample.json +16 -0
- package/.agents/skills/skillspector-security-guard/SKILL.md +32 -90
- package/.agents/skills/skillspector-security-guard/examples/safe_mcp_config.json +12 -0
- package/.agents/skills/surgical-coding-principles/SKILL.md +89 -0
- package/.agents/skills/surgical-coding-principles/examples/surgical_vs_scope_creep.md +46 -0
- package/.agents/skills/synthetic-test-data-generator/SKILL.md +3 -3
- package/.agents/skills/synthetic-test-data-generator/examples/idempotent_data_recipe.json +9 -0
- package/.agents/skills/systematic-debugging/SKILL.md +100 -0
- package/.agents/skills/systematic-debugging/examples/four_phase_case.md +44 -0
- package/.agents/skills/test-driven-development/SKILL.md +114 -0
- package/.agents/skills/test-driven-development/examples/red_green_refactor_qa.md +78 -0
- package/.agents/skills/token-and-context-optimizer/SKILL.md +1 -1
- package/.agents/skills/token-and-context-optimizer/examples/distilled_log_sample.txt +3 -0
- package/.agents/skills/verification-before-completion/SKILL.md +100 -0
- package/.agents/skills/verification-before-completion/examples/evidence_log_example.md +46 -0
- package/.agents/skills/visual-regression-sentinel/SKILL.md +21 -1
- package/.agents/skills/visual-regression-sentinel/examples/visual_mask_rules.json +9 -0
- package/.agents/skills/wcag-audit-patterns/SKILL.md +3 -3
- package/.agents/skills/wcag-audit-patterns/examples/wcag_compliance_checklist.json +10 -0
- package/.agents/skills/wcag-audit-patterns/resources/implementation-playbook.md +541 -541
- package/.agents/skills/web-vitals-and-performance-profiler/SKILL.md +1 -1
- package/.agents/skills/web-vitals-and-performance-profiler/examples/cwv_budget_policy.json +6 -0
- package/.agents/templates/completion_report.md +57 -57
- package/.agents/workflows/analyze_requirement_document.md +18 -0
- package/.agents/workflows/export_testcases_excel.md +32 -0
- package/.agents/workflows/generate_combinatorial_test_data.md +28 -0
- package/.agents/workflows/generate_cross_module_test_plan.md +37 -0
- package/.agents/workflows/generate_manual_testcases_rbt.md +56 -0
- package/.agents/workflows/generate_requirements_from_website.md +25 -0
- package/.agents/workflows/generate_testcases_from_requirements.md +21 -0
- package/.agents/workflows/graphify.md +10 -10
- package/.agents/workflows/verify.md +2 -2
- package/.cursor/rules/language.mdc +7 -7
- package/.cursor/rules/synapse-qa.mdc +23 -0
- package/.cursorrules +7 -0
- package/.pre-commit-hooks.yaml +14 -0
- package/.windsurfrules +7 -0
- package/AGENTS.md +54 -15
- package/CLAUDE.md +35 -12
- package/LICENSE +30 -0
- package/NOTICE +180 -0
- package/README.en.md +325 -0
- package/README.md +247 -512
- package/action.yml +51 -0
- package/benchmarks/qa_eval/README.md +71 -0
- package/benchmarks/qa_eval/build_dataset.py +677 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-06_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-07_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-08_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-09_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/api_contract_drift/qa-challenge-10_api_contract_drift.json +22 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-21_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-22_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-23_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-24_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/fake_pass_tautology/qa-challenge-25_fake_pass_tautology.json +21 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-01_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-02_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-03_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-04_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/locator_drift/qa-challenge-05_locator_drift.json +23 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-16_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-17_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-18_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-19_stale_and_mutation.json +22 -0
- package/benchmarks/qa_eval/dataset/stale_and_mutation/qa-challenge-20_stale_and_mutation.json +23 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-11_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-12_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-13_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-14_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/dataset/timing_and_race/qa-challenge-15_timing_and_race.json +22 -0
- package/benchmarks/qa_eval/eval_runner.py +418 -0
- package/benchmarks/qa_eval/reports/AB_METHODOLOGY_REPORT.md +83 -0
- package/benchmarks/qa_eval/reports/BENCHMARK_REPORT.md +69 -0
- package/benchmarks/qa_eval/reports/eval_results.json +105 -0
- package/bin/agent-qa.js +10 -3
- package/docs/ARCHITECTURE.md +107 -0
- package/docs/CI_CD_INTEGRATION.md +94 -0
- package/docs/CLI_REFERENCE.md +157 -0
- package/docs/CONTRIBUTING.md +91 -0
- package/docs/PLUGIN_DEVELOPMENT_GUIDE.md +126 -0
- package/docs/TOKEN_QUOTA_PLAYBOOK.md +41 -0
- package/docs/adopted-ecosystem-tools.md +87 -0
- package/docs/schemas/synapse.config.schema.json +64 -0
- package/examples/cypress-ecommerce-suite/README.md +45 -0
- package/examples/cypress-ecommerce-suite/cypress/e2e/checkout.cy.js +17 -0
- package/examples/cypress-ecommerce-suite/cypress/pages/BasePage.js +29 -0
- package/examples/cypress-ecommerce-suite/cypress/pages/CartPage.js +51 -0
- package/examples/cypress-ecommerce-suite/cypress.config.js +13 -0
- package/examples/cypress-ecommerce-suite/package.json +13 -0
- package/examples/katalon-suite/Keywords/pages/BasePage.groovy +19 -0
- package/examples/katalon-suite/Keywords/pages/DashboardPage.groovy +29 -0
- package/examples/katalon-suite/Keywords/pages/LoginPage.groovy +45 -0
- package/examples/katalon-suite/Profiles/default.glbl +12 -0
- package/examples/katalon-suite/README.md +18 -0
- package/examples/katalon-suite/Scripts/Auth/TC_LoginSuccess/Script1234567890.groovy +12 -0
- package/examples/katalon-suite/Scripts/Dashboard/TC_ViewSummary/Script1234567891.groovy +15 -0
- package/examples/katalon-suite/katalon_suite.prj +21 -0
- package/examples/playwright-crm-suite/README.md +40 -0
- package/examples/playwright-crm-suite/package.json +14 -0
- package/examples/playwright-crm-suite/pages/BasePage.ts +37 -0
- package/examples/playwright-crm-suite/pages/CustomerPage.ts +57 -0
- package/examples/playwright-crm-suite/pages/LoginPage.ts +32 -0
- package/examples/playwright-crm-suite/playwright.config.ts +27 -0
- package/examples/playwright-crm-suite/tests/auth.spec.ts +22 -0
- package/examples/playwright-crm-suite/tests/customers.spec.ts +33 -0
- package/examples/plugins/sample-custom-plugin/README.md +14 -0
- package/examples/plugins/sample-custom-plugin/plugin.json +16 -0
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/SKILL.md +29 -0
- package/examples/plugins/sample-custom-plugin/skills/custom-security-headers-audit/examples/audit_fixture.json +8 -0
- package/examples/plugins/sample-custom-plugin/tools/custom_security_headers.py +125 -0
- package/examples/practices/README.md +22 -0
- package/examples/practices/requirements/crm/requirements_contracts.md +292 -0
- package/examples/practices/requirements/crm/requirements_customers.md +462 -0
- package/examples/practices/requirements/crm/requirements_login.md +202 -0
- package/examples/practices/requirements/crm/requirements_projects.md +396 -0
- package/examples/practices/requirements/crm/requirements_tasks.md +343 -0
- package/examples/practices/requirements/ecommerce/requirements_category_brand.txt +402 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-1/2026-04-03_04-28-27.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-1/KAN-1_requirement.md +52 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-19.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/2026-04-03_04-28-57.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-4/KAN-4_requirement.md +119 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-5_overview.md +9 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-08.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/2026-04-03_05-58-23.png +0 -0
- package/examples/practices/requirements/jira/KAN-5/KAN-6/KAN-6_requirement.md +32 -0
- package/examples/practices/testcases/api/book_management_api_test_cases.md +144 -0
- package/examples/practices/testcases/api/user_management_api_test_cases.md +139 -0
- package/examples/practices/testcases/crm/test_cases_crm_login.md +148 -0
- package/examples/practices/testcases/crm/test_cases_customers.md +156 -0
- package/examples/pytest-api-suite/README.md +45 -0
- package/examples/pytest-api-suite/conftest.py +31 -0
- package/examples/pytest-api-suite/pages/user_api_client.py +36 -0
- package/examples/pytest-api-suite/requirements.txt +2 -0
- package/examples/pytest-api-suite/tests/test_user_api.py +44 -0
- package/examples/selenium-suite/README.md +18 -0
- package/examples/selenium-suite/pages/base_page.py +27 -0
- package/examples/selenium-suite/pages/login_page.py +29 -0
- package/examples/selenium-suite/pages/order_page.py +25 -0
- package/examples/selenium-suite/pytest.ini +6 -0
- package/examples/selenium-suite/requirements.txt +2 -0
- package/examples/selenium-suite/tests/test_login.py +10 -0
- package/examples/selenium-suite/tests/test_order.py +10 -0
- package/package.json +22 -7
- package/scripts/generate_skill_examples.py +244 -0
- package/scripts/install.ps1 +112 -0
- package/scripts/install_global_plugin.ps1 +94 -0
- package/scripts/install_global_plugin.sh +49 -0
- package/scripts/lint_skills.ps1 +57 -0
- package/scripts/package_dist.py +323 -0
- package/scripts/setup.sh +59 -0
- package/scripts/update_hub.ps1 +19 -0
- package/scripts/update_hub.sh +15 -0
- package/skills_manifest.json +209 -6
- package/synapse.config.json +30 -0
- package/templates/PROJECT_AI_GUIDE_TEMPLATE.md +7 -7
- package/templates/PROJECT_STATE_TEMPLATE.md +1 -1
- package/templates/ai_bridges/CLAUDE.md +33 -16
- package/templates/ai_bridges/copilot-instructions.md +14 -21
- package/templates/ai_bridges/cursor_synapse_qa.mdc +17 -20
- package/templates/ai_bridges/windsurfrules +21 -21
- package/templates/ci/github-actions-synapse.yml +71 -4
- package/templates/welcome.html.tmpl +1674 -0
- package/tools/.infer_baseline.json +1102 -0
- package/tools/TOOLS_RUNBOOK.md +92 -130
- package/tools/__init__.py +26 -0
- package/tools/agent_canary.py +501 -501
- package/tools/analyze_project.py +31 -17
- package/tools/api_fuzzer.py +278 -6
- package/tools/author_integrity.py +6 -6
- package/tools/auto_heal.py +1 -1
- package/tools/browser_helpers.js +105 -7
- package/tools/bug_reporter.py +31 -1
- package/tools/bump_version.py +23 -3
- package/tools/cache_resolver.py +248 -14
- package/tools/check_env.py +55 -14
- package/tools/check_version_sync.py +153 -0
- package/tools/ci_healing_hook.py +1 -1
- package/tools/cli.py +263 -13
- package/tools/count_tokens.py +1257 -0
- package/tools/dashboard_generator.py +2638 -0
- package/tools/db_sandbox.py +198 -20
- package/tools/e2e_flow_prober.ps1 +12 -64
- package/tools/e2e_flow_prober.py +99 -0
- package/tools/e2e_flow_prober.sh +4 -0
- package/tools/export_postman_collection.py +29 -7
- package/tools/flaky_detector.py +4 -3
- package/tools/generate_allure_report.ps1 +12 -29
- package/tools/generate_allure_report.py +77 -0
- package/tools/generate_allure_report.sh +4 -0
- package/tools/generate_jmx_plan.py +299 -68
- package/tools/generate_test_reports.ps1 +12 -134
- package/tools/generate_test_reports.py +133 -0
- package/tools/generate_test_reports.sh +4 -0
- package/tools/gherkin_suite.py +758 -0
- package/tools/git_pre_commit_guard.py +12 -6
- package/tools/goldfish_review.py +366 -0
- package/tools/heal_pr_automator.py +1 -1
- package/tools/heuristic_locator_matcher.py +170 -21
- package/tools/infer_linter.py +612 -70
- package/tools/jtl_analyzer.py +1 -1
- package/tools/lint_ai_docs.py +64 -0
- package/tools/matrix_sharder.py +1 -1
- package/tools/mcp_excel_server.ps1 +12 -250
- package/tools/mcp_excel_server.py +249 -0
- package/tools/mcp_excel_server.sh +4 -0
- package/tools/mcp_server.py +368 -144
- package/tools/md_to_xlsx.py +307 -0
- package/tools/micro_mutator.py +300 -69
- package/tools/omni_transpiler.py +2 -2
- package/tools/output_formatter.py +128 -0
- package/tools/pinpoint_failure.py +88 -88
- package/tools/project_state.py +2 -2
- package/tools/repo_map.py +1 -1
- package/tools/safety_firewall.py +197 -33
- package/tools/setup_project.py +294 -30
- package/tools/skillspector.py +8 -8
- package/tools/spec_drift_sentinel.py +439 -0
- package/tools/sync_agent_rules.py +248 -0
- package/tools/telemetry_correlator.py +45 -0
- package/tools/test_impact.py +51 -12
- package/tools/tms_sync_bridge.py +21 -5
- package/tools/universal_ir.py +3 -0
- package/tools/update_sentinel.py +87 -15
- package/tools/verify_all.ps1 +13 -0
- package/tools/verify_all.py +463 -79
- package/tools/visual_diff_canvas.py +1 -0
- package/tools/visual_som_helper.py +1 -1
- package/tools/watch_mode.py +305 -0
- package/tools/welcome_page.py +291 -0
|
@@ -11,6 +11,7 @@ Ensures:
|
|
|
11
11
|
|
|
12
12
|
import sys
|
|
13
13
|
import os
|
|
14
|
+
import shlex
|
|
14
15
|
import subprocess
|
|
15
16
|
|
|
16
17
|
# Enforce UTF-8 stdout encoding for Windows console compatibility
|
|
@@ -23,8 +24,13 @@ if hasattr(sys.stdout, 'reconfigure'):
|
|
|
23
24
|
|
|
24
25
|
FORBIDDEN_PATHS = ["/Users/", "C:\\Workspace\\", "D:\\Workspace\\", "file:///c:", "file:///d:"]
|
|
25
26
|
|
|
26
|
-
def run_cmd(cmd):
|
|
27
|
-
|
|
27
|
+
def run_cmd(cmd, timeout: float = 60.0):
|
|
28
|
+
if isinstance(cmd, str):
|
|
29
|
+
cmd = shlex.split(cmd)
|
|
30
|
+
try:
|
|
31
|
+
return subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=timeout)
|
|
32
|
+
except subprocess.TimeoutExpired:
|
|
33
|
+
return subprocess.CompletedProcess(cmd, returncode=124, stdout="", stderr=f"Command timed out after {timeout}s")
|
|
28
34
|
|
|
29
35
|
def check_bom(files):
|
|
30
36
|
bom_files = []
|
|
@@ -187,7 +193,7 @@ def main():
|
|
|
187
193
|
if doc_affected:
|
|
188
194
|
linter_script = os.path.join(os.path.dirname(__file__), "lint_ai_docs.py")
|
|
189
195
|
if os.path.exists(linter_script):
|
|
190
|
-
res =
|
|
196
|
+
res = run_cmd([sys.executable, linter_script], timeout=60.0)
|
|
191
197
|
if res.returncode != 0:
|
|
192
198
|
print("❌ [PRE-COMMIT BLOCKED] AI Documentation Linter detected drift:")
|
|
193
199
|
print(res.stdout.strip())
|
|
@@ -198,16 +204,16 @@ def main():
|
|
|
198
204
|
if keywords_affected:
|
|
199
205
|
repo_map_script = os.path.join(os.path.dirname(__file__), "repo_map.py")
|
|
200
206
|
if os.path.exists(repo_map_script):
|
|
201
|
-
|
|
207
|
+
run_cmd([sys.executable, repo_map_script], timeout=60.0)
|
|
202
208
|
# Stage updated repo_map files
|
|
203
|
-
|
|
209
|
+
run_cmd(["git", "add", "tools/repo_map.txt", "tools/repo_map.json"], timeout=30.0)
|
|
204
210
|
|
|
205
211
|
# 6. Scripts/ change -> Static Defect Linter (Meta Infer-Style)
|
|
206
212
|
scripts_affected = any(f.startswith("Scripts/") and f.endswith(".groovy") for f in staged_files)
|
|
207
213
|
if scripts_affected:
|
|
208
214
|
infer_script = os.path.join(os.path.dirname(__file__), "infer_linter.py")
|
|
209
215
|
if os.path.exists(infer_script):
|
|
210
|
-
res =
|
|
216
|
+
res = run_cmd([sys.executable, infer_script], timeout=60.0)
|
|
211
217
|
if res.returncode != 0:
|
|
212
218
|
print("❌ [PRE-COMMIT BLOCKED] Static Defect Sentinel detected critical issues in staged scripts:")
|
|
213
219
|
print(res.stdout.strip())
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-FileCopyrightText: Copyright (c) 2026 Thế Vị (@TeeVee998). All rights reserved.
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
# Project: Synapse-Hub (https://github.com/TeeVee998/Synapse-Hub)
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
tools/goldfish_review.py — Zero-Context Test Specification Reviewer
|
|
8
|
+
-------------------------------------------------------------------
|
|
9
|
+
Inspired by Google's Elephant-Goldfish Model (EGM).
|
|
10
|
+
Acts as a stateless, zero-context 'Goldfish' reviewer to stress-test test specifications,
|
|
11
|
+
BDD Gherkin feature files, and Acceptance Criteria BEFORE code synthesis begins.
|
|
12
|
+
|
|
13
|
+
5 Verification Vectors:
|
|
14
|
+
1. Comprehension & System Boundaries (20%): Actor, Preconditions, Clear Target Scope.
|
|
15
|
+
2. Dynamic Data & Idempotent Teardown (20%): Dynamic IDs (uniqueCode), No hardcoded collisions, Teardown hook.
|
|
16
|
+
3. Assertion Rigor (25%): Unambiguous expected results, Anti-Fake Pass, explicit state checks.
|
|
17
|
+
4. Boundary & Negative Scenarios (20%): Negative flows, invalid inputs, edge cases covered.
|
|
18
|
+
5. Implementation Target (15%): Concrete Page Class mapping, API endpoints, or UI targets specified.
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
python tools/goldfish_review.py <path_to_spec.md_or_.feature>
|
|
22
|
+
python tools/goldfish_review.py --json <path_to_spec>
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import os
|
|
26
|
+
import sys
|
|
27
|
+
import re
|
|
28
|
+
import json
|
|
29
|
+
import argparse
|
|
30
|
+
|
|
31
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
32
|
+
try:
|
|
33
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
34
|
+
sys.stderr.reconfigure(encoding='utf-8')
|
|
35
|
+
except Exception:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
VAGUE_ASSERTION_PATTERNS = [
|
|
40
|
+
re.compile(r'\b(works? fine|works? properly|works? as expected)\b', re.IGNORECASE),
|
|
41
|
+
re.compile(r'\b(system works|page opens|everything is ok|no errors?)\b', re.IGNORECASE),
|
|
42
|
+
re.compile(r'\b(hệ thống hoạt động bình thường|thành công mà không có lỗi|hiển thị đúng)\b', re.IGNORECASE),
|
|
43
|
+
re.compile(r'\b(should succeed|should pass)\b(?!\s+(with|and assert|expecting))', re.IGNORECASE),
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
PRECISE_ASSERTION_PATTERNS = [
|
|
47
|
+
re.compile(r'\b(assert|expect|verify|check)\b', re.IGNORECASE),
|
|
48
|
+
re.compile(r'\b(status code|http \d{3}|returns? \d{3})\b', re.IGNORECASE),
|
|
49
|
+
re.compile(r'\b(contains?|equals?|matches?|visible|hidden|disabled|enabled)\b', re.IGNORECASE),
|
|
50
|
+
re.compile(r'\b(then\s+the\s+.*\s+(should|must|will))\b', re.IGNORECASE),
|
|
51
|
+
re.compile(r'\b(thông báo|thành công|thất bại|mã lỗi|kết quả mong đợi)\b', re.IGNORECASE),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
DYNAMIC_DATA_PATTERNS = [
|
|
55
|
+
re.compile(r'\b(uniquecode|timestamp|random|uuid|generator|autogen|dyn_)\b', re.IGNORECASE),
|
|
56
|
+
re.compile(r'\b(auto_\w+|test_\$\w+|faker)\b', re.IGNORECASE),
|
|
57
|
+
re.compile(r'\b(dữ liệu động|ngẫu nhiên|mã tự sinh)\b', re.IGNORECASE),
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
HARDCODED_DATA_PATTERNS = [
|
|
61
|
+
re.compile(r'["\'](user\d+|admin\d+|testuser|demo\d+|pass\d+)["\']', re.IGNORECASE),
|
|
62
|
+
re.compile(r'id\s*[:=]\s*["\']\d+["\']', re.IGNORECASE),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
TEARDOWN_PATTERNS = [
|
|
66
|
+
re.compile(r'\b(teardown|cleanup|delete after|roll back|xóa dữ liệu|dọn dẹp|aftereach|afterall)\b', re.IGNORECASE),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
BOUNDARY_NEGATIVE_PATTERNS = [
|
|
70
|
+
re.compile(r'\b(negative|invalid|boundary|error|fail|reject|unauthorized|forbidden|400|401|403|404|500)\b', re.IGNORECASE),
|
|
71
|
+
re.compile(r'\b(trường hợp lỗi|không hợp lệ|quá độ dài|để trống|bỏ trống|sai định dạng)\b', re.IGNORECASE),
|
|
72
|
+
re.compile(r'\b(double submit|race condition|timeout|network lag)\b', re.IGNORECASE),
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
IMPLEMENTATION_TARGET_PATTERNS = [
|
|
76
|
+
re.compile(r'\b([A-Z][a-zA-Z0-9]+(Page|Screen|View|Modal|Dialog|Api|Client|Service))\b'),
|
|
77
|
+
re.compile(r'\b(page class|endpoint|url|route|table|input|button|form)\b', re.IGNORECASE),
|
|
78
|
+
re.compile(r'(/api/v\d+/[\w/]+)', re.IGNORECASE),
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def evaluate_spec_content(content: str, filename: str = "") -> dict:
|
|
83
|
+
"""
|
|
84
|
+
Evaluates a test specification content through the 5 Goldfish vectors.
|
|
85
|
+
Returns a structured dictionary with scores, findings, and overall readiness.
|
|
86
|
+
"""
|
|
87
|
+
if not content or not content.strip():
|
|
88
|
+
return {
|
|
89
|
+
"file": filename,
|
|
90
|
+
"score": 0,
|
|
91
|
+
"passed": False,
|
|
92
|
+
"status": "REJECTED",
|
|
93
|
+
"vector_scores": {
|
|
94
|
+
"Comprehension": 0,
|
|
95
|
+
"Data Independence": 0,
|
|
96
|
+
"Assertion Rigor": 0,
|
|
97
|
+
"Boundary Coverage": 0,
|
|
98
|
+
"Implementation Target": 0
|
|
99
|
+
},
|
|
100
|
+
"findings_count": 1,
|
|
101
|
+
"findings": [{
|
|
102
|
+
"vector": "Comprehension",
|
|
103
|
+
"severity": "CRITICAL",
|
|
104
|
+
"message": "Specification content is completely empty or whitespace only."
|
|
105
|
+
}]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
findings = []
|
|
109
|
+
vector_scores = {}
|
|
110
|
+
|
|
111
|
+
lines = [line.strip() for line in content.splitlines() if line.strip()]
|
|
112
|
+
full_text = content.lower()
|
|
113
|
+
|
|
114
|
+
# -------------------------------------------------------------
|
|
115
|
+
# Vector 1: Comprehension & System Boundaries (Weight: 20)
|
|
116
|
+
# -------------------------------------------------------------
|
|
117
|
+
v1_score = 0
|
|
118
|
+
has_title = bool(re.search(r'^(#|feature:|title:|user story:)', content, re.MULTILINE | re.IGNORECASE))
|
|
119
|
+
has_preconditions = bool(re.search(r'\b(precondition|given|context|tiền điều kiện|bối cảnh|trước khi)\b', content, re.IGNORECASE))
|
|
120
|
+
has_actor = bool(re.search(r'\b(as a|actor|user|admin|role|người dùng|vai trò)\b', content, re.IGNORECASE))
|
|
121
|
+
|
|
122
|
+
if has_title:
|
|
123
|
+
v1_score += 8
|
|
124
|
+
else:
|
|
125
|
+
findings.append({
|
|
126
|
+
"vector": "Comprehension",
|
|
127
|
+
"severity": "MEDIUM",
|
|
128
|
+
"message": "Missing explicit Title or Feature declaration (# Title / Feature: ...)."
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
if has_preconditions:
|
|
132
|
+
v1_score += 7
|
|
133
|
+
else:
|
|
134
|
+
findings.append({
|
|
135
|
+
"vector": "Comprehension",
|
|
136
|
+
"severity": "HIGH",
|
|
137
|
+
"message": "Missing Preconditions / Given setup context. Zero-context agents cannot deduce start state."
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
if has_actor:
|
|
141
|
+
v1_score += 5
|
|
142
|
+
else:
|
|
143
|
+
findings.append({
|
|
144
|
+
"vector": "Comprehension",
|
|
145
|
+
"severity": "LOW",
|
|
146
|
+
"message": "Missing explicit Actor/Role definition ('As a ...' / 'Actor: ...')."
|
|
147
|
+
})
|
|
148
|
+
vector_scores["Comprehension"] = v1_score
|
|
149
|
+
|
|
150
|
+
# -------------------------------------------------------------
|
|
151
|
+
# Vector 2: Dynamic Data & Idempotent Teardown (Weight: 20)
|
|
152
|
+
# -------------------------------------------------------------
|
|
153
|
+
v2_score = 0
|
|
154
|
+
has_dynamic_data = any(p.search(content) for p in DYNAMIC_DATA_PATTERNS)
|
|
155
|
+
has_hardcoded_data = any(p.search(content) for p in HARDCODED_DATA_PATTERNS)
|
|
156
|
+
has_teardown = any(p.search(content) for p in TEARDOWN_PATTERNS)
|
|
157
|
+
|
|
158
|
+
is_creation_test = bool(re.search(r'\b(create|add|insert|register|post|tạo mới|thêm mới|đăng ký)\b', content, re.IGNORECASE))
|
|
159
|
+
|
|
160
|
+
if has_dynamic_data:
|
|
161
|
+
v2_score += 10
|
|
162
|
+
elif not is_creation_test:
|
|
163
|
+
v2_score += 7 # Read-only or navigation spec
|
|
164
|
+
else:
|
|
165
|
+
findings.append({
|
|
166
|
+
"vector": "Data Independence",
|
|
167
|
+
"severity": "HIGH",
|
|
168
|
+
"message": "Creation spec lacks dynamic test data generation (uniqueCode, timestamp). High risk of DB collisions."
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
if has_teardown:
|
|
172
|
+
v2_score += 10
|
|
173
|
+
elif not is_creation_test:
|
|
174
|
+
v2_score += 10
|
|
175
|
+
else:
|
|
176
|
+
findings.append({
|
|
177
|
+
"vector": "Data Independence",
|
|
178
|
+
"severity": "HIGH",
|
|
179
|
+
"message": "Creation spec lacks explicit automated Teardown / Cleanup step. Violates DB hygiene discipline."
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
if has_hardcoded_data:
|
|
183
|
+
v2_score = max(0, v2_score - 5)
|
|
184
|
+
findings.append({
|
|
185
|
+
"vector": "Data Independence",
|
|
186
|
+
"severity": "MEDIUM",
|
|
187
|
+
"message": "Detected static/hardcoded credentials or entity IDs. Must parameterize via environment or dynamic generator."
|
|
188
|
+
})
|
|
189
|
+
vector_scores["Data Independence"] = v2_score
|
|
190
|
+
|
|
191
|
+
# -------------------------------------------------------------
|
|
192
|
+
# Vector 3: Assertion Rigor & Truth Anchor (Weight: 25)
|
|
193
|
+
# -------------------------------------------------------------
|
|
194
|
+
v3_score = 0
|
|
195
|
+
precise_matches = sum(len(p.findall(content)) for p in PRECISE_ASSERTION_PATTERNS)
|
|
196
|
+
vague_matches = sum(len(p.findall(content)) for p in VAGUE_ASSERTION_PATTERNS)
|
|
197
|
+
|
|
198
|
+
if precise_matches >= 3:
|
|
199
|
+
v3_score += 25
|
|
200
|
+
elif precise_matches >= 1:
|
|
201
|
+
v3_score += 15
|
|
202
|
+
findings.append({
|
|
203
|
+
"vector": "Assertion Rigor",
|
|
204
|
+
"severity": "MEDIUM",
|
|
205
|
+
"message": f"Low assertion density (found {precise_matches} precise check(s)). Spec needs more concrete expected values."
|
|
206
|
+
})
|
|
207
|
+
else:
|
|
208
|
+
findings.append({
|
|
209
|
+
"vector": "Assertion Rigor",
|
|
210
|
+
"severity": "CRITICAL",
|
|
211
|
+
"message": "Zero concrete assertions or expected outcomes detected in spec. Violates Truth Anchor."
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
if vague_matches > 0:
|
|
215
|
+
v3_score = max(0, v3_score - (vague_matches * 5))
|
|
216
|
+
findings.append({
|
|
217
|
+
"vector": "Assertion Rigor",
|
|
218
|
+
"severity": "HIGH",
|
|
219
|
+
"message": f"Found {vague_matches} vague assertion phrase(s) ('works fine', 'hoạt động bình thường'). Replace with concrete verification criteria."
|
|
220
|
+
})
|
|
221
|
+
vector_scores["Assertion Rigor"] = v3_score
|
|
222
|
+
|
|
223
|
+
# -------------------------------------------------------------
|
|
224
|
+
# Vector 4: Boundary & Negative Scenarios (Weight: 20)
|
|
225
|
+
# -------------------------------------------------------------
|
|
226
|
+
v4_score = 0
|
|
227
|
+
has_boundary = any(p.search(content) for p in BOUNDARY_NEGATIVE_PATTERNS)
|
|
228
|
+
|
|
229
|
+
if has_boundary:
|
|
230
|
+
v4_score = 20
|
|
231
|
+
else:
|
|
232
|
+
findings.append({
|
|
233
|
+
"vector": "Boundary Coverage",
|
|
234
|
+
"severity": "MEDIUM",
|
|
235
|
+
"message": "No negative, boundary, or invalid input scenarios specified. Spec only tests the happy path."
|
|
236
|
+
})
|
|
237
|
+
v4_score = 5
|
|
238
|
+
vector_scores["Boundary Coverage"] = v4_score
|
|
239
|
+
|
|
240
|
+
# -------------------------------------------------------------
|
|
241
|
+
# Vector 5: Implementation Target & Technical Mapping (Weight: 15)
|
|
242
|
+
# -------------------------------------------------------------
|
|
243
|
+
v5_score = 0
|
|
244
|
+
has_target = any(p.search(content) for p in IMPLEMENTATION_TARGET_PATTERNS)
|
|
245
|
+
|
|
246
|
+
if has_target:
|
|
247
|
+
v5_score = 15
|
|
248
|
+
else:
|
|
249
|
+
findings.append({
|
|
250
|
+
"vector": "Implementation Target",
|
|
251
|
+
"severity": "LOW",
|
|
252
|
+
"message": "No target PageClass, API endpoint, or concrete UI selector category referenced. Engineers must guess technical anchors."
|
|
253
|
+
})
|
|
254
|
+
v5_score = 5
|
|
255
|
+
vector_scores["Implementation Target"] = v5_score
|
|
256
|
+
|
|
257
|
+
# Total score calculation
|
|
258
|
+
total_score = sum(vector_scores.values())
|
|
259
|
+
total_score = max(0, min(100, total_score))
|
|
260
|
+
|
|
261
|
+
passed = total_score >= 80 and not any(f["severity"] == "CRITICAL" for f in findings)
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
"file": filename,
|
|
265
|
+
"score": total_score,
|
|
266
|
+
"passed": passed,
|
|
267
|
+
"status": "APPROVED" if passed else "REJECTED",
|
|
268
|
+
"vector_scores": vector_scores,
|
|
269
|
+
"findings_count": len(findings),
|
|
270
|
+
"findings": findings
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def review_file(filepath: str) -> dict:
|
|
275
|
+
if not os.path.isfile(filepath):
|
|
276
|
+
return {
|
|
277
|
+
"file": filepath,
|
|
278
|
+
"score": 0,
|
|
279
|
+
"passed": False,
|
|
280
|
+
"status": "ERROR",
|
|
281
|
+
"vector_scores": {},
|
|
282
|
+
"findings_count": 1,
|
|
283
|
+
"findings": [{"vector": "File System", "severity": "CRITICAL", "message": f"File not found: {filepath}"}]
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
try:
|
|
287
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
288
|
+
content = f.read()
|
|
289
|
+
except UnicodeDecodeError:
|
|
290
|
+
try:
|
|
291
|
+
with open(filepath, "r", encoding="latin-1") as f:
|
|
292
|
+
content = f.read()
|
|
293
|
+
except Exception as e:
|
|
294
|
+
return {
|
|
295
|
+
"file": filepath,
|
|
296
|
+
"score": 0,
|
|
297
|
+
"passed": False,
|
|
298
|
+
"status": "ERROR",
|
|
299
|
+
"vector_scores": {},
|
|
300
|
+
"findings_count": 1,
|
|
301
|
+
"findings": [{"vector": "Encoding", "severity": "CRITICAL", "message": f"Could not read file: {e}"}]
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return evaluate_spec_content(content, filename=filepath)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def print_cli_report(result: dict):
|
|
308
|
+
print("=" * 70)
|
|
309
|
+
print(" GOLDFISH SPECIFICATION AUDITOR — ZERO-CONTEXT VERIFICATION")
|
|
310
|
+
print(" Inspired by Google Elephant-Goldfish Model (EGM)")
|
|
311
|
+
print("=" * 70)
|
|
312
|
+
print(f"Target Specification : {result['file'] or 'Direct Input'}")
|
|
313
|
+
print(f"Readiness Score : {result['score']}/100")
|
|
314
|
+
status_icon = "✅" if result['passed'] else "❌"
|
|
315
|
+
print(f"Audit Verdict : {status_icon} [{result['status']}] (Threshold: >= 80%)")
|
|
316
|
+
print("-" * 70)
|
|
317
|
+
print("Vector Breakdown:")
|
|
318
|
+
for vec, score in result.get("vector_scores", {}).items():
|
|
319
|
+
max_v = 25 if vec == "Assertion Rigor" else (15 if vec == "Implementation Target" else 20)
|
|
320
|
+
filled = int(score / max_v * 10) if max_v > 0 else 0
|
|
321
|
+
filled = max(0, min(10, filled))
|
|
322
|
+
bar = "#" * filled + "-" * (10 - filled)
|
|
323
|
+
print(f" • {vec:<24}: {score:>2}/{max_v:>2} [{bar}]")
|
|
324
|
+
|
|
325
|
+
print("-" * 70)
|
|
326
|
+
if result["findings"]:
|
|
327
|
+
print(f"Discovered Unstated Assumptions & Gaps ({len(result['findings'])}):")
|
|
328
|
+
for i, item in enumerate(result["findings"], 1):
|
|
329
|
+
sev = item["severity"]
|
|
330
|
+
sev_badge = f"[{sev}]"
|
|
331
|
+
print(f" {i}. {sev_badge:<10} ({item['vector']}) {item['message']}")
|
|
332
|
+
else:
|
|
333
|
+
print("✅ Zero unstated assumptions detected. Specification is 100% implementation-ready.")
|
|
334
|
+
print("=" * 70)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def main():
|
|
338
|
+
parser = argparse.ArgumentParser(
|
|
339
|
+
description="Goldfish Spec Reviewer — Zero-context stress-test for specifications and user stories."
|
|
340
|
+
)
|
|
341
|
+
parser.add_argument("spec_file", nargs="?", default="", help="Path to specification Markdown or Gherkin .feature file (use '-' for stdin)")
|
|
342
|
+
parser.add_argument("--stdin", action="store_true", help="Read specification from standard input (stdin)")
|
|
343
|
+
parser.add_argument("--json", action="store_true", help="Output machine-readable JSON format")
|
|
344
|
+
parser.add_argument("--min-score", type=int, default=80, help="Minimum readiness score threshold (default: 80)")
|
|
345
|
+
|
|
346
|
+
args = parser.parse_args()
|
|
347
|
+
|
|
348
|
+
if args.spec_file == "-" or getattr(args, "stdin", False):
|
|
349
|
+
content = sys.stdin.read()
|
|
350
|
+
result = evaluate_spec_content(content, filename="<stdin>")
|
|
351
|
+
elif not args.spec_file:
|
|
352
|
+
parser.print_help()
|
|
353
|
+
sys.exit(1)
|
|
354
|
+
else:
|
|
355
|
+
result = review_file(args.spec_file)
|
|
356
|
+
|
|
357
|
+
if args.json:
|
|
358
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
359
|
+
else:
|
|
360
|
+
print_cli_report(result)
|
|
361
|
+
|
|
362
|
+
sys.exit(0 if result["passed"] else 1)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
if __name__ == "__main__":
|
|
366
|
+
main()
|
|
@@ -140,7 +140,7 @@ def generate_pr_draft(
|
|
|
140
140
|
#### 3. Verification Checklist
|
|
141
141
|
- [x] Confidence score meets threshold ($\ge 90\%$)
|
|
142
142
|
- [x] Tested with `python tools/test_impact.py` on impacted test cases
|
|
143
|
-
- [x]
|
|
143
|
+
- [x] 9 Quality Gates DoD satisfied
|
|
144
144
|
{checklist_trace}{evidence_markdown}
|
|
145
145
|
"""
|
|
146
146
|
return {
|