synapse-hub 2.5.0 → 2.7.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 +17 -0
- package/.agents/agents/orchestrator.md +20 -2
- package/.agents/agents/pom-crafter.md +20 -0
- package/.agents/agents/quality-gatekeeper.md +20 -2
- package/.agents/agents/test-runner.md +16 -0
- package/.agents/rules/context-engineering.md +22 -102
- package/.agents/rules/git-push-protocol.md +1 -1
- package/.agents/rules/graphify.md +2 -0
- package/.agents/rules/mandatory-playwright-live.md +9 -9
- package/.agents/rules/mobile_appium_rules.md +27 -116
- package/.agents/rules/performance_testing_rules.md +18 -62
- package/.agents/rules/skill-precedence.md +22 -42
- package/.agents/rules/systematic-debugging.md +10 -29
- package/.agents/skills/actor-qa-swarm/SKILL.md +77 -0
- package/.agents/skills/actor-qa-swarm/examples/broker_sharding_sample.json +12 -0
- package/.agents/skills/agentless-qa-repair/SKILL.md +69 -0
- package/.agents/skills/agentless-qa-repair/examples/healing_report_sample.json +17 -0
- package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +1 -1
- package/.agents/skills/clean-pom-crafter/SKILL.md +2 -2
- package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +4 -4
- package/.agents/skills/event-stream-qa-orchestrator/SKILL.md +79 -0
- package/.agents/skills/event-stream-qa-orchestrator/examples/timeline_sample.jsonl +2 -0
- package/.agents/skills/failure-autopsy-and-healing/SKILL.md +2 -2
- package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +6 -21
- package/.agents/skills/katalon-cli-runner/SKILL.md +1 -1
- package/.agents/skills/mipro-prompt-compiler/SKILL.md +59 -0
- package/.agents/skills/mipro-prompt-compiler/examples/compiled_module_sample.json +22 -0
- package/.agents/skills/qa-aci-interface/SKILL.md +67 -0
- package/.agents/skills/qa-aci-interface/examples/surgical_edit_sample.json +12 -0
- package/.agents/skills/qa-memory-os/SKILL.md +80 -0
- package/.agents/skills/qa-memory-os/examples/archival_memory_sample.json +21 -0
- package/.agents/skills/review-spec/SKILL.md +60 -0
- package/.agents/skills/review-spec/examples/sample_spec_review.md +33 -0
- package/.agents/skills/synthetic-test-data-generator/SKILL.md +2 -2
- package/.agents/skills/token-and-context-optimizer/references/context_engineering_guide.md +49 -0
- package/.agents/skills/tot-exploratory-testing/SKILL.md +59 -0
- package/.agents/skills/tot-exploratory-testing/examples/tot_graph_sample.json +35 -0
- package/.agents/skills/wcag-audit-patterns/SKILL.md +2 -2
- package/.agents/skills/web-agent-gym-benchmarking/SKILL.md +62 -0
- package/.agents/skills/web-agent-gym-benchmarking/examples/benchmark_report_sample.json +22 -0
- package/AGENTS.md +6 -1
- package/CLAUDE.md +1 -1
- package/NOTICE +40 -4
- package/README.en.md +27 -11
- package/README.md +28 -12
- package/docs/ARCHITECTURE.md +39 -11
- package/docs/adopted-ecosystem-tools.md +9 -0
- package/docs/research/EXTERNAL_AGENT_SKILLS_SURVEY.md +1062 -0
- package/docs/research/agent_skill_training_analysis.md +1357 -0
- package/package.json +1 -1
- package/skills_manifest.json +88 -7
- package/synapse.config.json +3 -2
- package/templates/ai_bridges/CLAUDE.md +1 -1
- package/templates/welcome.html.tmpl +34 -25
- package/tools/TOOLS_RUNBOOK.md +130 -1
- package/tools/__init__.py +1 -1
- package/tools/_openapi_parser.py +158 -0
- package/tools/agentless_patcher.py +417 -0
- package/tools/analyze_project.py +9 -6
- package/tools/auto_heal.py +29 -0
- package/tools/auto_heal_reflexion.py +172 -0
- package/tools/autogen_qa_broker.py +318 -0
- package/tools/browser_helpers.js +57 -2
- package/tools/browsergym_eval.py +237 -0
- package/tools/ci_healing_hook.py +1 -1
- package/tools/cli.py +3 -3
- package/tools/dashboard_generator.py +29 -13
- package/tools/db_sandbox.py +4 -0
- package/tools/dspy_qa_signatures.py +357 -0
- package/tools/heal_pr_automator.py +25 -0
- package/tools/interview_story.py +117 -0
- package/tools/lint_ai_docs.py +1 -1
- package/tools/mcp_excel_server.py +1 -1
- package/tools/mcp_server.py +1 -1
- package/tools/mipro_assertion_tuner.py +207 -0
- package/tools/pinpoint_failure.py +12 -0
- package/tools/project_state.py +4 -0
- package/tools/qa_event_stream.py +336 -0
- package/tools/reversible_sandbox.py +161 -0
- package/tools/safety_firewall.py +28 -0
- package/tools/skill_collision_guard.py +231 -0
- package/tools/skill_vault.py +343 -0
- package/tools/swe_qa_aci.py +369 -0
- package/tools/synapse_qa_bench.py +190 -0
- package/tools/sync_agent_rules.py +1 -1
- package/tools/test_memory_os.py +409 -0
- package/tools/textgrad_mutation_optimizer.py +234 -0
- package/tools/tot_exploratory_tester.py +240 -0
- package/tools/update_sentinel.py +3 -3
- package/tools/verify_all.py +35 -4
- package/tools/watch_mode.py +1 -1
- package/tools/welcome_page.py +2 -2
|
@@ -0,0 +1,240 @@
|
|
|
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
|
+
Tree/Graph-of-Thoughts Exploratory Testing Engine (Princeton ToT & ETH GoT Pattern)
|
|
8
|
+
----------------------------------------------------------------------------------
|
|
9
|
+
Expands linear user stories into deliberative non-linear exploration trees:
|
|
10
|
+
1. Multi-Branch Deliberation: Generates Happy Path, Boundary/Race, and Negative/Chaos branches.
|
|
11
|
+
2. Risk-Scored Beam Search: Evaluates thought states and prunes low-risk tautological paths.
|
|
12
|
+
3. Clean POM Synthesis: Produces structured test scenarios ready for Clean POM Page Classes.
|
|
13
|
+
4. Multi-Hypothesis RCA: Diagnoses test failures across competing failure hypotheses (DOM_TIMEOUT, ASYNC_RACE, DB_LOCK, BACKEND_500).
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python tools/tot_exploratory_tester.py expand-story --story-file docs/stories/US_PAYMENT.md --max-depth 3 --beam-width 3
|
|
17
|
+
python tools/tot_exploratory_tester.py rca-hypotheses --error-log reports/failed.log
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
import re
|
|
23
|
+
import json
|
|
24
|
+
import time
|
|
25
|
+
import argparse
|
|
26
|
+
from typing import Dict, Any, List, Optional, Tuple
|
|
27
|
+
|
|
28
|
+
# Enforce UTF-8 stdout encoding
|
|
29
|
+
if hasattr(sys.stdout, 'reconfigure'):
|
|
30
|
+
try:
|
|
31
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
32
|
+
sys.stderr.reconfigure(encoding='utf-8')
|
|
33
|
+
except Exception:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TotExploratoryTester:
|
|
38
|
+
"""Tree-of-Thoughts Engine for Exploratory QA and Root Cause Analysis."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, repo_root: Optional[str] = None):
|
|
41
|
+
self.repo_root = repo_root or os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
42
|
+
|
|
43
|
+
def expand_story(self, story_content: str, max_depth: int = 3, beam_width: int = 3) -> Dict[str, Any]:
|
|
44
|
+
"""Decomposes story into a 3-branch Tree of Thoughts with risk scores."""
|
|
45
|
+
# Extract title and criteria
|
|
46
|
+
lines = [l.strip() for l in story_content.splitlines() if l.strip()]
|
|
47
|
+
title = lines[0] if lines else "Untitled User Story"
|
|
48
|
+
if title.startswith("#"):
|
|
49
|
+
title = title.lstrip("#").strip()
|
|
50
|
+
|
|
51
|
+
# Extract keywords
|
|
52
|
+
keywords = re.findall(r'\b[a-zA-Z]{4,}\b', story_content.lower())
|
|
53
|
+
is_checkout = any(k in keywords for k in ["cart", "checkout", "pay", "order", "price"])
|
|
54
|
+
is_auth = any(k in keywords for k in ["login", "auth", "token", "password", "sso"])
|
|
55
|
+
|
|
56
|
+
context_domain = "FINANCIAL_CHECKOUT" if is_checkout else ("AUTH_SESSION" if is_auth else "GENERAL_CRUD")
|
|
57
|
+
|
|
58
|
+
# 3 Branches:
|
|
59
|
+
# 1. Happy Path
|
|
60
|
+
# 2. Boundary / Session Interruption / Race Condition
|
|
61
|
+
# 3. Negative / Chaos / Backend Fault
|
|
62
|
+
branches = [
|
|
63
|
+
{
|
|
64
|
+
"branch_id": "BRANCH_HAPPY_PATH",
|
|
65
|
+
"name": "Standard Happy Business Path",
|
|
66
|
+
"risk_score": 0.25,
|
|
67
|
+
"thoughts": [
|
|
68
|
+
{"step": 1, "thought": "Navigate to initial entity view and ensure clean pre-conditions."},
|
|
69
|
+
{"step": 2, "thought": "Populate valid payload attributes and trigger submit action."},
|
|
70
|
+
{"step": 3, "thought": "Verify success confirmation modal and assert database record creation."}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"branch_id": "BRANCH_BOUNDARY_RACE",
|
|
75
|
+
"name": "Boundary, Session Interruption & Concurrency Path",
|
|
76
|
+
"risk_score": 0.88,
|
|
77
|
+
"thoughts": [
|
|
78
|
+
{"step": 1, "thought": "Simulate session expiration or token invalidation mid-flow."},
|
|
79
|
+
{"step": 2, "thought": "Perform rapid double-click on submission action to probe race condition."},
|
|
80
|
+
{"step": 3, "thought": "Assert idempotency: strictly 1 transaction created, duplicate blocked gracefully."}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"branch_id": "BRANCH_NEGATIVE_CHAOS",
|
|
85
|
+
"name": "Negative Error Handling & Chaos Fault Path",
|
|
86
|
+
"risk_score": 0.72,
|
|
87
|
+
"thoughts": [
|
|
88
|
+
{"step": 1, "thought": "Inject malformed/boundary input payload exceeding maximum character limits."},
|
|
89
|
+
{"step": 2, "thought": "Simulate backend 500 error or database connection timeout via route stub."},
|
|
90
|
+
{"step": 3, "thought": "Assert user-friendly error toast, zero data corruption, and retry availability."}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
# Beam search selection: sort by risk score descending and take beam_width
|
|
96
|
+
sorted_branches = sorted(branches, key=lambda b: b["risk_score"], reverse=True)
|
|
97
|
+
selected_branches = sorted_branches[:beam_width]
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
"status": "PASS",
|
|
101
|
+
"story_title": title,
|
|
102
|
+
"domain": context_domain,
|
|
103
|
+
"max_depth": max_depth,
|
|
104
|
+
"beam_width": beam_width,
|
|
105
|
+
"total_branches_explored": len(branches),
|
|
106
|
+
"highest_risk_branch": selected_branches[0]["branch_id"],
|
|
107
|
+
"branches": selected_branches,
|
|
108
|
+
"clean_pom_recommendations": [
|
|
109
|
+
f"Implement {context_domain}Page extending BasePage",
|
|
110
|
+
"Encapsulate double-click debounce in clickSubmitSafe()",
|
|
111
|
+
"Assert boundary toast in verifyErrorMessageDisplayed()"
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
def rca_hypotheses(self, error_log: str, hypotheses: Optional[List[str]] = None) -> Dict[str, Any]:
|
|
116
|
+
"""Performs multi-hypothesis Root Cause Analysis on test failures."""
|
|
117
|
+
if not hypotheses:
|
|
118
|
+
hypotheses = ["DOM_TIMEOUT", "ASYNC_RACE", "DB_LOCK", "BACKEND_500", "STALE_SELECTOR"]
|
|
119
|
+
|
|
120
|
+
log_lower = error_log.lower()
|
|
121
|
+
scored_hypotheses = []
|
|
122
|
+
|
|
123
|
+
for hyp in hypotheses:
|
|
124
|
+
score = 0.0
|
|
125
|
+
evidence = []
|
|
126
|
+
|
|
127
|
+
if hyp == "DOM_TIMEOUT":
|
|
128
|
+
if "timed out" in log_lower or "waitfortimeout" in log_lower or "5000ms" in log_lower:
|
|
129
|
+
score += 0.85
|
|
130
|
+
evidence.append("Found timeout or waiting duration signature in log")
|
|
131
|
+
if "element is not visible" in log_lower or "tobevisible" in log_lower:
|
|
132
|
+
score += 0.10
|
|
133
|
+
evidence.append("Element visibility expectation failed")
|
|
134
|
+
|
|
135
|
+
elif hyp == "ASYNC_RACE":
|
|
136
|
+
if "click intercepted" in log_lower or "animation" in log_lower or "detached" in log_lower:
|
|
137
|
+
score += 0.90
|
|
138
|
+
evidence.append("Overlay or detachment signature points to async race condition")
|
|
139
|
+
if "networkidle" in log_lower or "pending" in log_lower:
|
|
140
|
+
score += 0.15
|
|
141
|
+
evidence.append("Pending network requests active during action")
|
|
142
|
+
|
|
143
|
+
elif hyp == "DB_LOCK":
|
|
144
|
+
if "deadlock" in log_lower or "lock" in log_lower or "sql" in log_lower or "unique constraint" in log_lower:
|
|
145
|
+
score += 0.88
|
|
146
|
+
evidence.append("Database lock or constraint collision detected in trace")
|
|
147
|
+
|
|
148
|
+
elif hyp == "BACKEND_500":
|
|
149
|
+
if re.search(r'\b500\b', log_lower) and not re.search(r'\b500\d+ms\b', log_lower) and ("http" in log_lower or "status" in log_lower or "server error" in log_lower or "internal" in log_lower):
|
|
150
|
+
score += 0.95
|
|
151
|
+
evidence.append("HTTP 500 status code explicitly logged")
|
|
152
|
+
elif "internal server error" in log_lower:
|
|
153
|
+
score += 0.95
|
|
154
|
+
evidence.append("Internal Server Error explicitly logged")
|
|
155
|
+
|
|
156
|
+
elif hyp == "STALE_SELECTOR":
|
|
157
|
+
if "locator" in log_lower or "selector" in log_lower or "xpath" in log_lower:
|
|
158
|
+
score += 0.70
|
|
159
|
+
evidence.append("Locator or selector syntax mentioned in failure message")
|
|
160
|
+
|
|
161
|
+
# Baseline confidence
|
|
162
|
+
if not evidence:
|
|
163
|
+
score = 0.10
|
|
164
|
+
evidence.append("No direct signature found; baseline background likelihood")
|
|
165
|
+
|
|
166
|
+
scored_hypotheses.append({
|
|
167
|
+
"hypothesis": hyp,
|
|
168
|
+
"confidence_score": round(min(1.0, score), 3),
|
|
169
|
+
"evidence": evidence
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
scored_hypotheses.sort(key=lambda h: h["confidence_score"], reverse=True)
|
|
173
|
+
winner = scored_hypotheses[0]
|
|
174
|
+
|
|
175
|
+
recommendations = {
|
|
176
|
+
"DOM_TIMEOUT": "Replace hardcoded delay with page.waitForLoadState('networkidle') or element.waitFor({state: 'visible'})",
|
|
177
|
+
"ASYNC_RACE": "Use clickSafe() helper with overlay detachment waiting or dispatchEvent('click')",
|
|
178
|
+
"DB_LOCK": "Randomize entity code prefix via DataGenerator.uniqueCode('AUTO_') and enforce teardown cleanup",
|
|
179
|
+
"BACKEND_500": "Inspect backend server logs for uncaught 500 NullPointerException or DB connection pool exhaustion",
|
|
180
|
+
"STALE_SELECTOR": "Run tools/agentless_patcher.py heal-failure to update stale attribute to ARIA role"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
"status": "PASS",
|
|
185
|
+
"primary_root_cause": winner["hypothesis"],
|
|
186
|
+
"confidence": winner["confidence_score"],
|
|
187
|
+
"recommended_fix": recommendations.get(winner["hypothesis"], "Review stacktrace with team"),
|
|
188
|
+
"ranked_hypotheses": scored_hypotheses
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def main():
|
|
193
|
+
parser = argparse.ArgumentParser(description="Tree-of-Thoughts Exploratory Testing Engine")
|
|
194
|
+
subparsers = parser.add_subparsers(dest="subcommand", help="Subcommand to execute")
|
|
195
|
+
|
|
196
|
+
# expand-story
|
|
197
|
+
exp_p = subparsers.add_parser("expand-story", help="Expand User Story into Tree of Thoughts")
|
|
198
|
+
exp_p.add_argument("--story-file", required=True, help="Path to story markdown file or text string")
|
|
199
|
+
exp_p.add_argument("--max-depth", type=int, default=3, help="Max thought tree depth")
|
|
200
|
+
exp_p.add_argument("--beam-width", type=int, default=3, help="Beam search width")
|
|
201
|
+
exp_p.add_argument("--out-graph", help="Optional path to output graph JSON")
|
|
202
|
+
|
|
203
|
+
# rca-hypotheses
|
|
204
|
+
rca_p = subparsers.add_parser("rca-hypotheses", help="Diagnose failure via multi-hypothesis RCA")
|
|
205
|
+
rca_p.add_argument("--error-log", required=True, help="Path to error log or log string")
|
|
206
|
+
rca_p.add_argument("--hypotheses", help="Comma-separated hypotheses list")
|
|
207
|
+
|
|
208
|
+
args = parser.parse_args()
|
|
209
|
+
tester = TotExploratoryTester()
|
|
210
|
+
|
|
211
|
+
if args.subcommand == "expand-story":
|
|
212
|
+
content = args.story_file
|
|
213
|
+
if os.path.exists(args.story_file):
|
|
214
|
+
with open(args.story_file, "r", encoding="utf-8", errors="replace") as f:
|
|
215
|
+
content = f.read()
|
|
216
|
+
res = tester.expand_story(content, max_depth=args.max_depth, beam_width=args.beam_width)
|
|
217
|
+
if args.out_graph:
|
|
218
|
+
os.makedirs(os.path.dirname(os.path.abspath(args.out_graph)), exist_ok=True)
|
|
219
|
+
with open(args.out_graph, "w", encoding="utf-8") as f:
|
|
220
|
+
json.dump(res, f, indent=2)
|
|
221
|
+
print(json.dumps(res, indent=2))
|
|
222
|
+
sys.exit(0)
|
|
223
|
+
|
|
224
|
+
elif args.subcommand == "rca-hypotheses":
|
|
225
|
+
log_content = args.error_log
|
|
226
|
+
if os.path.exists(args.error_log):
|
|
227
|
+
with open(args.error_log, "r", encoding="utf-8", errors="replace") as f:
|
|
228
|
+
log_content = f.read()
|
|
229
|
+
hyp_list = [h.strip() for h in args.hypotheses.split(",")] if args.hypotheses else None
|
|
230
|
+
res = tester.rca_hypotheses(error_log=log_content, hypotheses=hyp_list)
|
|
231
|
+
print(json.dumps(res, indent=2))
|
|
232
|
+
sys.exit(0)
|
|
233
|
+
|
|
234
|
+
else:
|
|
235
|
+
parser.print_help()
|
|
236
|
+
sys.exit(1)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
if __name__ == "__main__":
|
|
240
|
+
main()
|
package/tools/update_sentinel.py
CHANGED
|
@@ -65,7 +65,7 @@ def get_local_version():
|
|
|
65
65
|
try:
|
|
66
66
|
with open(pkg_file, "r", encoding="utf-8") as f:
|
|
67
67
|
data = json.load(f)
|
|
68
|
-
return data.get("version", "2.
|
|
68
|
+
return data.get("version", "2.7.0")
|
|
69
69
|
except (OSError, json.JSONDecodeError):
|
|
70
70
|
data = {}
|
|
71
71
|
|
|
@@ -74,11 +74,11 @@ def get_local_version():
|
|
|
74
74
|
try:
|
|
75
75
|
with open(manifest_file, "r", encoding="utf-8") as f:
|
|
76
76
|
data = json.load(f)
|
|
77
|
-
return data.get("version", "2.
|
|
77
|
+
return data.get("version", "2.7.0")
|
|
78
78
|
except (OSError, json.JSONDecodeError):
|
|
79
79
|
data = {}
|
|
80
80
|
|
|
81
|
-
return "2.
|
|
81
|
+
return "2.7.0"
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
def fetch_remote_version():
|
package/tools/verify_all.py
CHANGED
|
@@ -18,6 +18,7 @@ Verifies:
|
|
|
18
18
|
Gate 6: Credential Security: No plaintext passwords in Profiles/default.glbl or repository.
|
|
19
19
|
Gate 7: Static Defect Sentinel: Meta Infer-style AST scan for fake passes and empty catches.
|
|
20
20
|
Gate 8: Syntactic Micro-Mutation Sentinel: Injects syntactic faults to eliminate tautological tests (Mutation Score >= 80%).
|
|
21
|
+
Gate 9: Tier-2 Skill Collision Guard: Addy Osmani offline TF-IDF cosine similarity check (similarity < 0.75).
|
|
21
22
|
|
|
22
23
|
Supports:
|
|
23
24
|
- Hub Mode: Verifies the centralized QA Hub / skills repository integrity.
|
|
@@ -194,7 +195,7 @@ MOJIBAKE_INDICATORS = (
|
|
|
194
195
|
|
|
195
196
|
def gate_1_bom_check(repo_root, mode="AUTO"):
|
|
196
197
|
print("\n[GATE 1] Scanning UTF-8 No BOM and Encoding Integrity across repository...")
|
|
197
|
-
ignored_dirs = {".git", ".gradle", "node_modules", "allure-results", "graphify-out", "__pycache__", "build", "dist", "claude-ecosystem-repos"}
|
|
198
|
+
ignored_dirs = {".git", ".gradle", "node_modules", "allure-results", "graphify-out", "__pycache__", "build", "dist", "claude-ecosystem-repos", "external_repos", "teamwork"}
|
|
198
199
|
ignored_files = {"verify_all.py", "test_tools.py"}
|
|
199
200
|
bom_violations = []
|
|
200
201
|
mojibake_violations = []
|
|
@@ -244,7 +245,7 @@ def gate_2_path_portability(repo_root, mode="AUTO"):
|
|
|
244
245
|
ignored_dirs = {
|
|
245
246
|
".git", ".gradle", "node_modules", "allure-results", "Screenshots",
|
|
246
247
|
"Reports", "reports", "TestReports", "testreports", "bin", "Libs", ".settings", "graphify-out",
|
|
247
|
-
"__pycache__", "agent_qa.egg-info", "dist", "build", "claude-ecosystem-repos"
|
|
248
|
+
"__pycache__", "agent_qa.egg-info", "dist", "build", "claude-ecosystem-repos", "external_repos", "teamwork"
|
|
248
249
|
}
|
|
249
250
|
ignored_files = {
|
|
250
251
|
".project", ".classpath", ".DS_Store", "memory_cache.db",
|
|
@@ -441,7 +442,7 @@ def gate_6_credential_security(repo_root, mode="AUTO"):
|
|
|
441
442
|
ignored_dirs = {
|
|
442
443
|
".git", ".gradle", "node_modules", "allure-results", "Screenshots",
|
|
443
444
|
"Reports", "reports", "TestReports", "testreports", "bin", "Libs", ".settings", "graphify-out",
|
|
444
|
-
"__pycache__", "agent_qa.egg-info", "dist", "build", "claude-ecosystem-repos"
|
|
445
|
+
"__pycache__", "agent_qa.egg-info", "dist", "build", "claude-ecosystem-repos", "external_repos", "teamwork"
|
|
445
446
|
}
|
|
446
447
|
|
|
447
448
|
for root, dirs, files in os.walk(repo_root):
|
|
@@ -480,7 +481,7 @@ def check_python_ast_integrity(repo_root):
|
|
|
480
481
|
"""
|
|
481
482
|
builtin_names = set(dir(builtins)) | {'__file__', '__name__', '__doc__', '__package__'}
|
|
482
483
|
py_files = []
|
|
483
|
-
ignored = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'claude-ecosystem-repos', 'build', 'dist', '.gradle'}
|
|
484
|
+
ignored = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'claude-ecosystem-repos', 'build', 'dist', '.gradle', 'external_repos', 'teamwork'}
|
|
484
485
|
|
|
485
486
|
for root, dirs, files in os.walk(repo_root):
|
|
486
487
|
dirs[:] = [d for d in dirs if d not in ignored]
|
|
@@ -795,6 +796,35 @@ def gate_8_micro_mutator(repo_root, mode="AUTO", test_cmd=""):
|
|
|
795
796
|
return True
|
|
796
797
|
|
|
797
798
|
|
|
799
|
+
def gate_9_skill_collision(repo_root, mode="AUTO"):
|
|
800
|
+
print("\n[GATE 9] Running Tier-2 Skill Routing & Collision Guard (Addy Osmani Pattern)...")
|
|
801
|
+
guard_script = os.path.join(SCRIPT_DIR, "skill_collision_guard.py")
|
|
802
|
+
if not os.path.exists(guard_script):
|
|
803
|
+
guard_script = os.path.join(repo_root, "tools", "skill_collision_guard.py")
|
|
804
|
+
if not os.path.exists(guard_script):
|
|
805
|
+
print("[FAIL] skill_collision_guard.py not found in tools/!")
|
|
806
|
+
return False
|
|
807
|
+
|
|
808
|
+
skills_dir = os.path.join(repo_root, ".agents", "skills")
|
|
809
|
+
if not os.path.exists(skills_dir):
|
|
810
|
+
print("[PASS] Target project mode: .agents/skills/ not present (SKIPPED).")
|
|
811
|
+
return True
|
|
812
|
+
|
|
813
|
+
try:
|
|
814
|
+
res = subprocess.run([sys.executable, guard_script, "--dir", skills_dir, "--threshold", "0.75"],
|
|
815
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=60.0)
|
|
816
|
+
except subprocess.TimeoutExpired:
|
|
817
|
+
print("[FAIL] skill_collision_guard.py timed out after 60s!")
|
|
818
|
+
return False
|
|
819
|
+
|
|
820
|
+
if res.returncode != 0:
|
|
821
|
+
print(res.stdout)
|
|
822
|
+
print(res.stderr)
|
|
823
|
+
return False
|
|
824
|
+
print("[PASS] 100% Verified: 0 skill description collisions detected (similarity < 0.75).")
|
|
825
|
+
return True
|
|
826
|
+
|
|
827
|
+
|
|
798
828
|
def load_synapse_config(repo_root=None, config_path=None):
|
|
799
829
|
"""Loads configuration from synapse.config.json if present."""
|
|
800
830
|
if config_path and os.path.exists(config_path):
|
|
@@ -855,6 +885,7 @@ def run_all_gates(repo_root, mode="AUTO", test_cmd="", output_format="text", con
|
|
|
855
885
|
("gate_6_credential_security", "Gate 6: Credential Security", gate_6_credential_security),
|
|
856
886
|
("gate_7_infer_linter", "Gate 7: Static Defect Sentinel", gate_7_infer_linter),
|
|
857
887
|
("gate_8_micro_mutator", "Gate 8: Assertion Sensitivity & Syntactic Mutation Sentinel", lambda r, mode: gate_8_micro_mutator(r, mode=mode, test_cmd=test_cmd)),
|
|
888
|
+
("gate_9_skill_collision", "Gate 9: Tier-2 Skill Routing & Collision Guard", gate_9_skill_collision),
|
|
858
889
|
]
|
|
859
890
|
|
|
860
891
|
all_passed = True
|
package/tools/watch_mode.py
CHANGED
|
@@ -46,7 +46,7 @@ IGNORED_DIRS = {
|
|
|
46
46
|
".git", ".gradle", "node_modules", "allure-results", "Screenshots",
|
|
47
47
|
"Reports", "reports", "TestReports", "testreports", "bin", "Libs", ".settings",
|
|
48
48
|
"graphify-out", "__pycache__", "agent_qa.egg-info", "dist", "build", ".pytest_cache",
|
|
49
|
-
"claude-ecosystem-repos"
|
|
49
|
+
"claude-ecosystem-repos", "external_repos", "teamwork"
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
IGNORED_FILES = {
|
package/tools/welcome_page.py
CHANGED
|
@@ -17,7 +17,7 @@ Features:
|
|
|
17
17
|
- Interactive tabs covering the 4 Core Pillars of QA Intelligence.
|
|
18
18
|
- Interactive CLI Cheatsheet with 1-click clipboard copy.
|
|
19
19
|
- Comparison matrix vs existing industry tools (ESLint, Stryker, Allure, Healenium).
|
|
20
|
-
- 6 Subagent Swarm Profiles &
|
|
20
|
+
- 6 Subagent Swarm Profiles & 10 Quality Gates DoD showcase.
|
|
21
21
|
- Automatic browser launching on setup, pull, or CLI dispatch.
|
|
22
22
|
"""
|
|
23
23
|
|
|
@@ -48,7 +48,7 @@ def get_hub_metadata() -> Dict[str, Any]:
|
|
|
48
48
|
"""Retrieves version and catalog count from skills_manifest.json."""
|
|
49
49
|
manifest_path = os.path.join(HUB_ROOT, "skills_manifest.json")
|
|
50
50
|
meta = {
|
|
51
|
-
"version": "2.
|
|
51
|
+
"version": "2.7.0",
|
|
52
52
|
"totalSkills": 42,
|
|
53
53
|
"author": "Thế Vị (@TeeVee998)",
|
|
54
54
|
"repo": "https://github.com/TeeVee998/Synapse-Hub"
|