Files
codestable__codestable/tests/test_codestable_goal_consistency_gate.py

825 lines
29 KiB
Python

from __future__ import annotations
import json
import hashlib
import os
import subprocess
import sys
from pathlib import Path
import pytest
GOAL_CONSISTENCY_GATE = (
Path(__file__).resolve().parents[1]
/ "plugins/codestable/skills/cs-onboard/tools/codestable-goal-consistency-gate.py"
)
TOOLS_DIR = GOAL_CONSISTENCY_GATE.parent
FEATURE_SLUG = "invoice-export"
FEATURE_IDENTITY = "2026-07-15-invoice-export"
def write(path: Path, text: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(text, encoding="utf-8")
def digest(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def write_feature_artifacts(root: Path) -> Path:
feature_dir = root / f".codestable/features/{FEATURE_IDENTITY}"
write(
feature_dir / f"{FEATURE_SLUG}-checklist.yaml",
f"feature: {FEATURE_IDENTITY}\nsteps:\n - id: implement\n status: done\n"
"checks:\n - id: tests\n status: passed\n",
)
for suffix, doc_type, status in (
("design", "feature-design", "approved"),
("review", "feature-review", "passed"),
("qa", "feature-qa", "passed"),
("acceptance", "feature-acceptance", "passed"),
("evidence-pack", "feature-evidence-pack", "generated"),
):
write(
feature_dir / f"{FEATURE_SLUG}-{suffix}.md",
f"---\ndoc_type: {doc_type}\nfeature: {FEATURE_IDENTITY}\nstatus: {status}\n"
f"---\n# {suffix}\n",
)
prefix = f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}"
checklist = feature_dir / f"{FEATURE_SLUG}-checklist.yaml"
design = feature_dir / f"{FEATURE_SLUG}-design.md"
evidence_pack = feature_dir / f"{FEATURE_SLUG}-evidence-pack.md"
gate_results = feature_dir / f"{FEATURE_SLUG}-gate-results.json"
dod_results = feature_dir / f"{FEATURE_SLUG}-dod-results.json"
dod_contract_results = feature_dir / f"{FEATURE_SLUG}-dod-contract-results.json"
result_payloads = {
gate_results: {
"gate_id": "scope-gate",
"feature": FEATURE_IDENTITY,
"stage": "implementation.before_review",
"status": "passed",
"inputs": {"feature_dir": f".codestable/features/{FEATURE_IDENTITY}"},
"input_digests": {},
},
dod_results: {
"gate_id": "dod-runner",
"feature": FEATURE_IDENTITY,
"stage": "implementation.before_review",
"status": "passed",
"inputs": {"checklist": f"{prefix}-checklist.yaml"},
"input_digests": {"checklist": digest(checklist)},
},
dod_contract_results: {
"gate_id": "dod-contract-gate",
"feature": FEATURE_IDENTITY,
"stage": "feature_design.before_approve",
"status": "passed",
"inputs": {"design": f"{prefix}-design.md"},
"input_digests": {"design": digest(design)},
},
}
for path, payload in result_payloads.items():
write(path, json.dumps(payload) + "\n")
evidence_results = feature_dir / f"{FEATURE_SLUG}-evidence-pack-results.json"
write(
evidence_results,
json.dumps(
{
"gate_id": "evidence-pack",
"feature": FEATURE_IDENTITY,
"stage": "implementation.before_review",
"status": "passed",
"inputs": {
"design": f"{prefix}-design.md",
"checklist": f"{prefix}-checklist.yaml",
"out": f"{prefix}-evidence-pack.md",
"dod_results": f"{prefix}-dod-results.json",
"gate_results": f"{prefix}-gate-results.json",
},
"input_digests": {
"design": digest(design),
"checklist": digest(checklist),
"out": digest(evidence_pack),
"dod_results": digest(dod_results),
"gate_results": digest(gate_results),
},
}
)
+ "\n",
)
return feature_dir
def write_final_audit_candidate(
tmp_path: Path,
*,
commit_ref: str = "approval-report.md#goal-commits",
commit_decision: str = "approved",
include_item: bool = True,
include_feature: bool = True,
duplicate_feature: bool = False,
item_status: str = "done",
execution_confirmation_id: str | None = "goal-confirm-1",
approval_group_status: str | None = "approved",
approval_group_confirmation_id: str = "goal-confirm-1",
) -> Path:
roadmap = tmp_path / "repo/.codestable/roadmap/billing-system"
item_rows = (
f"items:\n - slug: {FEATURE_SLUG}\n status: {item_status}\n"
f" feature: {FEATURE_IDENTITY}\n"
if include_item
else "items: []\n"
)
write(roadmap / "billing-system-items.yaml", "roadmap: billing-system\n" + item_rows)
feature_row = (
f" - slug: {FEATURE_SLUG}\n"
f" roadmap_item: {FEATURE_SLUG}\n"
" status: accepted\n"
f" feature_dir: .codestable/features/{FEATURE_IDENTITY}\n"
f" design: .codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-design.md\n"
f" checklist: .codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-checklist.yaml\n"
f" review: .codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-review.md\n"
f" qa: .codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-qa.md\n"
f" acceptance: .codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-acceptance.md\n"
)
feature_count = 2 if duplicate_feature else 1
feature_state = (
f"current_feature_index: {feature_count}\nfeatures:\n"
+ feature_row
+ (feature_row if duplicate_feature else "")
if include_feature
else "current_feature_index: 0\nfeatures: []\n"
)
confirmation_state = (
f'execution_confirmation_id: "{execution_confirmation_id}"\n'
if execution_confirmation_id is not None
else ""
)
write(
roadmap / "goal-state.yaml",
"roadmap: billing-system\n"
"status: ready-to-dispatch\n"
+ confirmation_state
+ "acceptance_authorization: approved\n"
+ 'acceptance_authorization_ref: "approval-report.md#goal-acceptance"\n'
+ "commit_authorization: approved\n"
f'commit_authorization_ref: "{commit_ref}"\n'
+ feature_state,
)
approval_group = ""
if approval_group_status is not None:
approval_group = (
"approval_groups:\n"
" goal-execution:\n"
f" status: {approval_group_status}\n"
f' confirmation_id: "{approval_group_confirmation_id}"\n'
" decisions:\n"
" - goal-acceptance\n"
" - goal-commits\n"
)
write(
roadmap / "approval-report.md",
"---\ndoc_type: approval-report\nstatus: approved\napprovals:\n"
" goal-acceptance: approved\n"
f" goal-commits: {commit_decision}\n"
+ approval_group
+ "---\n# Approval\n",
)
if include_feature:
write_feature_artifacts(roadmap.parents[2])
return roadmap
def run_gate(roadmap: Path) -> tuple[subprocess.CompletedProcess[str], dict]:
completed = subprocess.run(
[sys.executable, GOAL_CONSISTENCY_GATE.as_posix(), "--roadmap", roadmap.as_posix()],
cwd=roadmap.parents[2],
check=False,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env={"PYTHONDONTWRITEBYTECODE": "1", "PATH": os.environ.get("PATH", "")},
timeout=10,
)
return completed, json.loads(completed.stdout)
def test_final_consistency_gate_checks_authorizations_before_audit_report(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
completed, result = run_gate(roadmap)
assert completed.returncode == 0
assert result["status"] == "passed"
authorizations = result["evidence"][0]["authorizations"]
assert authorizations["acceptance_authorization"]["status"] == "approved"
assert authorizations["commit_authorization"]["status"] == "approved"
confirmation = result["evidence"][1]["goal_execution_confirmation"]
assert confirmation["status"] == "approved"
assert confirmation["confirmation_id"] == "goal-confirm-1"
assert confirmation["state_confirmation_id"] == "goal-confirm-1"
assert not (roadmap / "goal-audit.md").exists()
def test_final_consistency_gate_rejects_confirmation_id_mismatch(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(
tmp_path,
execution_confirmation_id="other-confirmation",
)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert "goal-state execution_confirmation_id does not match approval group" in result[
"blocking"
]
@pytest.mark.parametrize("group_status", ["pending", "rejected"])
def test_final_consistency_gate_rejects_unapproved_execution_group(
tmp_path: Path,
group_status: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path, approval_group_status=group_status)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any("approval group goal-execution" in item for item in result["blocking"])
def test_final_consistency_gate_allows_legacy_approvals_with_warning(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(
tmp_path,
execution_confirmation_id=None,
approval_group_status=None,
)
completed, result = run_gate(roadmap)
assert completed.returncode == 0
assert result["status"] == "passed"
assert "legacy epic goal approvals" in result["warnings"][-1]
def test_final_consistency_gate_rejects_new_state_without_execution_group(
tmp_path: Path,
) -> None:
roadmap = write_final_audit_candidate(
tmp_path,
execution_confirmation_id="",
approval_group_status=None,
)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert "approval group goal-execution is absent" in result["blocking"]
def test_final_consistency_gate_rejects_external_approval_symlink(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
approval = roadmap / "approval-report.md"
external = tmp_path / "external-approval-report.md"
write(external, approval.read_text(encoding="utf-8"))
approval.unlink()
approval.symlink_to(external)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert "approval-report.md escapes the workflow unit" in result["blocking"]
def test_final_consistency_gate_does_not_label_incomplete_approvals_as_legacy(
tmp_path: Path,
) -> None:
roadmap = write_final_audit_candidate(
tmp_path,
commit_decision="pending",
execution_confirmation_id=None,
approval_group_status=None,
)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert not any("legacy epic goal approvals" in warning for warning in result["warnings"])
@pytest.mark.parametrize(
("commit_ref", "reason"),
[
("approval-report.md#goal-acceptance", "must be approval-report.md#goal-commits"),
("../approval-report.md#goal-commits", "escapes the workflow unit"),
],
)
def test_final_consistency_gate_rejects_invalid_commit_reference(
tmp_path: Path,
commit_ref: str,
reason: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path, commit_ref=commit_ref)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(reason in item for item in result["blocking"])
def test_final_consistency_gate_rejects_named_commit_rejection(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path, commit_decision="rejected")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert "approval decision goal-commits was rejected" in result["blocking"]
@pytest.mark.parametrize(
"artifact",
["items", "state", "approval", "checklist"],
)
def test_final_consistency_gate_reports_invalid_yaml_without_traceback(
tmp_path: Path,
artifact: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path)
paths = {
"items": roadmap / "billing-system-items.yaml",
"state": roadmap / "goal-state.yaml",
"approval": roadmap / "approval-report.md",
"checklist": roadmap.parents[2]
/ ".codestable/features/2026-07-15-invoice-export/invoice-export-checklist.yaml",
}
target = paths[artifact]
if artifact == "approval":
write(target, "---\napprovals: [unterminated\n---\n# Approval\n")
else:
write(target, "items: [unterminated\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert "Traceback" not in completed.stderr
assert result["status"] == "failed"
assert any(f"invalid YAML artifact: {target}" in item for item in result["blocking"])
def test_final_consistency_gate_rejects_non_mapping_checklist(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
checklist = (
roadmap.parents[2]
/ ".codestable/features/2026-07-15-invoice-export/invoice-export-checklist.yaml"
)
write(checklist, "- step-1\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert "Traceback" not in completed.stderr
assert result["status"] == "failed"
assert f"invoice-export: checklist is not a mapping: {checklist}" in result["blocking"]
def test_final_consistency_gate_rejects_done_item_without_feature(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path, include_feature=False)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert f"roadmap item has no goal-state feature: {FEATURE_SLUG}" in result["blocking"]
def test_final_consistency_gate_rejects_empty_roadmap(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(
tmp_path,
include_item=False,
include_feature=False,
)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert "roadmap items is empty" in result["blocking"]
def test_final_consistency_gate_rejects_feature_without_roadmap_item(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path, include_item=False)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert f"goal-state feature has no non-dropped roadmap item: {FEATURE_SLUG}" in result["blocking"]
def test_final_consistency_gate_rejects_mismatched_roadmap_feature_pointer(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
items_path = roadmap / "billing-system-items.yaml"
items = items_path.read_text(encoding="utf-8").replace(
f"feature: {FEATURE_IDENTITY}",
"feature: 2026-07-15-other",
)
write(items_path, items)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any("roadmap item feature pointer does not match" in item for item in result["blocking"])
def test_final_consistency_gate_accepts_all_dropped_roadmap(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(
tmp_path,
include_feature=False,
item_status="dropped",
)
completed, result = run_gate(roadmap)
assert completed.returncode == 0
assert result["status"] == "passed"
def test_final_consistency_gate_rejects_duplicate_feature(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path, duplicate_feature=True)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert f"duplicate goal-state feature slug: {FEATURE_SLUG}" in result["blocking"]
def test_final_consistency_gate_rejects_cross_feature_evidence_replay(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
other_review = roadmap.parents[2] / ".codestable/features/2026-07-15-other/other-review.md"
write(
other_review,
"---\ndoc_type: feature-review\nfeature: 2026-07-15-other\nstatus: passed\n---\n# Review\n",
)
state_path = roadmap / "goal-state.yaml"
state = state_path.read_text(encoding="utf-8").replace(
f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-review.md",
".codestable/features/2026-07-15-other/other-review.md",
)
write(state_path, state)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(f"{FEATURE_SLUG}: review path is not canonical" in item for item in result["blocking"])
def test_final_consistency_gate_does_not_read_escaped_feature_artifacts(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
state_path = roadmap / "goal-state.yaml"
escaped = tmp_path / "outside-feature"
write(
escaped / f"{FEATURE_SLUG}-review.md",
"---\napprovals: [unterminated\n---\n# Invalid external evidence\n",
)
state = state_path.read_text(encoding="utf-8")
state = state.replace(
f".codestable/features/{FEATURE_IDENTITY}",
escaped.as_posix(),
)
write(state_path, state)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert "Traceback" not in completed.stderr
assert result["status"] == "failed"
assert any("feature_dir escapes .codestable/features" in item for item in result["blocking"])
assert not any("invalid YAML artifact" in item for item in result["blocking"])
@pytest.mark.parametrize(
("old", "new", "reason"),
[
(
"doc_type: feature-review",
"doc_type: feature-qa",
"doc_type is not feature-review",
),
(
f"feature: {FEATURE_IDENTITY}",
"feature: 2026-07-15-other",
f"feature identity does not match {FEATURE_IDENTITY}",
),
],
)
def test_final_consistency_gate_rejects_review_frontmatter_identity_mismatch(
tmp_path: Path,
old: str,
new: str,
reason: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path)
review = (
roadmap.parents[2]
/ f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-review.md"
)
write(review, review.read_text(encoding="utf-8").replace(old, new))
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(reason in item for item in result["blocking"])
@pytest.mark.parametrize(
("field", "value", "reason"),
[
("gate_id", "dod-runner", "gate_results gate_id is not scope-gate"),
(
"feature",
"2026-07-15-other",
f"gate_results feature identity does not match {FEATURE_IDENTITY}",
),
],
)
def test_final_consistency_gate_rejects_replayed_gate_result_identity(
tmp_path: Path,
field: str,
value: str,
reason: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path)
gate_results = (
roadmap.parents[2]
/ f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-gate-results.json"
)
data = json.loads(gate_results.read_text(encoding="utf-8"))
data[field] = value
write(gate_results, json.dumps(data) + "\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(reason in item for item in result["blocking"])
@pytest.mark.parametrize(
("field", "value", "reason"),
[
("status", "generated", "gate_results JSON is not passed: status=generated"),
("stage", "other-feature", "gate_results stage is not valid for final audit"),
],
)
def test_final_consistency_gate_rejects_invalid_gate_result_state(
tmp_path: Path,
field: str,
value: str,
reason: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path)
gate_results = (
roadmap.parents[2]
/ f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-gate-results.json"
)
data = json.loads(gate_results.read_text(encoding="utf-8"))
data[field] = value
write(gate_results, json.dumps(data) + "\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(reason in item for item in result["blocking"])
def test_final_consistency_gate_rejects_result_from_alternate_checklist(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
gate_results = (
roadmap.parents[2]
/ f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-dod-results.json"
)
data = json.loads(gate_results.read_text(encoding="utf-8"))
data["inputs"] = {
"checklist": f".codestable/features/{FEATURE_IDENTITY}/alternate-checklist.yaml"
}
write(gate_results, json.dumps(data) + "\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(
"dod_results inputs do not match canonical feature artifacts" in item
for item in result["blocking"]
)
def test_final_consistency_gate_rejects_stale_result_after_checklist_changes(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
checklist = (
roadmap.parents[2]
/ f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-checklist.yaml"
)
write(checklist, checklist.read_text(encoding="utf-8") + "# changed after gate\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert result["status"] == "failed"
assert any(
"dod_results input digests do not match current canonical artifacts" in item
for item in result["blocking"]
)
@pytest.mark.parametrize(
("checklist_body", "reason"),
[
("steps: []\nchecks:\n - id: tests\n status: passed\n", "checklist steps must be a non-empty list"),
("steps:\n - id: implement\n status: done\nchecks: []\n", "checklist checks must be a non-empty list"),
("steps: invalid\nchecks:\n - id: tests\n status: passed\n", "checklist steps must be a non-empty list"),
("steps:\n - invalid\nchecks:\n - id: tests\n status: passed\n", "checklist steps[0] is not a mapping"),
],
)
def test_final_consistency_gate_requires_nonempty_mapping_checklist_entries(
tmp_path: Path,
checklist_body: str,
reason: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path)
root = roadmap.parents[2]
feature_dir = root / f".codestable/features/{FEATURE_IDENTITY}"
checklist = feature_dir / f"{FEATURE_SLUG}-checklist.yaml"
write(checklist, f"feature: {FEATURE_IDENTITY}\n{checklist_body}")
for suffix in ("dod-results", "evidence-pack-results"):
result_path = feature_dir / f"{FEATURE_SLUG}-{suffix}.json"
data = json.loads(result_path.read_text(encoding="utf-8"))
data["input_digests"]["checklist"] = digest(checklist)
write(result_path, json.dumps(data) + "\n")
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert "Traceback" not in completed.stderr
assert result["status"] == "failed"
assert any(reason in item for item in result["blocking"])
@pytest.mark.parametrize(
("suffix", "label", "payload"),
[
("evidence-pack-results", "evidence_pack_results", "[]\n"),
("gate-results", "gate_results", "null\n"),
("dod-results", "dod_results", '"passed"\n'),
("dod-contract-results", "dod_contract_results", "[1]\n"),
],
)
def test_final_consistency_gate_rejects_non_mapping_result_json(
tmp_path: Path,
suffix: str,
label: str,
payload: str,
) -> None:
roadmap = write_final_audit_candidate(tmp_path)
result_path = (
roadmap.parents[2]
/ f".codestable/features/{FEATURE_IDENTITY}/{FEATURE_SLUG}-{suffix}.json"
)
write(result_path, payload)
completed, result = run_gate(roadmap)
assert completed.returncode == 1
assert "Traceback" not in completed.stderr
assert result["status"] == "failed"
assert any(f"{label} JSON is not passed: status=invalid" in item for item in result["blocking"])
def test_executable_feature_gates_emit_canonical_feature_identity(tmp_path: Path) -> None:
roadmap = write_final_audit_candidate(tmp_path)
root = roadmap.parents[2]
feature_dir = root / f".codestable/features/{FEATURE_IDENTITY}"
design = feature_dir / f"{FEATURE_SLUG}-design.md"
checklist = feature_dir / f"{FEATURE_SLUG}-checklist.yaml"
evidence_pack = feature_dir / f"{FEATURE_SLUG}-evidence-pack.md"
gate_results = feature_dir / f"{FEATURE_SLUG}-gate-results.json"
dod_results = feature_dir / f"{FEATURE_SLUG}-dod-results.json"
cases = [
(
"codestable-scope-gate.py",
["--feature-dir", feature_dir.relative_to(root).as_posix()],
"scope-gate",
{"feature_dir": feature_dir.relative_to(root).as_posix()},
{},
),
(
"codestable-dod-contract-gate.py",
["--design", design.as_posix()],
"dod-contract-gate",
{"design": design.relative_to(root).as_posix()},
{"design": design},
),
(
"codestable-dod-runner.py",
["--checklist", checklist.as_posix()],
"dod-runner",
{"checklist": checklist.relative_to(root).as_posix()},
{"checklist": checklist},
),
(
"codestable-evidence-pack.py",
[
"--feature",
FEATURE_IDENTITY,
"--design",
design.as_posix(),
"--checklist",
checklist.as_posix(),
"--out",
evidence_pack.as_posix(),
"--dod-results",
dod_results.as_posix(),
"--gate-results",
gate_results.as_posix(),
],
"evidence-pack",
{
"design": design.relative_to(root).as_posix(),
"checklist": checklist.relative_to(root).as_posix(),
"out": evidence_pack.relative_to(root).as_posix(),
"dod_results": dod_results.relative_to(root).as_posix(),
"gate_results": gate_results.relative_to(root).as_posix(),
},
{
"design": design,
"checklist": checklist,
"out": evidence_pack,
"dod_results": dod_results,
"gate_results": gate_results,
},
),
]
for filename, args, gate_id, expected_inputs, digest_paths in cases:
completed = subprocess.run(
[sys.executable, (TOOLS_DIR / filename).as_posix(), *args],
cwd=root,
check=False,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env={"PYTHONDONTWRITEBYTECODE": "1", "PATH": os.environ.get("PATH", "")},
timeout=10,
)
result = json.loads(completed.stdout)
assert "Traceback" not in completed.stderr
assert result["gate_id"] == gate_id
assert result["feature"] == FEATURE_IDENTITY
assert result["inputs"] == expected_inputs
assert result["input_digests"] == {
name: digest(path) for name, path in digest_paths.items()
}
def test_scope_gate_fails_closed_when_git_status_cannot_run(tmp_path: Path) -> None:
root = tmp_path / "repo"
feature_dir = root / f".codestable/features/{FEATURE_IDENTITY}"
feature_dir.mkdir(parents=True)
completed = subprocess.run(
[
sys.executable,
(TOOLS_DIR / "codestable-scope-gate.py").as_posix(),
"--feature-dir",
feature_dir.relative_to(root).as_posix(),
],
cwd=root,
check=False,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env={"PYTHONDONTWRITEBYTECODE": "1", "PATH": os.environ.get("PATH", "")},
timeout=10,
)
result = json.loads(completed.stdout)
assert completed.returncode == 1
assert "Traceback" not in completed.stderr
assert result["status"] == "failed"
assert result["blocking"] == ["git status failed with exit 128"]
assert result["evidence"][0]["git_status"]["exit_code"] == 128