Skip to content

Commit c6b42ed

Browse files
tbitcsoz-agent
andcommitted
style: ruff lint + format fixes (Python 3.10 compat, line lengths)
Fix f-string backslash escape for Python 3.10 compatibility in session_info CLI command. Format compliance, governance_logic, and test_intelligence to comply with line length limits. Remove unused imports. Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent 0e5fe67 commit c6b42ed

5 files changed

Lines changed: 163 additions & 43 deletions

File tree

src/specsmith/commands/intelligence.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,27 @@ def session_info(project_dir: str, as_json: bool) -> None:
390390
if as_json:
391391
click.echo(json.dumps(ctx.to_dict(), indent=2))
392392
else:
393+
gov = "\u2713" if ctx.is_governed else "\u2717"
393394
click.echo(f" Project: {ctx.project_name}")
394-
click.echo(f" Governed: {'\u2713' if ctx.is_governed else '\u2717'}")
395-
click.echo(f" Phase: {ctx.phase_emoji} {ctx.phase_label} ({ctx.phase_readiness_pct}%)")
395+
click.echo(f" Governed: {gov}")
396+
phase = ctx.phase_emoji
397+
label = ctx.phase_label
398+
pct = ctx.phase_readiness_pct
399+
click.echo(f" Phase: {phase} {label} ({pct}%)")
396400
click.echo(f" Health: {ctx.health_score}%")
397401
click.echo(f" Compliance: {ctx.compliance_score}%")
398402
click.echo(f" Profile: {ctx.active_profile}")
399-
click.echo(f" Providers: {ctx.reachable_providers}/{ctx.provider_count} reachable")
403+
rp = ctx.reachable_providers
404+
pc = ctx.provider_count
405+
click.echo(f" Providers: {rp}/{pc} reachable")
400406
click.echo(f" Session: {ctx.session_id}")
401407
if ctx.needs_import:
402-
click.echo("\n \u26a0 Not a specsmith project. Run 'specsmith import' to add governance.")
408+
click.echo(
409+
"\n \u26a0 Not a specsmith project. Run 'specsmith import' to add governance."
410+
)
403411
if ctx.needs_migration:
404-
click.echo(f"\n \u26a0 Spec version mismatch ({ctx.spec_version} vs {ctx.installed_version}). Run 'specsmith migrate-project'.")
412+
sv = ctx.spec_version
413+
iv = ctx.installed_version
414+
click.echo(
415+
f"\n \u26a0 Spec version mismatch ({sv} vs {iv}). Run 'specsmith migrate-project'."
416+
)

src/specsmith/compliance.py

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -129,16 +129,16 @@ def get_compliance_summary(project_dir: str | Path = ".") -> ComplianceSummary:
129129
# Build trace matrix
130130
trace: list[dict[str, Any]] = []
131131
for req_id, req in sorted(reqs.items()):
132-
linked_tests = [
133-
t["id"] for t in tests.values() if t.get("requirement_id") == req_id
134-
]
135-
trace.append({
136-
"requirement_id": req_id,
137-
"title": req.get("title", ""),
138-
"status": req.get("status", ""),
139-
"tests": linked_tests,
140-
"covered": len(linked_tests) > 0,
141-
})
132+
linked_tests = [t["id"] for t in tests.values() if t.get("requirement_id") == req_id]
133+
trace.append(
134+
{
135+
"requirement_id": req_id,
136+
"title": req.get("title", ""),
137+
"status": req.get("status", ""),
138+
"tests": linked_tests,
139+
"covered": len(linked_tests) > 0,
140+
}
141+
)
142142

