WP-0001: feedback channels, CI, pre-commit, telemetry docs
Add kaizen-agentic feedback CLI, Gitea issue templates, CI workflow, pre-commit hooks, FEEDBACK/TELEMETRY docs, and cross-platform path tests. Improve CLI registry error messages; remove agents_backup scaffolding. Apply black formatting across src/tests for CI consistency. State Hub message sent to agentic-resources for Helix correlation doc link.
This commit is contained in:
@@ -20,9 +20,12 @@ class TestClickWorkaround:
|
||||
def test_install_command_error_suppression(self):
|
||||
"""Test that spurious 'unexpected extra argument' errors are suppressed for install commands."""
|
||||
# Test the install command that previously showed spurious errors
|
||||
with patch('sys.argv', ['kaizen-agentic', 'install', 'tdd-workflow', '--target', '/tmp/test']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
with patch(
|
||||
"sys.argv",
|
||||
["kaizen-agentic", "install", "tdd-workflow", "--target", "/tmp/test"],
|
||||
):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.stderr", new_callable=StringIO) as mock_stderr:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit:
|
||||
@@ -40,9 +43,9 @@ class TestClickWorkaround:
|
||||
def test_update_command_error_suppression(self):
|
||||
"""Test that spurious 'unexpected extra argument' errors are suppressed for update commands."""
|
||||
# Test the update command that also shows spurious errors
|
||||
with patch('sys.argv', ['kaizen-agentic', 'update']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
with patch("sys.argv", ["kaizen-agentic", "update"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.stderr", new_callable=StringIO) as mock_stderr:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit:
|
||||
@@ -59,9 +62,9 @@ class TestClickWorkaround:
|
||||
|
||||
def test_non_install_command_normal_operation(self):
|
||||
"""Test that non-install commands work normally without interference."""
|
||||
with patch('sys.argv', ['kaizen-agentic', 'list']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
with patch("sys.argv", ["kaizen-agentic", "list"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.stderr", new_callable=StringIO) as mock_stderr:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit:
|
||||
@@ -76,9 +79,9 @@ class TestClickWorkaround:
|
||||
|
||||
def test_legitimate_error_preservation(self):
|
||||
"""Test that legitimate errors are still displayed for non-install commands."""
|
||||
with patch('sys.argv', ['kaizen-agentic', 'invalid-command']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
with patch("sys.argv", ["kaizen-agentic", "invalid-command"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.stderr", new_callable=StringIO) as mock_stderr:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit as e:
|
||||
@@ -95,8 +98,8 @@ class TestClickWorkaround:
|
||||
|
||||
def test_help_commands_work_normally(self):
|
||||
"""Test that help commands work without interference."""
|
||||
with patch('sys.argv', ['kaizen-agentic', '--help']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.argv", ["kaizen-agentic", "--help"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit as e:
|
||||
@@ -104,7 +107,9 @@ class TestClickWorkaround:
|
||||
assert e.code == 0
|
||||
|
||||
stdout_content = mock_stdout.getvalue()
|
||||
assert "Kaizen Agentic - AI agent development framework" in stdout_content
|
||||
assert (
|
||||
"Kaizen Agentic - AI agent development framework" in stdout_content
|
||||
)
|
||||
assert "Commands:" in stdout_content
|
||||
|
||||
|
||||
@@ -113,9 +118,9 @@ class TestInstallCommandSpecifics:
|
||||
|
||||
def test_install_with_valid_agent(self):
|
||||
"""Test install command with a valid agent name."""
|
||||
with patch('sys.argv', ['kaizen-agentic', 'install', 'tdd-workflow']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
with patch("sys.argv", ["kaizen-agentic", "install", "tdd-workflow"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.stderr", new_callable=StringIO) as mock_stderr:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit:
|
||||
@@ -127,12 +132,17 @@ class TestInstallCommandSpecifics:
|
||||
# Should show clean installation output
|
||||
assert "Installing agents to:" in stdout_content
|
||||
# Should not show Click error
|
||||
assert "Got unexpected extra argument" not in (stdout_content + stderr_content)
|
||||
assert "Got unexpected extra argument" not in (
|
||||
stdout_content + stderr_content
|
||||
)
|
||||
|
||||
def test_install_with_target_option(self):
|
||||
"""Test install command with target directory option."""
|
||||
with patch('sys.argv', ['kaizen-agentic', 'install', 'tdd-workflow', '--target', '/tmp/test']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch(
|
||||
"sys.argv",
|
||||
["kaizen-agentic", "install", "tdd-workflow", "--target", "/tmp/test"],
|
||||
):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit:
|
||||
@@ -144,8 +154,8 @@ class TestInstallCommandSpecifics:
|
||||
|
||||
def test_install_help_works(self):
|
||||
"""Test that install command help works correctly."""
|
||||
with patch('sys.argv', ['kaizen-agentic', 'install', '--help']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.argv", ["kaizen-agentic", "install", "--help"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
try:
|
||||
safe_cli_wrapper()
|
||||
except SystemExit as e:
|
||||
@@ -170,12 +180,14 @@ class TestWorkaroundRemovalReadiness:
|
||||
may be ready for removal.
|
||||
"""
|
||||
# Skip this test in normal runs since it's expected to show the spurious error
|
||||
pytest.skip("This test demonstrates the underlying Click issue. "
|
||||
"Enable when testing Click library updates.")
|
||||
pytest.skip(
|
||||
"This test demonstrates the underlying Click issue. "
|
||||
"Enable when testing Click library updates."
|
||||
)
|
||||
|
||||
with patch('sys.argv', ['kaizen-agentic', 'install', 'tdd-workflow']):
|
||||
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
|
||||
with patch('sys.stderr', new_callable=StringIO) as mock_stderr:
|
||||
with patch("sys.argv", ["kaizen-agentic", "install", "tdd-workflow"]):
|
||||
with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
|
||||
with patch("sys.stderr", new_callable=StringIO) as mock_stderr:
|
||||
try:
|
||||
cli(standalone_mode=False)
|
||||
except SystemExit:
|
||||
@@ -201,9 +213,13 @@ class TestWorkaroundRemovalReadiness:
|
||||
"""
|
||||
# Test that the CLI works when invoked as a subprocess
|
||||
result = subprocess.run(
|
||||
['python', '-c', 'from kaizen_agentic.cli import safe_cli_wrapper; import sys; sys.argv = ["kaizen-agentic", "list"]; safe_cli_wrapper()'],
|
||||
[
|
||||
"python",
|
||||
"-c",
|
||||
'from kaizen_agentic.cli import safe_cli_wrapper; import sys; sys.argv = ["kaizen-agentic", "list"]; safe_cli_wrapper()',
|
||||
],
|
||||
capture_output=True,
|
||||
text=True
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert "Available Agents" in result.stdout
|
||||
@@ -220,7 +236,7 @@ class TestErrorMessagePatterns:
|
||||
spurious_patterns = [
|
||||
"Got unexpected extra argument (tdd-workflow)",
|
||||
"Got unexpected extra argument (some-agent)",
|
||||
"Error: Got unexpected extra argument"
|
||||
"Error: Got unexpected extra argument",
|
||||
]
|
||||
|
||||
for pattern in spurious_patterns:
|
||||
@@ -234,7 +250,7 @@ class TestErrorMessagePatterns:
|
||||
"Error: No such file or directory",
|
||||
"Error: Permission denied",
|
||||
"Error: Invalid agent name",
|
||||
"Error: Configuration file not found"
|
||||
"Error: Configuration file not found",
|
||||
]
|
||||
|
||||
for pattern in legitimate_patterns:
|
||||
@@ -243,4 +259,4 @@ class TestErrorMessagePatterns:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -22,11 +22,11 @@ from kaizen_agentic.cli import cli
|
||||
from kaizen_agentic.metrics import MetricsStore, OptimizerStore
|
||||
from kaizen_agentic.optimization import MIN_SAMPLES_FOR_RECOMMENDATIONS
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _sys_medic_memory() -> str:
|
||||
"""Realistic sys-medic memory after two simulated sessions."""
|
||||
return textwrap.dedent("""\
|
||||
@@ -124,6 +124,7 @@ def _project_management_memory() -> str:
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def project(tmp_path):
|
||||
"""A temporary 'project' directory with a name."""
|
||||
@@ -136,10 +137,13 @@ def project(tmp_path):
|
||||
# Tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestMemoryInit:
|
||||
def test_init_creates_file(self, project):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "init", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "init", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0, result.output
|
||||
assert "Initialized memory" in result.output
|
||||
|
||||
@@ -166,7 +170,9 @@ class TestMemoryInit:
|
||||
def test_init_idempotent(self, project):
|
||||
runner = CliRunner()
|
||||
runner.invoke(cli, ["memory", "init", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(cli, ["memory", "init", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "init", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "already exists" in result.output
|
||||
|
||||
@@ -178,14 +184,18 @@ class TestMemoryShow:
|
||||
memory_file.write_text(_sys_medic_memory())
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "show", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "show", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "Node Profiles" in result.output
|
||||
assert "tegpi-01" in result.output
|
||||
|
||||
def test_show_missing_prints_guidance(self, project):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "show", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "show", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "No memory found" in result.output
|
||||
assert "memory init" in result.output
|
||||
@@ -205,7 +215,9 @@ class TestMemoryBrief:
|
||||
def test_brief_includes_own_memory(self, project):
|
||||
self._populate(project)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "brief", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "Orientation Brief for: sys-medic" in result.output
|
||||
assert "Your Memory" in result.output
|
||||
@@ -214,7 +226,9 @@ class TestMemoryBrief:
|
||||
def test_brief_includes_cross_agent_context(self, project):
|
||||
self._populate(project)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "brief", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "Context From Other Agents" in result.output
|
||||
assert "project-management" in result.output
|
||||
@@ -222,20 +236,26 @@ class TestMemoryBrief:
|
||||
def test_brief_coach_tip_present(self, project):
|
||||
self._populate(project)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "brief", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "agent-coach" in result.output
|
||||
|
||||
def test_brief_no_memory_gives_guidance(self, project):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "brief", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "No agent memory files found" in result.output
|
||||
|
||||
def test_brief_raw_flag_skips_header(self, project):
|
||||
self._populate(project)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["memory", "brief", "sys-medic", "--target", str(project), "--raw"])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "sys-medic", "--target", str(project), "--raw"]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "=== sys-medic ===" in result.output
|
||||
# Raw mode should not include the orientation header
|
||||
@@ -275,7 +295,9 @@ class TestMemoryBrief:
|
||||
],
|
||||
)
|
||||
|
||||
result = runner.invoke(cli, ["memory", "brief", "sys-medic", "--target", str(project)])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "sys-medic", "--target", str(project)]
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "## Performance Summary" in result.output
|
||||
@@ -367,7 +389,10 @@ class TestTddWorkflowMetricsPilot:
|
||||
["metrics", "show", "tdd-workflow", "--target", str(project)],
|
||||
)
|
||||
assert show_result.exit_code == 0
|
||||
assert "test_pass_rate" in show_result.output or "2 execution" in show_result.output.lower()
|
||||
assert (
|
||||
"test_pass_rate" in show_result.output
|
||||
or "2 execution" in show_result.output.lower()
|
||||
)
|
||||
|
||||
store = MetricsStore(project, "tdd-workflow")
|
||||
for i in range(MIN_SAMPLES_FOR_RECOMMENDATIONS - len(sessions)):
|
||||
@@ -422,7 +447,9 @@ class TestProtocolsCommand:
|
||||
|
||||
def test_protocols_show_outputs_content(self):
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["protocols", "show", "sys-medic", "k3s-node-health-assessment"])
|
||||
result = runner.invoke(
|
||||
cli, ["protocols", "show", "sys-medic", "k3s-node-health-assessment"]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
# Protocol should contain key structural sections
|
||||
assert "k3s" in result.output.lower()
|
||||
|
||||
27
tests/test_feedback_cli.py
Normal file
27
tests/test_feedback_cli.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""Tests for developer feedback CLI (WP-0001 T01)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from kaizen_agentic.cli import cli
|
||||
|
||||
|
||||
def test_feedback_human_output():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["feedback"])
|
||||
assert result.exit_code == 0
|
||||
assert "feedback channels" in result.output.lower()
|
||||
assert "gitea.coulomb.social" in result.output
|
||||
assert "bug report" in result.output.lower()
|
||||
|
||||
|
||||
def test_feedback_json_output():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, ["feedback", "--json"])
|
||||
assert result.exit_code == 0
|
||||
payload = json.loads(result.output)
|
||||
assert "channels" in payload
|
||||
assert "bug_report" in payload["templates"]
|
||||
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
@@ -158,4 +157,4 @@ class TestHelixCorrelationCli:
|
||||
["memory", "brief", "tdd-workflow", "--target", str(tmp_path)],
|
||||
)
|
||||
assert brief.exit_code == 0
|
||||
assert "## Performance Summary" in brief.output
|
||||
assert "## Performance Summary" in brief.output
|
||||
|
||||
@@ -6,7 +6,6 @@ from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
DEFINITIONS_DIR = (
|
||||
Path(__file__).parent.parent / "docs" / "integrations" / "activity-definitions"
|
||||
)
|
||||
@@ -30,4 +29,4 @@ def test_integration_docs_exist():
|
||||
root = Path(__file__).parent.parent / "docs"
|
||||
assert (root / "INTEGRATION_PATTERNS.md").exists()
|
||||
assert (root / "integrations" / "helix-forge-correlation.md").exists()
|
||||
assert (root / "integrations" / "optimizer-artifact-manifest.md").exists()
|
||||
assert (root / "integrations" / "optimizer-artifact-manifest.md").exists()
|
||||
|
||||
@@ -104,4 +104,4 @@ class TestMetricsStore:
|
||||
assert agents == ["coach", "tdd-workflow"]
|
||||
|
||||
def test_default_retention_matches_adr(self):
|
||||
assert DEFAULT_RETENTION_DAYS == 180
|
||||
assert DEFAULT_RETENTION_DAYS == 180
|
||||
|
||||
@@ -45,7 +45,9 @@ class TestMetricsCli:
|
||||
assert record.exit_code == 0
|
||||
assert "Recorded metrics" in record.output
|
||||
|
||||
show = runner.invoke(cli, ["metrics", "show", "tdd-workflow", "--target", target])
|
||||
show = runner.invoke(
|
||||
cli, ["metrics", "show", "tdd-workflow", "--target", target]
|
||||
)
|
||||
assert show.exit_code == 0
|
||||
assert '"execution_count": 1' in show.output
|
||||
assert '"success": true' in show.output
|
||||
@@ -54,7 +56,9 @@ class TestMetricsCli:
|
||||
assert listed.exit_code == 0
|
||||
assert "tdd-workflow" in listed.output
|
||||
|
||||
export = runner.invoke(cli, ["metrics", "export", "tdd-workflow", "--target", target])
|
||||
export = runner.invoke(
|
||||
cli, ["metrics", "export", "tdd-workflow", "--target", target]
|
||||
)
|
||||
assert export.exit_code == 0
|
||||
lines = [line for line in export.output.splitlines() if line.strip()]
|
||||
assert len(lines) == 1
|
||||
@@ -69,7 +73,9 @@ class TestMetricsCli:
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
|
||||
show = runner.invoke(cli, ["metrics", "show", "coach", "--target", str(project_dir)])
|
||||
show = runner.invoke(
|
||||
cli, ["metrics", "show", "coach", "--target", str(project_dir)]
|
||||
)
|
||||
assert '"success": false' in show.output
|
||||
|
||||
def test_record_idempotency_key_skips_duplicate(
|
||||
@@ -96,7 +102,9 @@ class TestMetricsCli:
|
||||
)
|
||||
assert len(export.output.strip().splitlines()) == 1
|
||||
|
||||
def test_record_requires_outcome_without_json(self, runner: CliRunner, project_dir: Path):
|
||||
def test_record_requires_outcome_without_json(
|
||||
self, runner: CliRunner, project_dir: Path
|
||||
):
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
["metrics", "record", "tdd-workflow", "--target", str(project_dir)],
|
||||
@@ -133,7 +141,9 @@ class TestMetricsCli:
|
||||
],
|
||||
)
|
||||
|
||||
result = runner.invoke(cli, ["memory", "brief", "tdd-workflow", "--target", target])
|
||||
result = runner.invoke(
|
||||
cli, ["memory", "brief", "tdd-workflow", "--target", target]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "## Performance Summary" in result.output
|
||||
assert "Success rate: 100.0%" in result.output
|
||||
@@ -144,4 +154,4 @@ class TestMetricsCli:
|
||||
["memory", "init", "coach", "--target", str(project_dir), "--no-metrics"],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert not (project_dir / ".kaizen" / "metrics" / "coach").exists()
|
||||
assert not (project_dir / ".kaizen" / "metrics" / "coach").exists()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -140,4 +139,4 @@ def test_publish_against_live_artifact_store(project_with_optimizer: Path):
|
||||
token=token,
|
||||
)
|
||||
assert result.package_id
|
||||
assert result.files_uploaded >= 1
|
||||
assert result.files_uploaded >= 1
|
||||
|
||||
@@ -85,7 +85,9 @@ class TestOptimizationFromMetricsStore:
|
||||
store = MetricsStore(project_dir, "coach")
|
||||
_seed_executions(store, 4)
|
||||
|
||||
report = OptimizationLoop.from_metrics_store(store).get_optimization_report_json()
|
||||
report = OptimizationLoop.from_metrics_store(
|
||||
store
|
||||
).get_optimization_report_json()
|
||||
json.dumps(report)
|
||||
|
||||
|
||||
@@ -130,4 +132,7 @@ class TestMetricsOptimizeCli:
|
||||
optimizer = OptimizerStore(project_dir)
|
||||
assert optimizer.analysis_path.exists()
|
||||
assert optimizer.recommendations_path.exists()
|
||||
assert '"type": "reliability"' in result.output or '"type": "quality"' in result.output
|
||||
assert (
|
||||
'"type": "reliability"' in result.output
|
||||
or '"type": "quality"' in result.output
|
||||
)
|
||||
|
||||
19
tests/test_path_compat.py
Normal file
19
tests/test_path_compat.py
Normal file
@@ -0,0 +1,19 @@
|
||||
"""Cross-platform path handling smoke tests (WP-0001 T07)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path, PureWindowsPath
|
||||
|
||||
from kaizen_agentic.metrics import MetricsStore
|
||||
|
||||
|
||||
def test_metrics_store_accepts_string_project_root(tmp_path: Path):
|
||||
store = MetricsStore(str(tmp_path), "coach")
|
||||
store.append({"success": True}, idempotency_key="win-path-test")
|
||||
assert store.executions_path.exists()
|
||||
|
||||
|
||||
def test_metrics_paths_use_forward_join_semantics(tmp_path: Path):
|
||||
store = MetricsStore(tmp_path, "tdd-workflow")
|
||||
suffix = PureWindowsPath(".kaizen/metrics/tdd-workflow/executions.jsonl")
|
||||
assert store.executions_path.as_posix().endswith(suffix.as_posix())
|
||||
Reference in New Issue
Block a user