hexastack-qual 0.7.0__py3-none-any.whl
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.
- hexastack_qual/__init__.py +18 -0
- hexastack_qual/adapters/__init__.py +14 -0
- hexastack_qual/adapters/cqrs/__init__.py +50 -0
- hexastack_qual/adapters/cqrs/commands.py +88 -0
- hexastack_qual/adapters/cqrs/handlers.py +187 -0
- hexastack_qual/adapters/cqrs/queries.py +90 -0
- hexastack_qual/adapters/events/__init__.py +13 -0
- hexastack_qual/adapters/events/publisher.py +105 -0
- hexastack_qual/adapters/hexaqual/__init__.py +14 -0
- hexastack_qual/adapters/hexaqual/runner.py +628 -0
- hexastack_qual/adapters/mcp/__init__.py +37 -0
- hexastack_qual/adapters/mcp/server.py +77 -0
- hexastack_qual/adapters/mcp/tools.py +351 -0
- hexastack_qual/adapters/ui/__init__.py +13 -0
- hexastack_qual/adapters/ui/panel.py +88 -0
- hexastack_qual/domain/__init__.py +54 -0
- hexastack_qual/domain/events.py +93 -0
- hexastack_qual/domain/exceptions.py +134 -0
- hexastack_qual/domain/models.py +296 -0
- hexastack_qual/infra/__init__.py +15 -0
- hexastack_qual/infra/bootstrap.py +117 -0
- hexastack_qual/infra/cli.py +75 -0
- hexastack_qual/ports/__init__.py +20 -0
- hexastack_qual/ports/auditor.py +122 -0
- hexastack_qual/ports/diagnostics.py +55 -0
- hexastack_qual/ports/mutator.py +66 -0
- hexastack_qual/ports/openssf.py +109 -0
- hexastack_qual-0.7.0.dist-info/METADATA +103 -0
- hexastack_qual-0.7.0.dist-info/RECORD +31 -0
- hexastack_qual-0.7.0.dist-info/WHEEL +4 -0
- hexastack_qual-0.7.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Hexastack Quality & Governance Adapter.
|
|
2
|
+
|
|
3
|
+
Bridges the Hexaqual engine into Hexastack applications, providing CQRS
|
|
4
|
+
dispatching, MCP server tools, reactive DevTools panels, and distributed event
|
|
5
|
+
publishing.
|
|
6
|
+
|
|
7
|
+
Notes/Architectural Intent:
|
|
8
|
+
Serves as the root package for hexastack-qual. Exports package version
|
|
9
|
+
and core domain models while preserving lazy loading for optional extras.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
__version__ = "0.7.0"
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"__version__",
|
|
18
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Adapters for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Houses concrete adapters for Hexaqual engine, CQRS message handlers, MCP
|
|
5
|
+
tool endpoints, NiceGUI DevTools panels, and distributed event publishers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from hexastack_qual.adapters.hexaqual.runner import HexaqualRunnerAdapter
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"HexaqualRunnerAdapter",
|
|
14
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""CQRS messages and handlers for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Exports Commands, Queries, and corresponding Handlers for dispatching
|
|
5
|
+
quality audits through the Hexastack ExecutionPipeline.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from hexastack_qual.adapters.cqrs.commands import (
|
|
11
|
+
FormatStatementsCommand,
|
|
12
|
+
RunMutationTestingCommand,
|
|
13
|
+
RunSanityCheckCommand,
|
|
14
|
+
SyncAgentAssetsCommand,
|
|
15
|
+
)
|
|
16
|
+
from hexastack_qual.adapters.cqrs.handlers import (
|
|
17
|
+
FormatStatementsHandler,
|
|
18
|
+
GetPrHealthHandler,
|
|
19
|
+
GetQualityScorecardHandler,
|
|
20
|
+
GetTestImpactHandler,
|
|
21
|
+
InspectMutantsHandler,
|
|
22
|
+
RunMutationTestingHandler,
|
|
23
|
+
RunSanityCheckHandler,
|
|
24
|
+
SyncAgentAssetsHandler,
|
|
25
|
+
)
|
|
26
|
+
from hexastack_qual.adapters.cqrs.queries import (
|
|
27
|
+
GetPrHealthQuery,
|
|
28
|
+
GetQualityScorecardQuery,
|
|
29
|
+
GetTestImpactQuery,
|
|
30
|
+
InspectMutantsQuery,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"FormatStatementsCommand",
|
|
35
|
+
"FormatStatementsHandler",
|
|
36
|
+
"GetPrHealthHandler",
|
|
37
|
+
"GetPrHealthQuery",
|
|
38
|
+
"GetQualityScorecardHandler",
|
|
39
|
+
"GetQualityScorecardQuery",
|
|
40
|
+
"GetTestImpactHandler",
|
|
41
|
+
"GetTestImpactQuery",
|
|
42
|
+
"InspectMutantsHandler",
|
|
43
|
+
"InspectMutantsQuery",
|
|
44
|
+
"RunMutationTestingCommand",
|
|
45
|
+
"RunMutationTestingHandler",
|
|
46
|
+
"RunSanityCheckCommand",
|
|
47
|
+
"RunSanityCheckHandler",
|
|
48
|
+
"SyncAgentAssetsCommand",
|
|
49
|
+
"SyncAgentAssetsHandler",
|
|
50
|
+
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""CQRS commands for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Encapsulates state-changing intent: running sanity gates, auto-fixing
|
|
5
|
+
statements, executing mutation tests, and syncing agent assets.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pydantic import ConfigDict, Field
|
|
11
|
+
|
|
12
|
+
from hexastack_core.domain import Command
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RunSanityCheckCommand(Command):
|
|
16
|
+
"""Command to execute full or scoped sanity check quality gate.
|
|
17
|
+
|
|
18
|
+
Notes/Architectural Intent:
|
|
19
|
+
Triggers cognitive complexity, test parity, and __all__ validation.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
model_config = ConfigDict(frozen=True)
|
|
23
|
+
|
|
24
|
+
package: str | None = Field(
|
|
25
|
+
default=None,
|
|
26
|
+
description="Target package name or None for workspace.",
|
|
27
|
+
)
|
|
28
|
+
skip_tests: bool = Field(
|
|
29
|
+
default=True,
|
|
30
|
+
description="Whether to skip unit test suites.",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class FormatStatementsCommand(Command):
|
|
35
|
+
"""Command to auto-format and sort __all__ export statements.
|
|
36
|
+
|
|
37
|
+
Notes/Architectural Intent:
|
|
38
|
+
Modifies target files in-place to enforce casefold ordering.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
model_config = ConfigDict(frozen=True)
|
|
42
|
+
|
|
43
|
+
package: str | None = Field(
|
|
44
|
+
default=None,
|
|
45
|
+
description="Target package name or None for workspace.",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RunMutationTestingCommand(Command):
|
|
50
|
+
"""Command to execute mutation testing across target components.
|
|
51
|
+
|
|
52
|
+
Notes/Architectural Intent:
|
|
53
|
+
Executes mutmut runner and compiles surviving mutant scorecards.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
model_config = ConfigDict(frozen=True)
|
|
57
|
+
|
|
58
|
+
package: str | None = Field(
|
|
59
|
+
default=None,
|
|
60
|
+
description="Target package name or None for workspace.",
|
|
61
|
+
)
|
|
62
|
+
reset: bool = Field(
|
|
63
|
+
default=False,
|
|
64
|
+
description="Whether to clear existing mutation cache before running.",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SyncAgentAssetsCommand(Command):
|
|
69
|
+
"""Command to re-synchronize universal AI agent rules and workflows.
|
|
70
|
+
|
|
71
|
+
Notes/Architectural Intent:
|
|
72
|
+
Materializes latest hexaqual agent assets into .agents/.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
model_config = ConfigDict(frozen=True)
|
|
76
|
+
|
|
77
|
+
dry_run: bool = Field(
|
|
78
|
+
default=False,
|
|
79
|
+
description="If True, verifies sync without writing files.",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
__all__ = [
|
|
84
|
+
"FormatStatementsCommand",
|
|
85
|
+
"RunMutationTestingCommand",
|
|
86
|
+
"RunSanityCheckCommand",
|
|
87
|
+
"SyncAgentAssetsCommand",
|
|
88
|
+
]
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""CQRS command and query handlers for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Connects CQRS message dispatching to QualityAuditorPort, MutationInspectorPort,
|
|
5
|
+
and PrDiagnosticPort, with optional event emission across EventBusPort.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from hexaqual.adapters.agents import FileSystemAgentAssetAdapter
|
|
13
|
+
from hexaqual.adapters.workspace import get_repo_root
|
|
14
|
+
|
|
15
|
+
from hexastack_qual.adapters.cqrs.commands import (
|
|
16
|
+
FormatStatementsCommand,
|
|
17
|
+
RunMutationTestingCommand,
|
|
18
|
+
RunSanityCheckCommand,
|
|
19
|
+
SyncAgentAssetsCommand,
|
|
20
|
+
)
|
|
21
|
+
from hexastack_qual.adapters.cqrs.queries import (
|
|
22
|
+
GetPrHealthQuery,
|
|
23
|
+
GetQualityScorecardQuery,
|
|
24
|
+
GetTestImpactQuery,
|
|
25
|
+
InspectMutantsQuery,
|
|
26
|
+
)
|
|
27
|
+
from hexastack_qual.domain.events import (
|
|
28
|
+
QualityGateFailedEvent,
|
|
29
|
+
StatementsFixedEvent,
|
|
30
|
+
)
|
|
31
|
+
from hexastack_qual.domain.models import (
|
|
32
|
+
MutantReport,
|
|
33
|
+
PrHealthSummary,
|
|
34
|
+
QualityScorecard,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from hexastack_cqrs.ports.buses import EventBusPort
|
|
39
|
+
from hexastack_qual.ports.auditor import QualityAuditorPort
|
|
40
|
+
from hexastack_qual.ports.diagnostics import PrDiagnosticPort
|
|
41
|
+
from hexastack_qual.ports.mutator import MutationInspectorPort
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class RunSanityCheckHandler:
|
|
45
|
+
"""Handler for RunSanityCheckCommand."""
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
auditor: QualityAuditorPort,
|
|
50
|
+
event_bus: EventBusPort | None = None,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Initialize handler with auditor port and optional event bus."""
|
|
53
|
+
self._auditor = auditor
|
|
54
|
+
self._event_bus = event_bus
|
|
55
|
+
|
|
56
|
+
async def __call__(self, command: RunSanityCheckCommand) -> QualityScorecard:
|
|
57
|
+
"""Execute sanity check and emit failure event if unhealthy."""
|
|
58
|
+
scorecard = self._auditor.run_sanity(
|
|
59
|
+
package=command.package,
|
|
60
|
+
skip_tests=command.skip_tests,
|
|
61
|
+
)
|
|
62
|
+
if not scorecard.is_healthy and self._event_bus:
|
|
63
|
+
failed_names = [
|
|
64
|
+
c.check_name for c in scorecard.checks if c.status == "fail"
|
|
65
|
+
]
|
|
66
|
+
event = QualityGateFailedEvent(
|
|
67
|
+
target=scorecard.target,
|
|
68
|
+
failed_checks=failed_names,
|
|
69
|
+
)
|
|
70
|
+
await self._event_bus.publish(event)
|
|
71
|
+
return scorecard
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class FormatStatementsHandler:
|
|
75
|
+
"""Handler for FormatStatementsCommand."""
|
|
76
|
+
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
auditor: QualityAuditorPort,
|
|
80
|
+
event_bus: EventBusPort | None = None,
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Initialize handler with auditor port and optional event bus."""
|
|
83
|
+
self._auditor = auditor
|
|
84
|
+
self._event_bus = event_bus
|
|
85
|
+
|
|
86
|
+
async def __call__(self, command: FormatStatementsCommand) -> int:
|
|
87
|
+
"""Fix statement formatting and emit event if files modified."""
|
|
88
|
+
modified_count = self._auditor.fix_statements(package=command.package)
|
|
89
|
+
if modified_count > 0 and self._event_bus:
|
|
90
|
+
event = StatementsFixedEvent(
|
|
91
|
+
target=command.package or "workspace",
|
|
92
|
+
files_modified=modified_count,
|
|
93
|
+
)
|
|
94
|
+
await self._event_bus.publish(event)
|
|
95
|
+
return modified_count
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class RunMutationTestingHandler:
|
|
99
|
+
"""Handler for RunMutationTestingCommand."""
|
|
100
|
+
|
|
101
|
+
def __init__(self, mutator: MutationInspectorPort) -> None:
|
|
102
|
+
"""Initialize handler with mutation inspector port."""
|
|
103
|
+
self._mutator = mutator
|
|
104
|
+
|
|
105
|
+
async def __call__(self, command: RunMutationTestingCommand) -> MutantReport:
|
|
106
|
+
"""Execute mutation testing runner."""
|
|
107
|
+
return self._mutator.run_mutation_testing(
|
|
108
|
+
package=command.package,
|
|
109
|
+
reset=command.reset,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class SyncAgentAssetsHandler:
|
|
114
|
+
"""Handler for SyncAgentAssetsCommand."""
|
|
115
|
+
|
|
116
|
+
async def __call__(self, command: SyncAgentAssetsCommand) -> int:
|
|
117
|
+
"""Synchronize universal AI agent rules and workflows."""
|
|
118
|
+
root = get_repo_root()
|
|
119
|
+
adapter = FileSystemAgentAssetAdapter()
|
|
120
|
+
res = adapter.sync_assets(root, dry_run=command.dry_run)
|
|
121
|
+
return res.created_count + res.updated_count
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class GetQualityScorecardHandler:
|
|
125
|
+
"""Handler for GetQualityScorecardQuery."""
|
|
126
|
+
|
|
127
|
+
def __init__(self, auditor: QualityAuditorPort) -> None:
|
|
128
|
+
"""Initialize handler with auditor port."""
|
|
129
|
+
self._auditor = auditor
|
|
130
|
+
|
|
131
|
+
async def __call__(self, query: GetQualityScorecardQuery) -> QualityScorecard:
|
|
132
|
+
"""Execute sanity check and return scorecard."""
|
|
133
|
+
return self._auditor.run_sanity(
|
|
134
|
+
package=query.package,
|
|
135
|
+
skip_tests=query.skip_tests,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class InspectMutantsHandler:
|
|
140
|
+
"""Handler for InspectMutantsQuery."""
|
|
141
|
+
|
|
142
|
+
def __init__(self, mutator: MutationInspectorPort) -> None:
|
|
143
|
+
"""Initialize handler with mutator port."""
|
|
144
|
+
self._mutator = mutator
|
|
145
|
+
|
|
146
|
+
async def __call__(self, query: InspectMutantsQuery) -> MutantReport:
|
|
147
|
+
"""Inspect surviving mutants."""
|
|
148
|
+
return self._mutator.inspect_surviving_mutants(
|
|
149
|
+
package=query.package,
|
|
150
|
+
actionable_only=query.actionable_only,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class GetTestImpactHandler:
|
|
155
|
+
"""Handler for GetTestImpactQuery."""
|
|
156
|
+
|
|
157
|
+
def __init__(self, diagnostics: PrDiagnosticPort) -> None:
|
|
158
|
+
"""Initialize handler with diagnostics port."""
|
|
159
|
+
self._diagnostics = diagnostics
|
|
160
|
+
|
|
161
|
+
async def __call__(self, query: GetTestImpactQuery) -> list[str]:
|
|
162
|
+
"""Compute impacted test suites."""
|
|
163
|
+
return self._diagnostics.get_test_impact(base_ref=query.base_ref)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class GetPrHealthHandler:
|
|
167
|
+
"""Handler for GetPrHealthQuery."""
|
|
168
|
+
|
|
169
|
+
def __init__(self, diagnostics: PrDiagnosticPort) -> None:
|
|
170
|
+
"""Initialize handler with diagnostics port."""
|
|
171
|
+
self._diagnostics = diagnostics
|
|
172
|
+
|
|
173
|
+
async def __call__(self, query: GetPrHealthQuery) -> PrHealthSummary:
|
|
174
|
+
"""Inspect pull request diagnostic health."""
|
|
175
|
+
return self._diagnostics.get_pr_health(pr_number=query.pr_number)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
__all__ = [
|
|
179
|
+
"FormatStatementsHandler",
|
|
180
|
+
"GetPrHealthHandler",
|
|
181
|
+
"GetQualityScorecardHandler",
|
|
182
|
+
"GetTestImpactHandler",
|
|
183
|
+
"InspectMutantsHandler",
|
|
184
|
+
"RunMutationTestingHandler",
|
|
185
|
+
"RunSanityCheckHandler",
|
|
186
|
+
"SyncAgentAssetsHandler",
|
|
187
|
+
]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""CQRS queries for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Encapsulates read-only inspections for quality scorecards, mutant reports,
|
|
5
|
+
git test impact, and PR diagnostics.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pydantic import ConfigDict, Field
|
|
11
|
+
|
|
12
|
+
from hexastack_core.domain import Query
|
|
13
|
+
from hexastack_qual.domain.models import (
|
|
14
|
+
MutantReport,
|
|
15
|
+
PrHealthSummary,
|
|
16
|
+
QualityScorecard,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GetQualityScorecardQuery(Query[QualityScorecard]):
|
|
21
|
+
"""Query to retrieve quality health metrics and sanity status.
|
|
22
|
+
|
|
23
|
+
Notes/Architectural Intent:
|
|
24
|
+
Produces a comprehensive scorecard without side-effects.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
model_config = ConfigDict(frozen=True)
|
|
28
|
+
|
|
29
|
+
package: str | None = Field(
|
|
30
|
+
default=None,
|
|
31
|
+
description="Target package name or None for workspace.",
|
|
32
|
+
)
|
|
33
|
+
skip_tests: bool = Field(
|
|
34
|
+
default=True,
|
|
35
|
+
description="Whether to skip unit test suites.",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class InspectMutantsQuery(Query[MutantReport]):
|
|
40
|
+
"""Query to inspect surviving mutants and triage classifications.
|
|
41
|
+
|
|
42
|
+
Notes/Architectural Intent:
|
|
43
|
+
Reads mutation cache and classifies surviving mutants without running tests.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
model_config = ConfigDict(frozen=True)
|
|
47
|
+
|
|
48
|
+
package: str | None = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="Target package name or None for workspace.",
|
|
51
|
+
)
|
|
52
|
+
actionable_only: bool = Field(
|
|
53
|
+
default=True,
|
|
54
|
+
description="If True, filters only critical actionable mutants.",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class GetTestImpactQuery(Query[list[str]]):
|
|
59
|
+
"""Query to compute test suites impacted by git diff changes.
|
|
60
|
+
|
|
61
|
+
Notes/Architectural Intent:
|
|
62
|
+
Identifies impacted test targets to enable smart scoped testing.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
model_config = ConfigDict(frozen=True)
|
|
66
|
+
|
|
67
|
+
base_ref: str = Field(
|
|
68
|
+
default="origin/main",
|
|
69
|
+
description="Git base reference or branch.",
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class GetPrHealthQuery(Query[PrHealthSummary]):
|
|
74
|
+
"""Query to inspect pull request CI checks, CodeQL alerts, and review threads.
|
|
75
|
+
|
|
76
|
+
Notes/Architectural Intent:
|
|
77
|
+
Fetches GitHub PR diagnostic state.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(frozen=True)
|
|
81
|
+
|
|
82
|
+
pr_number: int = Field(description="GitHub pull request number.")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
__all__ = [
|
|
86
|
+
"GetPrHealthQuery",
|
|
87
|
+
"GetQualityScorecardQuery",
|
|
88
|
+
"GetTestImpactQuery",
|
|
89
|
+
"InspectMutantsQuery",
|
|
90
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Event publisher adapters for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Exports QualityEventPublisherAdapter for CQRS event bus broadcasting.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from hexastack_qual.adapters.events.publisher import QualityEventPublisherAdapter
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"QualityEventPublisherAdapter",
|
|
13
|
+
]
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Event publisher adapter for hexastack-qual domain events.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Provides convenience methods for emitting quality gate failures, mutant
|
|
5
|
+
survival notices, and asset drift notifications across the CQRS EventBusPort.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from hexastack_qual.domain.events import (
|
|
13
|
+
AgentAssetDriftDetectedEvent,
|
|
14
|
+
CriticalMutantSurvivingEvent,
|
|
15
|
+
QualityGateFailedEvent,
|
|
16
|
+
StatementsFixedEvent,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from hexastack_cqrs.ports.buses import EventBusPort
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class QualityEventPublisherAdapter:
|
|
24
|
+
"""Adapter publishing quality domain events across the CQRS event bus.
|
|
25
|
+
|
|
26
|
+
Notes/Architectural Intent:
|
|
27
|
+
Encapsulates event instantiation and publishing to decouple caller logic
|
|
28
|
+
from specific event models.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, event_bus: EventBusPort) -> None:
|
|
32
|
+
"""Initialize publisher with event bus.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
event_bus: The CQRS EventBusPort implementation.
|
|
36
|
+
"""
|
|
37
|
+
self._event_bus = event_bus
|
|
38
|
+
|
|
39
|
+
def publish_quality_gate_failed(
|
|
40
|
+
self,
|
|
41
|
+
target: str,
|
|
42
|
+
failed_checks: list[str],
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Publish QualityGateFailedEvent when checks fail.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
target: Target component or package.
|
|
48
|
+
failed_checks: List of failing sanity check names.
|
|
49
|
+
"""
|
|
50
|
+
event = QualityGateFailedEvent(target=target, failed_checks=failed_checks)
|
|
51
|
+
self._event_bus.publish(event)
|
|
52
|
+
|
|
53
|
+
def publish_critical_mutant_surviving(
|
|
54
|
+
self,
|
|
55
|
+
package: str,
|
|
56
|
+
mutant_id: str,
|
|
57
|
+
file_path: str,
|
|
58
|
+
line_number: int,
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Publish CriticalMutantSurvivingEvent when an actionable mutant survives.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
package: Target package name.
|
|
64
|
+
mutant_id: Identifier of surviving mutant.
|
|
65
|
+
file_path: Source file path where mutation occurred.
|
|
66
|
+
line_number: Line number of mutation.
|
|
67
|
+
"""
|
|
68
|
+
event = CriticalMutantSurvivingEvent(
|
|
69
|
+
package=package,
|
|
70
|
+
mutant_id=mutant_id,
|
|
71
|
+
file_path=file_path,
|
|
72
|
+
line_number=line_number,
|
|
73
|
+
)
|
|
74
|
+
self._event_bus.publish(event)
|
|
75
|
+
|
|
76
|
+
def publish_statements_fixed(
|
|
77
|
+
self,
|
|
78
|
+
target: str,
|
|
79
|
+
files_modified: int,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Publish StatementsFixedEvent when files are auto-formatted.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
target: Target component or workspace.
|
|
85
|
+
files_modified: Number of files modified.
|
|
86
|
+
"""
|
|
87
|
+
event = StatementsFixedEvent(target=target, files_modified=files_modified)
|
|
88
|
+
self._event_bus.publish(event)
|
|
89
|
+
|
|
90
|
+
def publish_agent_asset_drift(
|
|
91
|
+
self,
|
|
92
|
+
outdated_assets: list[str],
|
|
93
|
+
) -> None:
|
|
94
|
+
"""Publish AgentAssetDriftDetectedEvent when agent assets drift.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
outdated_assets: List of outdated agent asset paths.
|
|
98
|
+
"""
|
|
99
|
+
event = AgentAssetDriftDetectedEvent(outdated_assets=outdated_assets)
|
|
100
|
+
self._event_bus.publish(event)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
__all__ = [
|
|
104
|
+
"QualityEventPublisherAdapter",
|
|
105
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Hexaqual engine adapters for hexastack-qual.
|
|
2
|
+
|
|
3
|
+
Notes/Architectural Intent:
|
|
4
|
+
Exports HexaqualRunnerAdapter which implements QualityAuditorPort,
|
|
5
|
+
MutationInspectorPort, and PrDiagnosticPort using the Hexaqual engine.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from hexastack_qual.adapters.hexaqual.runner import HexaqualRunnerAdapter
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"HexaqualRunnerAdapter",
|
|
14
|
+
]
|