143143
return ComplianceSummary(
144144
total_requirements=total,
@@ -159,18 +159,62 @@ def get_governance_rules_status(project_dir: str | Path = ".") -> list[dict[str,
159159
rules = [
160160
{"id": "H1", "name": "Ledger required", "description": "No ledger entry = work not done"},
161161
{"id": "H2", "name": "Proposal required", "description": "No proposal = no execution"},
162-
{"id": "H3", "name": "Cross-platform awareness", "description": "All work must consider every target platform"},
163-
{"id": "H4", "name": "Environment isolation", "description": "No system-dependent assumptions"},
162+
{
163+
"id": "H3",
164+
"name": "Cross-platform awareness",
165+
"description": "All work must consider every target platform",
166+
},
167+
{
168+
"id": "H4",
169+
"name": "Environment isolation",
170+
"description": "No system-dependent assumptions",
171+
},
164172
{"id": "H5", "name": "Explicit startup", "description": "No hidden service logic"},
165-
{"id": "H6", "name": "No silent scope expansion", "description": "If task grows, stop and re-propose"},
166-
{"id": "H7", "name": "No undocumented state changes", "description": "Every change must be traceable"},
167-
{"id": "H8", "name": "Documentation is implementation", "description": "Architecture changes MUST update docs"},
168-
{"id": "H9", "name": "Execution timeout required", "description": "All agent commands must have timeouts"},
169-
{"id": "H10", "name": "No hardcoded versions", "description": "Use importlib.metadata at runtime"},
170-
{"id": "H11", "name": "No unbounded loops", "description": "Every loop must have a deadline"},
171-
{"id": "H12", "name": "Windows automation via .cmd", "description": "Multi-step automation uses .cmd files"},
172-
{"id": "H13", "name": "Epistemic boundaries required", "description": "Proposals must state assumptions"},
173-
{"id": "H14", "name": "Documentation freshness", "description": "Docs updated in same commit as code"},
173+
{
174+
"id": "H6",
175+
"name": "No silent scope expansion",
176+
"description": "If task grows, stop and re-propose",
177+
},
178+
{
179+
"id": "H7",
180+
"name": "No undocumented state changes",
181+
"description": "Every change must be traceable",
182+
},
183+
{
184+
"id": "H8",
185+
"name": "Documentation is implementation",
186+
"description": "Architecture changes MUST update docs",
187+
},
188+
{
189+
"id": "H9",
190+
"name": "Execution timeout required",
191+
"description": "All agent commands must have timeouts",
192+
},
193+
{
194+
"id": "H10",
195+
"name": "No hardcoded versions",
196+
"description": "Use importlib.metadata at runtime",
197+
},
198+
{
199+
"id": "H11",
200+
"name": "No unbounded loops",
201+
"description": "Every loop must have a deadline",
202+
},
203+
{
204+
"id": "H12",
205+
"name": "Windows automation via .cmd",
206+
"description": "Multi-step automation uses .cmd files",
207+
},
208+
{
209+
"id": "H13",
210+
"name": "Epistemic boundaries required",
211+
"description": "Proposals must state assumptions",
212+
},
213+
{
214+
"id": "H14",
215+
"name": "Documentation freshness",
216+
"description": "Docs updated in same commit as code",
217+
},
174218
]
175219

176220
# Quick checks for common violations

src/specsmith/governance_logic.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ def do_GET(self) -> None: # noqa: N802
490490
elif self.path == "/api/session":
491491
try:
492492
from specsmith.session_init import init_session
493+
493494
ctx = init_session(project_dir)
494495
self._json_ok(ctx.to_dict())
495496
except Exception as exc: # noqa: BLE001
@@ -499,20 +500,25 @@ def do_GET(self) -> None: # noqa: N802
499500
elif self.path == "/api/compliance/summary":
500501
try:
501502
from specsmith.compliance import get_compliance_summary
503+
502504
s = get_compliance_summary(project_dir)
503505
self._json_ok(s.to_dict())
504506
except Exception as exc: # noqa: BLE001
505507
self._json_err(str(exc), code=500)
506508
elif self.path == "/api/compliance/gaps":
507509
try:
508510
from specsmith.compliance import get_compliance_summary
511+
509512
s = get_compliance_summary(project_dir)
510-
self._json_ok({"uncovered": s.uncovered_requirements, "orphaned": s.orphaned_tests})
513+
self._json_ok(
514+
{"uncovered": s.uncovered_requirements, "orphaned": s.orphaned_tests}
515+
)
511516
except Exception as exc: # noqa: BLE001
512517
self._json_err(str(exc), code=500)
513518
elif self.path == "/api/compliance/trace":
514519
try:
515520
from specsmith.compliance import get_compliance_summary
521+
516522
s = get_compliance_summary(project_dir)
517523
self._json_ok({"trace_matrix": s.trace_matrix})
518524
except Exception as exc: # noqa: BLE001
@@ -522,30 +528,51 @@ def do_GET(self) -> None: # noqa: N802
522528
elif self.path == "/api/governance/rules":
523529
try:
524530
from specsmith.compliance import get_governance_rules_status
531+
525532
self._json_ok({"rules": get_governance_rules_status(project_dir)})
526533
except Exception as exc: # noqa: BLE001
527534
self._json_err(str(exc), code=500)
528535
elif self.path == "/api/governance/phase":
529536
try:
530537
from specsmith.phase import PHASE_MAP, phase_progress_pct, read_phase
538+
531539
root = Path(project_dir).resolve()
532540
key = read_phase(root)
533541
phase = PHASE_MAP[key]
534-
self._json_ok({"phase": key, "label": phase.label, "emoji": phase.emoji, "readiness_pct": phase_progress_pct(phase, root)})
542+
self._json_ok(
543+
{
544+
"phase": key,
545+
"label": phase.label,
546+
"emoji": phase.emoji,
547+
"readiness_pct": phase_progress_pct(phase, root),
548+
}
549+
)
535550
except Exception as exc: # noqa: BLE001
536551
self._json_err(str(exc), code=500)
537552
elif self.path == "/api/governance/audit":
538553
try:
539554
from specsmith.auditor import run_audit
555+
540556
report = run_audit(Path(project_dir).resolve())
541-
self._json_ok({"healthy": report.healthy, "passed": report.passed, "failed": report.failed, "results": [{"passed": r.passed, "message": r.message} for r in report.results]})
557+
self._json_ok(
558+
{
559+
"healthy": report.healthy,
560+
"passed": report.passed,
561+
"failed": report.failed,
562+
"results": [
563+
{"passed": r.passed, "message": r.message}
564+
for r in report.results
565+
],
566+
}
567+
)
542568
except Exception as exc: # noqa: BLE001
543569
self._json_err(str(exc), code=500)
544570

545571
# ── Providers ──────────────────────────────────────────
546572
elif self.path == "/api/providers":
547573
try:
548574
from specsmith.agent.provider_registry import ProviderRegistry
575+
549576
reg = ProviderRegistry.load()
550577
self._json_ok({"providers": [p.to_public_dict() for p in reg.providers]})
551578
except Exception as exc: # noqa: BLE001
@@ -555,22 +582,35 @@ def do_GET(self) -> None: # noqa: N802
555582
elif self.path == "/api/profiles":
556583
try:
557584
from specsmith.agent.execution_profiles import ExecutionProfileStore
585+
558586
store = ExecutionProfileStore.load()
559-
self._json_ok({"profiles": [p.to_dict() for p in store.profiles], "default": store.default().id})
587+
self._json_ok(
588+
{
589+
"profiles": [p.to_dict() for p in store.profiles],
590+
"default": store.default().id,
591+
}
592+
)
560593
except Exception as exc: # noqa: BLE001
561594
self._json_err(str(exc), code=500)
562595

563596
# ── Model Scores ───────────────────────────────────────
564597
elif self.path.startswith("/api/models/scores"):
565598
try:
566-
from specsmith.agent.model_intelligence import BASELINE_SCORES, rank_models_for_role
567599
import urllib.parse as _up
600+
601+
from specsmith.agent.model_intelligence import (
602+
BASELINE_SCORES,
603+
rank_models_for_role,
604+
)
605+
568606
qs = _up.urlparse(self.path).query
569607
params = _up.parse_qs(qs)
570608
role = params.get("role", ["coder"])[0]
571609
models = list(BASELINE_SCORES.keys())
572610
ranked = rank_models_for_role(role, models)
573-
self._json_ok({"role": role, "scores": [{"model": m, "score": s} for m, s in ranked]})
611+
self._json_ok(
612+
{"role": role, "scores": [{"model": m, "score": s} for m, s in ranked]}
613+
)
574614
except Exception as exc: # noqa: BLE001
575615
self._json_err(str(exc), code=500)
576616

src/specsmith/session_init.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
from __future__ import annotations
1818

19-
import json
2019
import logging
2120
import time
2221
from dataclasses import dataclass, field

tests/test_intelligence.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,8 @@
44

55
from __future__ import annotations
66

7-
import json
8-
from pathlib import Path
9-
107
import pytest
118

12-
139
# ---------------------------------------------------------------------------
1410
# Provider Registry (REQ-220)
1511
# ---------------------------------------------------------------------------
@@ -20,7 +16,9 @@ def test_provider_entry_validation(self):
2016
from specsmith.agent.provider_registry import ProviderEntry, ProviderError
2117

2218
# Valid entry
23-
e = ProviderEntry(id="test", name="Test", provider_type="byoe", base_url="http://localhost:8000/v1")
19+
e = ProviderEntry(
20+
id="test", name="Test", provider_type="byoe", base_url="http://localhost:8000/v1"
21+
)
2422
e.validate() # should not raise
2523

2624
# Invalid: empty id
@@ -63,7 +61,14 @@ def test_registry_persistence(self, tmp_path):
6361

6462
path = tmp_path / "providers.json"
6563
reg = ProviderRegistry(path=path)
66-
reg.add(ProviderEntry(id="vllm-1", name="vLLM Home", provider_type="vllm", base_url="http://10.0.0.1:8000/v1"))
64+
reg.add(
65+
ProviderEntry(
66+
id="vllm-1",
67+
name="vLLM Home",
68+
provider_type="vllm",
69+
base_url="http://10.0.0.1:8000/v1",
70+
)
71+
)
6772

6873
# Reload
6974
reg2 = ProviderRegistry(path=path)
@@ -73,15 +78,23 @@ def test_registry_persistence(self, tmp_path):
7378
def test_to_public_dict_redacts_key(self):
7479
from specsmith.agent.provider_registry import ProviderEntry
7580

76-
e = ProviderEntry(id="test", name="Test", provider_type="cloud", api_key="sk-secret123", base_url="http://api.example.com")
81+
e = ProviderEntry(
82+
id="test",
83+
name="Test",
84+
provider_type="cloud",
85+
api_key="sk-secret123",
86+
base_url="http://api.example.com",
87+
)
7788
d = e.to_public_dict()
7889
assert d["api_key"] == "***"
7990
assert d["api_key_set"] is True
8091

8192
def test_cloud_provider_auto_fills_url(self):
8293
from specsmith.agent.provider_registry import ProviderEntry
8394

84-
e = ProviderEntry(id="my-openai", name="OpenAI", provider_type="cloud", provider_id="openai")
95+
e = ProviderEntry(
96+
id="my-openai", name="OpenAI", provider_type="cloud", provider_id="openai"
97+
)
8598
e.validate()
8699
assert "api.openai.com" in e.base_url
87100

@@ -257,8 +270,20 @@ def test_all_clients_have_required_methods(self):
257270
from specsmith.datasources.ppubs import PPUBSClient
258271
from specsmith.datasources.ptab import PTABClient
259272

260-
for cls in [PatentsViewClient, PPUBSClient, ODPClient, PFWClient, CitationsClient, FPDClient, PTABClient]:
261-
client = cls() if cls in (PPUBSClient, ODPClient, CitationsClient, FPDClient, PTABClient) else cls("")
273+
for cls in [
274+
PatentsViewClient,
275+
PPUBSClient,
276+
ODPClient,
277+
PFWClient,
278+
CitationsClient,
279+
FPDClient,
280+
PTABClient,
281+
]:
282+
client = (
283+
cls()
284+
if cls in (PPUBSClient, ODPClient, CitationsClient, FPDClient, PTABClient)
285+
else cls("")
286+
)
262287
assert hasattr(client, "search")
263288
assert hasattr(client, "get")
264289
assert hasattr(client, "test_connection")

0 commit comments

Comments
 (0)