feat: engagement close-session wires vault, metrics, Kai ledger (WP-0009 T09)
Some checks failed
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 9m26s
ci / test (push) Failing after 4s

Add close_session helpers and CLI to append vault session logs, engagement-
scoped metrics, duty Kai charges, and client reports. Rejects sensitive
summaries. Pilot smoke-closed once; prepare points operators at close-session.
This commit is contained in:
tegwick 2026-07-16 12:09:05 +02:00
parent ad5965be91
commit 4532196546
11 changed files with 588 additions and 14 deletions

View file

@ -14,12 +14,15 @@ from kaizen_agentic.engagement import (
EngagementError,
build_prepare_bundle,
checklist_summary,
close_session,
compute_duty_kai,
load_checklist,
load_engagement,
parse_checklist_markdown,
set_checklist_item_status,
set_phase,
staff_engagement,
text_has_sensitive_content,
validate_engagement,
)
@ -159,6 +162,71 @@ class TestStaffAndLifecycle:
assert eng.phase == "closed"
class TestCloseSession:
def test_compute_duty_kai(self):
assert (
compute_duty_kai("standard_review", tier=4, access_class="host_observe")
== 1700
)
assert compute_duty_kai("ramp_up_package", tier=4) == 10000
assert compute_duty_kai("short_assist", tier=1, amount_override=50) == 50
def test_sensitive_summary_rejected(self, mini_repo: Path):
eng = staff_engagement(
engagement_id="eng-close-sens",
role_id="host-operator",
client_id="c",
target_id="h1",
repo_root=mini_repo,
)
with pytest.raises(EngagementError, match="sensitive"):
close_session(
eng,
success=True,
summary="password: hunter2 leaked",
record_metrics=False,
record_ledger=False,
write_report=False,
)
assert text_has_sensitive_content("-----BEGIN RSA PRIVATE KEY-----")
def test_close_session_writes_all_artifacts(self, mini_repo: Path):
eng = staff_engagement(
engagement_id="eng-close-001",
role_id="host-operator",
client_id="coulomb",
target_id="railiance01",
repo_root=mini_repo,
)
result = close_session(
eng,
success=True,
duty="standard_review",
summary="first health pass watch-level disk",
execution_time_s=90.0,
quality=0.85,
access_class="host_observe",
)
assert result["amount_kai"] == 1700
assert result["metrics_recorded"] is True
mem = Path(result["memory_path"]).read_text(encoding="utf-8")
assert "first health pass" in mem
assert "session_count: 1" in mem or "session_count: 1" in mem.replace('"', "")
report = Path(result["report_path"])
assert report.exists()
assert "first health pass" in report.read_text(encoding="utf-8")
ledger = (
Path(result["ledger_path"]).read_text(encoding="utf-8").strip().splitlines()
)
last = json.loads(ledger[-1])
assert last["amount_kai"] == 1700
assert last["product"] == "standard_review"
assert "password" not in last
metrics_path = Path(result["metrics_path"])
assert metrics_path.exists()
assert "engagement_id" in metrics_path.read_text(encoding="utf-8")
class TestEngagementCli:
def test_staff_list_checklist_prepare(self, runner: CliRunner, mini_repo: Path):
result = runner.invoke(
@ -363,3 +431,46 @@ class TestEngagementCli:
)
assert result.exit_code == 0, result.output
assert "72800" in result.output or "Kai" in result.output
def test_close_session_cli(self, runner: CliRunner, mini_repo: Path):
runner.invoke(
cli,
[
"engagement",
"staff",
"--id",
"eng-close-cli",
"--role",
"host-operator",
"--client",
"coulomb",
"--target",
"railiance01",
"--repo-root",
str(mini_repo),
],
)
result = runner.invoke(
cli,
[
"engagement",
"close-session",
"eng-close-cli",
"--success",
"--duty",
"standard_review",
"--summary",
"load review healthy",
"--time",
"60",
"--quality",
"0.9",
"--repo-root",
str(mini_repo),
"--json",
],
)
assert result.exit_code == 0, result.output
data = json.loads(result.output)
assert data["amount_kai"] == 1700
assert data["metrics_recorded"] is True