314dc03b0d
Moves the orchestrator into bot_bottle/orchestrator/ so one install gets everything. Entry point is now `python -m bot_bottle.orchestrator run`. - Add bot_bottle/orchestrator/ with all 14 modules (verbatim move; internal imports were already relative, so no changes inside orchestrator modules) - Rewrite bootstrap.py: remove the lazy bot_bottle import guard, use direct relative imports from ..contrib.* - Add bot_bottle/contrib/forge/base.py: ScopedForge (read-anywhere / write-scoped) - Add bot_bottle/contrib/gitea/client.py: GiteaClient + GiteaForge (urllib.request only) - Add bot_bottle/contrib/gitea/forge_state.py: ForgeState + SqliteForgeStateStore - Add tests/unit/orchestrator/ (82 tests: 63 migrated + 19 new for contrib modules) Closes #321
54 lines
1.9 KiB
Python
54 lines
1.9 KiB
Python
"""Unit: provenance assembly + serialization."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from bot_bottle.orchestrator.model import RunRecord
|
|
from bot_bottle.orchestrator.provenance import build_provenance, ops_from_log, provenance_to_dict
|
|
|
|
|
|
def _record() -> RunRecord:
|
|
return RunRecord(
|
|
owner="didericis", repo="bot-bottle", issue_number=17,
|
|
slug="impl-17", agent_name="impl", bottle_names=["claude"],
|
|
last_checkin_at="2026-07-01T00:05:00-04:00",
|
|
)
|
|
|
|
|
|
class ProvenanceTest(unittest.TestCase):
|
|
def test_ops_from_log(self):
|
|
ops = ops_from_log([
|
|
{"at": "T1", "op": "read_pr", "target": 5, "detail": "ok"},
|
|
{"at": "T2", "op": "signal_done", "target": None, "detail": "success: done"},
|
|
])
|
|
self.assertEqual(2, len(ops))
|
|
self.assertEqual("read_pr", ops[0].op)
|
|
self.assertIsNone(ops[1].target)
|
|
|
|
def test_build_and_serialize(self):
|
|
ops = ops_from_log([{"at": "T1", "op": "post_comment", "target": 17, "detail": "ok"}])
|
|
prov = build_provenance(
|
|
_record(), ops=ops, started_at="2026-07-01T00:00:00-04:00",
|
|
finished_at="2026-07-01T00:05:00-04:00", exit_code=0, watchdog_fired=False,
|
|
)
|
|
d = provenance_to_dict(prov)
|
|
self.assertEqual("impl-17", d["slug"])
|
|
self.assertEqual("didericis", d["owner"])
|
|
self.assertEqual(["claude"], d["bottles"])
|
|
self.assertEqual(0, d["exit_code"])
|
|
self.assertFalse(d["watchdog_fired"])
|
|
self.assertEqual(1, len(d["ops"]))
|
|
self.assertEqual("post_comment", d["ops"][0]["op"])
|
|
|
|
def test_watchdog_flag_serialized(self):
|
|
prov = build_provenance(
|
|
_record(), ops=(), started_at="", finished_at="",
|
|
exit_code=None, watchdog_fired=True,
|
|
)
|
|
self.assertTrue(provenance_to_dict(prov)["watchdog_fired"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|