feat: implement project bus MVP

This commit is contained in:
Codex Lead Engineer
2026-07-30 02:13:26 +02:00
commit bc55924198
28 changed files with 3518 additions and 0 deletions
+428
View File
@@ -0,0 +1,428 @@
from __future__ import annotations
import sqlite3
import tempfile
import threading
import unittest
from pathlib import Path
from project_bus.db import Database
from project_bus.errors import AuthorizationError, ConflictError, ValidationError
from project_bus.models import Principal
from project_bus.service import ProjectBusService
class ServiceTestCase(unittest.TestCase):
def setUp(self) -> None:
self.temporary = tempfile.TemporaryDirectory()
self.database_path = Path(self.temporary.name) / "bus.db"
self.database = Database(self.database_path)
self.service = ProjectBusService(self.database)
self.service.initialize()
self.system = Principal("system", "system", "System")
self.service.create_project(
self.system,
project_id="sandbox",
name="Sandbox",
idempotency_key="create-sandbox",
)
self.principals: dict[str, Principal] = {}
for actor_id, role in (
("po", "PO"),
("pm", "PM"),
("pa", "PA"),
("lead", "LEAD_ENGINEER"),
("impl2", "IMPLEMENTER"),
("reviewer", "REVIEWER"),
("security", "SECURITY_REVIEWER"),
):
self.service.register_actor(
self.system,
project_id="sandbox",
actor_id=actor_id,
auth_subject=f"subject-{actor_id}",
display_name=actor_id.title(),
role=role,
idempotency_key=f"register-{actor_id}",
)
self.principals[actor_id] = Principal(
actor_id, f"subject-{actor_id}", actor_id.title()
)
def tearDown(self) -> None:
self.temporary.cleanup()
def issue(self, work_package_id: str = "WP-001") -> None:
self.service.issue_work_package(
self.principals["pm"],
project_id="sandbox",
work_package_id=work_package_id,
title="Build it",
description="Implement the bounded feature.",
acceptance_criteria=["Tests pass", "Evidence linked"],
idempotency_key=f"issue-{work_package_id}",
)
def submit_and_review(self, work_package_id: str = "WP-001") -> str:
self.service.claim_work_package(
self.principals["lead"],
project_id="sandbox",
work_package_id=work_package_id,
idempotency_key=f"claim-{work_package_id}",
)
self.service.submit_result(
self.principals["lead"],
project_id="sandbox",
work_package_id=work_package_id,
summary="Implemented.",
evidence=[{"type": "test", "value": "all green"}],
idempotency_key=f"result-{work_package_id}",
)
requested = self.service.request_review(
self.principals["pa"],
project_id="sandbox",
work_package_id=work_package_id,
reviewer_id="reviewer",
review_type="technical",
idempotency_key=f"request-review-{work_package_id}",
)
self.service.submit_review(
self.principals["reviewer"],
project_id="sandbox",
review_id=requested["review_id"],
verdict="APPROVE",
findings=[],
summary="Approved independently.",
idempotency_key=f"review-{work_package_id}",
)
return requested["review_id"]
def test_full_workflow_gate_and_baseline(self) -> None:
self.issue()
self.submit_and_review()
linked = self.service.link_commit(
self.principals["lead"],
project_id="sandbox",
work_package_id="WP-001",
repository="git.example/project-bus",
commit_sha="0123456789abcdef",
relation="implementation",
idempotency_key="link-commit",
)
self.assertEqual(linked["event"]["event_type"], "commit.linked")
gate = self.service.close_gate(
self.principals["pm"],
project_id="sandbox",
work_package_id="WP-001",
outcome="ACCEPT",
rationale="Criteria and review satisfied.",
idempotency_key="close-gate",
)
self.assertEqual(gate["status"], "ACCEPTED")
baseline = self.service.baseline_release(
self.principals["pm"],
project_id="sandbox",
version="0.1.0",
artifact_uri="https://artifacts.example/project-bus-0.1.0.tar.gz",
digest="sha256:abc",
included_work_packages=["WP-001"],
idempotency_key="release-010",
)
self.assertEqual(baseline["version"], "0.1.0")
with self.assertRaises(ConflictError):
self.service.close_gate(
self.principals["pm"],
project_id="sandbox",
work_package_id="WP-001",
outcome="HOLD",
rationale="Cannot reopen a terminal gate.",
idempotency_key="reopen-gate",
)
with self.assertRaises(ConflictError):
self.service.baseline_release(
self.principals["pm"],
project_id="sandbox",
version="0.1.0",
artifact_uri="https://artifacts.example/other.tar.gz",
digest="sha256:different",
included_work_packages=["WP-001"],
idempotency_key="duplicate-release-version",
)
events = self.service.sync_since(
self.principals["pa"], project_id="sandbox", cursor=0, limit=100
)
self.assertEqual(events["events"][-1]["event_type"], "baseline.released")
self.assertFalse(events["has_more"])
def test_pa_cannot_record_decision_or_close_gate(self) -> None:
with self.assertRaises(AuthorizationError):
self.service.record_decision(
self.principals["pa"],
project_id="sandbox",
decision_id="DEC-001",
kind="ARCHITECTURE",
title="Architecture",
decision="Use option A.",
rationale="Because.",
work_package_id=None,
idempotency_key="pa-decision",
)
self.issue()
with self.assertRaises(AuthorizationError):
self.service.close_gate(
self.principals["pa"],
project_id="sandbox",
work_package_id="WP-001",
outcome="HOLD",
rationale="Waiting.",
idempotency_key="pa-gate",
)
def test_only_po_can_record_product_decision(self) -> None:
with self.assertRaises(AuthorizationError):
self.service.record_decision(
self.principals["pm"],
project_id="sandbox",
decision_id="DEC-PRODUCT-1",
kind="PRODUCT",
title="Product scope",
decision="Add a feature.",
rationale="Customer need.",
work_package_id=None,
idempotency_key="pm-product",
)
result = self.service.record_decision(
self.principals["po"],
project_id="sandbox",
decision_id="DEC-PRODUCT-1",
kind="PRODUCT",
title="Product scope",
decision="Add a feature.",
rationale="Customer need.",
work_package_id=None,
idempotency_key="po-product",
)
self.assertEqual(result["kind"], "PRODUCT")
def test_reviewer_must_be_independent_and_have_review_role(self) -> None:
self.issue()
self.service.claim_work_package(
self.principals["lead"],
project_id="sandbox",
work_package_id="WP-001",
idempotency_key="claim",
)
self.service.submit_result(
self.principals["lead"],
project_id="sandbox",
work_package_id="WP-001",
summary="Done.",
evidence=[],
idempotency_key="result",
)
with self.assertRaises(ValidationError):
self.service.request_review(
self.principals["pa"],
project_id="sandbox",
work_package_id="WP-001",
reviewer_id="lead",
review_type="technical",
idempotency_key="self-review",
)
def test_gate_accept_requires_approved_review(self) -> None:
self.issue()
self.service.claim_work_package(
self.principals["lead"],
project_id="sandbox",
work_package_id="WP-001",
idempotency_key="claim",
)
self.service.submit_result(
self.principals["lead"],
project_id="sandbox",
work_package_id="WP-001",
summary="Done.",
evidence=[],
idempotency_key="result",
)
with self.assertRaises(ConflictError):
self.service.close_gate(
self.principals["pm"],
project_id="sandbox",
work_package_id="WP-001",
outcome="ACCEPT",
rationale="Premature.",
idempotency_key="premature-gate",
)
def test_idempotent_replay_and_key_mismatch(self) -> None:
first = self.service.issue_work_package(
self.principals["pm"],
project_id="sandbox",
work_package_id="WP-001",
title="Build it",
description="First request.",
acceptance_criteria=["Pass"],
idempotency_key="same-key",
)
second = self.service.issue_work_package(
self.principals["pm"],
project_id="sandbox",
work_package_id="WP-001",
title="Build it",
description="First request.",
acceptance_criteria=["Pass"],
idempotency_key="same-key",
)
self.assertFalse(first["idempotent_replay"])
self.assertTrue(second["idempotent_replay"])
self.assertEqual(first["event"]["event_id"], second["event"]["event_id"])
with self.assertRaises(ConflictError):
self.service.issue_work_package(
self.principals["pm"],
project_id="sandbox",
work_package_id="WP-OTHER",
title="Different",
description="Different request.",
acceptance_criteria=["Pass"],
idempotency_key="same-key",
)
def test_concurrent_claim_has_single_winner(self) -> None:
self.issue()
barrier = threading.Barrier(2)
outcomes: list[str] = []
lock = threading.Lock()
def claim(actor_id: str) -> None:
barrier.wait()
try:
self.service.claim_work_package(
self.principals[actor_id],
project_id="sandbox",
work_package_id="WP-001",
idempotency_key=f"claim-{actor_id}",
)
value = "won"
except ConflictError:
value = "lost"
with lock:
outcomes.append(value)
first = threading.Thread(target=claim, args=("lead",))
second = threading.Thread(target=claim, args=("impl2",))
first.start()
second.start()
first.join()
second.join()
self.assertCountEqual(outcomes, ["won", "lost"])
def test_cursor_pagination_has_no_duplicates(self) -> None:
self.issue("WP-001")
self.issue("WP-002")
first = self.service.sync_since(
self.principals["pa"], project_id="sandbox", cursor=0, limit=3
)
second = self.service.sync_since(
self.principals["pa"],
project_id="sandbox",
cursor=first["next_cursor"],
limit=100,
)
first_ids = {event["event_id"] for event in first["events"]}
second_ids = {event["event_id"] for event in second["events"]}
self.assertFalse(first_ids & second_ids)
self.assertTrue(first["has_more"])
def test_work_package_ids_are_project_scoped_and_reads_are_isolated(self) -> None:
self.issue("WP-001")
self.service.create_project(
self.system,
project_id="other",
name="Other",
idempotency_key="create-other",
)
self.service.register_actor(
self.system,
project_id="other",
actor_id="pm",
auth_subject="subject-pm",
display_name="Pm",
role="PM",
idempotency_key="other-register-pm",
)
self.service.issue_work_package(
self.principals["pm"],
project_id="other",
work_package_id="WP-001",
title="Same local identifier",
description="Different project.",
acceptance_criteria=["Isolated"],
idempotency_key="other-issue-wp",
)
with self.assertRaises(AuthorizationError):
self.service.get_work_package(
self.principals["pa"],
project_id="other",
work_package_id="WP-001",
)
def test_event_log_rejects_update_and_delete(self) -> None:
self.issue()
with self.database.transaction(write=True) as connection:
event_id = connection.execute(
"SELECT event_id FROM event_log ORDER BY cursor LIMIT 1"
).fetchone()["event_id"]
with self.assertRaises(sqlite3.IntegrityError):
connection.execute(
"UPDATE event_log SET event_type = 'tampered' WHERE event_id = ?",
(event_id,),
)
with self.database.transaction(write=True) as connection:
with self.assertRaises(sqlite3.IntegrityError):
connection.execute("DELETE FROM event_log")
def test_baseline_rejects_unaccepted_work_package(self) -> None:
self.issue()
with self.assertRaises(ConflictError):
self.service.baseline_release(
self.principals["pm"],
project_id="sandbox",
version="bad",
artifact_uri="artifact://bad",
digest="sha256:bad",
included_work_packages=["WP-001"],
idempotency_key="bad-baseline",
)
def test_escalation_can_be_raised_by_pa_but_only_resolved_by_pm(self) -> None:
escalation = self.service.raise_escalation(
self.principals["pa"],
project_id="sandbox",
severity="HIGH",
title="Decision needed",
description="Tolerance exceeded.",
target_role="PM",
idempotency_key="raise-escalation",
)
with self.assertRaises(AuthorizationError):
self.service.resolve_escalation(
self.principals["pa"],
project_id="sandbox",
escalation_id=escalation["escalation_id"],
resolution="Resolved by PA.",
idempotency_key="pa-resolve",
)
resolved = self.service.resolve_escalation(
self.principals["pm"],
project_id="sandbox",
escalation_id=escalation["escalation_id"],
resolution="PM supplied the required decision.",
idempotency_key="pm-resolve",
)
self.assertEqual(resolved["status"], "RESOLVED")
if __name__ == "__main__":
unittest.main()