generated from coulomb/repo-seed
Add quality gate override flow
This commit is contained in:
@@ -164,3 +164,18 @@ def test_analysis_records_deterministic_gate_review_decision(tmp_path):
|
||||
assert gate_decision.criteria_version == "repo-scoping-quality-criteria/v1"
|
||||
assert "without approving registry truth" in gate_decision.rationale
|
||||
assert service.ability_map(repository.id).abilities == []
|
||||
|
||||
override = service.record_quality_gate_override(
|
||||
repository.id,
|
||||
summary.analysis_run.id,
|
||||
criterion_id="RREG-QC-002",
|
||||
element_type="capability",
|
||||
element_id=10,
|
||||
reason="Curator confirmed this repo now owns provider routing.",
|
||||
notes="Future criteria update may be needed.",
|
||||
)
|
||||
assert override.action == "quality_gate_override"
|
||||
assert override.reviewer_type == "human"
|
||||
assert override.decision_kind == "override"
|
||||
assert override.criterion_ids == ["RREG-QC-002"]
|
||||
assert override.rationale == "Curator confirmed this repo now owns provider routing."
|
||||
|
||||
@@ -135,6 +135,62 @@ def test_quality_criteria_api_lists_active_registry():
|
||||
)
|
||||
|
||||
|
||||
def test_quality_gate_override_api_records_auditable_override(tmp_path):
|
||||
source = tmp_path / "provider-repo"
|
||||
source.mkdir()
|
||||
(source / "README.md").write_text("# Provider Repo\n", encoding="utf-8")
|
||||
(source / "providers.py").write_text(
|
||||
"provider_registry = {'openrouter': OpenRouterAdapter}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
database_path = str(tmp_path / "quality-gate.sqlite3")
|
||||
|
||||
def override_settings():
|
||||
return Settings(
|
||||
database_path=database_path,
|
||||
checkout_root=str(tmp_path / "checkouts"),
|
||||
)
|
||||
|
||||
app.dependency_overrides[get_settings] = override_settings
|
||||
client = TestClient(app)
|
||||
try:
|
||||
repository_response = client.post(
|
||||
"/repos",
|
||||
json={"name": "Provider Repo", "url": str(source)},
|
||||
)
|
||||
repository_id = repository_response.json()["id"]
|
||||
run_response = client.post(
|
||||
f"/repos/{repository_id}/analysis-runs",
|
||||
json={"use_llm_assistance": False},
|
||||
)
|
||||
run_id = run_response.json()["analysis_run"]["id"]
|
||||
graph_response = client.get(
|
||||
f"/repos/{repository_id}/analysis-runs/{run_id}/candidate-graph"
|
||||
)
|
||||
outcome = graph_response.json()["quality_gate_outcomes"][0]
|
||||
|
||||
override_response = client.post(
|
||||
f"/repos/{repository_id}/analysis-runs/{run_id}/quality-gate-overrides",
|
||||
json={
|
||||
"criterion_id": outcome["criterion_id"],
|
||||
"element_type": outcome["element_type"],
|
||||
"element_id": outcome["element_id"],
|
||||
"reason": "Curator inspected source and accepts this exception.",
|
||||
"notes": "Track for criteria refinement.",
|
||||
},
|
||||
)
|
||||
|
||||
assert override_response.status_code == 200
|
||||
override = override_response.json()
|
||||
assert override["action"] == "quality_gate_override"
|
||||
assert override["reviewer_type"] == "human"
|
||||
assert override["decision_kind"] == "override"
|
||||
assert override["criterion_ids"] == [outcome["criterion_id"]]
|
||||
assert override["rationale"].startswith("Curator inspected source")
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
def test_openapi_contract_snapshot_for_stable_agent_paths():
|
||||
client = TestClient(app)
|
||||
|
||||
@@ -276,6 +332,9 @@ def test_openapi_contract_snapshot_for_stable_agent_paths():
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/review-decisions": {
|
||||
"get": {"tags": ["review"], "success_schema": "list[ReviewDecisionResponse]"}
|
||||
},
|
||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/quality-gate-overrides": {
|
||||
"post": {"tags": ["review"], "success_schema": "ReviewDecisionResponse"}
|
||||
},
|
||||
"/repos/{repository_id}/analysis-runs/{base_analysis_run_id}/diff/{target_analysis_run_id}": {
|
||||
"get": {"tags": ["review"], "success_schema": "AnalysisRunDiffResponse"}
|
||||
},
|
||||
@@ -2107,6 +2166,57 @@ def test_ui_register_and_explore_lands_on_analysis_result(tmp_path):
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
def test_ui_quality_gate_outcomes_can_be_overridden(tmp_path):
|
||||
source = tmp_path / "provider-ui"
|
||||
source.mkdir()
|
||||
(source / "README.md").write_text("# Provider UI\n", encoding="utf-8")
|
||||
(source / "providers.py").write_text(
|
||||
"provider_registry = {'openrouter': OpenRouterAdapter}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
def override_settings():
|
||||
return Settings(
|
||||
database_path=str(tmp_path / "ui-quality-gates.sqlite3"),
|
||||
checkout_root=str(tmp_path / "ui-quality-gates-checkouts"),
|
||||
)
|
||||
|
||||
app.dependency_overrides[get_settings] = override_settings
|
||||
client = TestClient(app)
|
||||
try:
|
||||
repository = client.post(
|
||||
"/repos",
|
||||
json={"name": "Provider UI", "url": str(source)},
|
||||
).json()
|
||||
run = client.post(
|
||||
f"/ui/repos/{repository['id']}/analysis-runs",
|
||||
data={"source_path": "", "use_llm_assistance": ""},
|
||||
follow_redirects=False,
|
||||
)
|
||||
detail = client.get(run.headers["location"])
|
||||
assert detail.status_code == 200
|
||||
assert "Quality Gate Outcomes" in detail.text
|
||||
assert "RREG-QC-002" in detail.text
|
||||
|
||||
override = client.post(
|
||||
f"/ui/repos/{repository['id']}/analysis-runs/1/quality-gate-overrides",
|
||||
data={
|
||||
"criterion_id": "RREG-QC-002",
|
||||
"element_type": "capability",
|
||||
"element_id": "1",
|
||||
"reason": "Curator accepts this exception.",
|
||||
"notes": "Review criteria later.",
|
||||
},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert override.status_code == 303
|
||||
updated = client.get(override.headers["location"])
|
||||
assert "quality_gate_override" in updated.text
|
||||
assert "Curator accepts this exception." in updated.text
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
def test_rebuild_characteristics_endpoint_dry_run_and_confirm(tmp_path):
|
||||
source = tmp_path / "rebuild-api"
|
||||
source.mkdir()
|
||||
|
||||
Reference in New Issue
Block a user