chore(repo): initialize team collaboration repository
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run

This commit is contained in:
2026-07-27 20:40:12 +08:00
commit c91a64fddb
109 changed files with 21121 additions and 0 deletions
@@ -0,0 +1,5 @@
"""Evidence Bundle 生成。"""
from .bundle import build_evidence_bundle
__all__ = ["build_evidence_bundle"]
@@ -0,0 +1,69 @@
"""把一次 Run 的可重放事件打成最小证据包。"""
from __future__ import annotations
import json
from pathlib import Path
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from ..config import get_settings
from ..models import EvidenceBundle, Run, RunEvent, iso_z
async def build_evidence_bundle(session: AsyncSession, run: Run) -> EvidenceBundle:
events = (
await session.scalars(
select(RunEvent).where(RunEvent.run_id == run.id).order_by(RunEvent.seq)
)
).all()
root = get_settings().object_store_path / "runs" / run.id
root.mkdir(parents=True, exist_ok=True)
timeline_path = root / "events.ndjson"
timeline = "\n".join(
json.dumps(
{
"seq": event.seq,
"ts": iso_z(event.ts),
"source": event.source,
"kind": event.kind,
"severity": event.severity,
"message": event.message,
"payload": event.payload,
},
ensure_ascii=False,
sort_keys=True,
)
for event in events
)
timeline_path.write_text(timeline + ("\n" if timeline else ""), encoding="utf-8")
manifest = {
"schema_version": 1,
"run_id": run.id,
"workflow": {
"key": run.workflow_key,
"version": run.workflow_version,
"spec_hash": run.spec_hash,
},
"environment_fingerprint": run.env_fingerprint,
"checkpoint": run.checkpoint,
"event_count": len(events),
"files": [{"path": "events.ndjson", "bytes": timeline_path.stat().st_size}],
}
manifest_path = root / "manifest.json"
manifest_path.write_text(
json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True),
encoding="utf-8",
)
size = manifest_path.stat().st_size + timeline_path.stat().st_size
bundle = EvidenceBundle(
run_id=run.id,
uri=str(root),
manifest=manifest,
size_bytes=size,
completeness=1.0,
missing_fields=[],
)
session.add(bundle)
await session.flush()
return bundle