generated from coulomb/repo-seed
Add retained run report helpers
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
<!-- custodian-brief: generated by fix-consistency — do not edit manually -->
|
||||
# Custodian Brief — guide-board
|
||||
|
||||
**Domain:** markitect
|
||||
**Last synced:** 2026-05-15 11:34 UTC
|
||||
**Domain:** markitect
|
||||
**Last synced:** 2026-05-15 11:38 UTC
|
||||
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
|
||||
|
||||
## Active Workstreams
|
||||
|
||||
### Assessment Operations Baseline
|
||||
Progress: 2/6 done | workstream_id: `fc5b1573-91b2-4a19-b6a9-dd4d17057d9b`
|
||||
Progress: 3/6 done | workstream_id: `fc5b1573-91b2-4a19-b6a9-dd4d17057d9b`
|
||||
|
||||
**Open tasks:**
|
||||
- · D2.3 - Run History And Result UX `ce18a2dc`
|
||||
- · D2.4 - Service Job Durability Contract `10e4003c`
|
||||
- · D2.5 - Container Smoke Acceptance `9e2e7fa7`
|
||||
- · D2.6 - External Extension Acceptance Path `65fbf1df`
|
||||
|
||||
@@ -92,6 +92,12 @@ Use the retained run helpers for history:
|
||||
|
||||
```sh
|
||||
PYTHONPATH=src python3 -m guide_board runs list --runs-dir runs
|
||||
PYTHONPATH=src python3 -m guide_board runs latest --runs-dir runs \
|
||||
--target sample-repository \
|
||||
--assessment sample-noop-assessment
|
||||
PYTHONPATH=src python3 -m guide_board runs report --runs-dir runs \
|
||||
--target sample-repository \
|
||||
--assessment sample-noop-assessment
|
||||
PYTHONPATH=src python3 -m guide_board runs trend --runs-dir runs
|
||||
PYTHONPATH=src python3 -m guide_board runs gate --runs-dir runs
|
||||
```
|
||||
|
||||
@@ -18,7 +18,12 @@ from guide_board.planning import (
|
||||
validate_assessment_profile,
|
||||
validate_target_profile,
|
||||
)
|
||||
from guide_board.retention import build_trend_summary, list_retained_runs
|
||||
from guide_board.retention import (
|
||||
build_trend_summary,
|
||||
list_retained_runs,
|
||||
retained_run_report_paths,
|
||||
select_retained_run,
|
||||
)
|
||||
from guide_board.schema import assert_valid
|
||||
from guide_board.service import build_server
|
||||
|
||||
@@ -93,6 +98,17 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
list_runs = runs_commands.add_parser("list", help="list retained run summaries")
|
||||
list_runs.add_argument("--runs-dir", type=Path)
|
||||
list_runs.set_defaults(func=cmd_runs_list)
|
||||
latest_run = runs_commands.add_parser("latest", help="show the latest retained run")
|
||||
latest_run.add_argument("--runs-dir", type=Path)
|
||||
latest_run.add_argument("--target")
|
||||
latest_run.add_argument("--assessment")
|
||||
latest_run.set_defaults(func=cmd_runs_latest)
|
||||
report_run = runs_commands.add_parser("report", help="show report paths for a retained run")
|
||||
report_run.add_argument("--runs-dir", type=Path)
|
||||
report_run.add_argument("--run-id")
|
||||
report_run.add_argument("--target")
|
||||
report_run.add_argument("--assessment")
|
||||
report_run.set_defaults(func=cmd_runs_report)
|
||||
trend_runs = runs_commands.add_parser("trend", help="summarize retained run trends")
|
||||
trend_runs.add_argument("--runs-dir", type=Path)
|
||||
trend_runs.set_defaults(func=cmd_runs_trend)
|
||||
@@ -187,6 +203,39 @@ def cmd_runs_list(args: argparse.Namespace) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def cmd_runs_latest(args: argparse.Namespace) -> dict[str, Any]:
|
||||
runs_dir = args.runs_dir or args.root / "runs"
|
||||
run = select_retained_run(
|
||||
runs_dir,
|
||||
target_profile_ref=args.target,
|
||||
assessment_profile_ref=args.assessment,
|
||||
)
|
||||
return {
|
||||
"runs_dir": str(runs_dir),
|
||||
"selection": {
|
||||
"target_profile_ref": args.target,
|
||||
"assessment_profile_ref": args.assessment,
|
||||
},
|
||||
"run": _run_with_report_paths(run) if run else None,
|
||||
}
|
||||
|
||||
|
||||
def cmd_runs_report(args: argparse.Namespace) -> dict[str, Any]:
|
||||
runs_dir = args.runs_dir or args.root / "runs"
|
||||
run = select_retained_run(
|
||||
runs_dir,
|
||||
run_id=args.run_id,
|
||||
target_profile_ref=args.target,
|
||||
assessment_profile_ref=args.assessment,
|
||||
)
|
||||
if run is None:
|
||||
raise ValueError("no retained run matched the requested selection")
|
||||
return {
|
||||
"runs_dir": str(runs_dir),
|
||||
"run": _run_with_report_paths(run),
|
||||
}
|
||||
|
||||
|
||||
def cmd_runs_trend(args: argparse.Namespace) -> dict[str, Any]:
|
||||
runs_dir = args.runs_dir or args.root / "runs"
|
||||
summary = build_trend_summary(runs_dir)
|
||||
@@ -224,3 +273,10 @@ def _display_path(root: Path, path: Path) -> str:
|
||||
return str(path.resolve().relative_to(root.resolve()))
|
||||
except ValueError:
|
||||
return str(path.resolve())
|
||||
|
||||
|
||||
def _run_with_report_paths(run: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
**run,
|
||||
"paths": retained_run_report_paths(run),
|
||||
}
|
||||
|
||||
@@ -73,6 +73,47 @@ def list_retained_runs(runs_dir: Path) -> list[dict[str, Any]]:
|
||||
return sorted(summaries, key=lambda item: item.get("created_at", ""), reverse=True)
|
||||
|
||||
|
||||
def select_retained_run(
|
||||
runs_dir: Path,
|
||||
run_id: str | None = None,
|
||||
target_profile_ref: str | None = None,
|
||||
assessment_profile_ref: str | None = None,
|
||||
) -> dict[str, Any] | None:
|
||||
"""Return the exact or latest retained run matching the optional selection."""
|
||||
for run in list_retained_runs(runs_dir):
|
||||
if run_id and run.get("run_id") != run_id:
|
||||
continue
|
||||
if target_profile_ref and run.get("target_profile_ref") != target_profile_ref:
|
||||
continue
|
||||
if assessment_profile_ref and run.get("assessment_profile_ref") != assessment_profile_ref:
|
||||
continue
|
||||
return run
|
||||
return None
|
||||
|
||||
|
||||
def retained_run_report_paths(run: dict[str, Any]) -> dict[str, str]:
|
||||
"""Return stable report paths for a retained run summary."""
|
||||
run_dir_value = run.get("run_dir")
|
||||
if not isinstance(run_dir_value, str) or not run_dir_value:
|
||||
raise ValueError("retained run summary is missing run_dir")
|
||||
|
||||
run_dir = Path(run_dir_value)
|
||||
paths: dict[str, str] = {}
|
||||
report_refs = run.get("report_refs", [])
|
||||
if isinstance(report_refs, list):
|
||||
for raw_ref in report_refs:
|
||||
if not isinstance(raw_ref, str) or not raw_ref:
|
||||
continue
|
||||
ref = Path(raw_ref)
|
||||
key = ref.stem.replace("-", "_")
|
||||
paths[key] = str(run_dir / ref)
|
||||
|
||||
paths.setdefault("assessment_package", str(run_dir / "reports" / "assessment-package.json"))
|
||||
paths.setdefault("report", str(run_dir / "reports" / "report.md"))
|
||||
paths.setdefault("retention_summary", str(run_dir / "retention-summary.json"))
|
||||
return dict(sorted(paths.items()))
|
||||
|
||||
|
||||
def build_trend_summary(
|
||||
runs_dir: Path,
|
||||
retained_runs: list[dict[str, Any]] | None = None,
|
||||
|
||||
@@ -16,7 +16,12 @@ from guide_board.planning import (
|
||||
validate_assessment_profile,
|
||||
validate_target_profile,
|
||||
)
|
||||
from guide_board.retention import build_trend_summary, list_retained_runs
|
||||
from guide_board.retention import (
|
||||
build_trend_summary,
|
||||
list_retained_runs,
|
||||
retained_run_report_paths,
|
||||
select_retained_run,
|
||||
)
|
||||
from guide_board.schema import assert_valid
|
||||
from guide_board.service import ServiceHandle, start_service
|
||||
|
||||
@@ -288,6 +293,19 @@ class CoreArchitectureTests(unittest.TestCase):
|
||||
self.assertEqual(gate["status"], "passed")
|
||||
self.assertEqual(gate["passed_groups"], 1)
|
||||
|
||||
latest = select_retained_run(
|
||||
runs_dir,
|
||||
target_profile_ref="sample-repository",
|
||||
assessment_profile_ref="sample-noop-assessment",
|
||||
)
|
||||
self.assertIsNotNone(latest)
|
||||
assert latest is not None
|
||||
self.assertEqual(latest["run_id"], "run-new")
|
||||
self.assertEqual(
|
||||
retained_run_report_paths(latest)["report"],
|
||||
str(runs_dir / "run-new" / "reports" / "report.md"),
|
||||
)
|
||||
|
||||
missing_gate = evaluate_trend_gates(
|
||||
trend,
|
||||
target_profile_ref="missing-target",
|
||||
|
||||
@@ -97,7 +97,7 @@ Progress:
|
||||
|
||||
```task
|
||||
id: GUIDE-BOARD-WP-0002-T003
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "ce18a2dc-7cc9-4fff-9272-5333b6118030"
|
||||
```
|
||||
@@ -109,6 +109,13 @@ Acceptance:
|
||||
report paths.
|
||||
- Preserve the existing run directory contract and retention summary model.
|
||||
|
||||
Progress:
|
||||
|
||||
- Added `guide_board.retention.select_retained_run`.
|
||||
- Added `guide_board.retention.retained_run_report_paths`.
|
||||
- Added `guide-board runs latest` and `guide-board runs report`.
|
||||
- Documented the new commands in `docs/ASSESSMENT-OPERATIONS.md`.
|
||||
|
||||
## D2.4 - Service Job Durability Contract
|
||||
|
||||
```task
|
||||
|
||||
Reference in New Issue
Block a user