Files
breakpilot-compliance/backend-compliance/compliance/playbook/engine.py
T
Benjamin Admin 78f0ffa9de feat(playbook): Implementation Playbooks — the Berater renderer ("wie komme ich dort hin?")
Roadmap item 4. After WHAT applies / WHAT is missing / WHICH first, the GF asks HOW. The
Implementation Playbook renders, for one capability, the full journey — why / which regulations
it closes / tools / process / evidence / controls — and chains the Optimization Roadmap into
per-measure playbooks. Another renderer over the same Capability spine (ADR-003/004), not a new
engine: ~95% of the data already exists, it just needs a different rendering.

- compliance/playbook/: build_playbook() + playbooks_for_plan() (chains optimization -> playbook,
  acyclic; reuses leverage for "closes which regulations"). Capabilities without curated content
  render as honest status:missing stubs — the content-owed signal.
- knowledge/implementation_playbooks/: curated knowledge layer (Reasoning Knowledge Acquisition),
  two deep expert drafts (SBOM, CVD/PSIRT, status draft, expert-draft-not-normative) + README.
  The bottleneck is now CONTENT, not software; Playbook (own knowledge) != regulatory domain.
- ADR-004: Implementation Playbooks = renderer + knowledge layer; content is the bottleneck.
- reference suite: "Implementation Playbook" section renders the SBOM journey + Roadmap->Playbook
  table (high-leverage caps flagged "fehlt (Inhalt)" — content backlog, highest leverage first).
- refactor: extracted markdown helpers to reference_scenarios/_helpers.py to keep generate.py
  under the 500-LOC budget.

9 playbook tests (40 with optimization+transition+company), mypy --strict clean, check-loc 0.
Product code with no app caller + knowledge/ADR/reference = non-runtime -> no deploy (ADR-001).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-27 10:38:13 +02:00

97 lines
4.3 KiB
Python

"""Implementation Playbook — the Berater renderer ("wie komme ich dort hin?").
After the Capability Delta Engine says WHAT is missing and the Optimization renderer says WHICH
measure first, the Playbook renderer says HOW to implement it. For one capability it assembles the
full journey from three sources:
- curated playbook KNOWLEDGE (why / tools / process steps / evidence / how others do it) — the
Reasoning Knowledge Acquisition layer under `knowledge/implementation_playbooks/`,
- the regulatory LEVERAGE (which regulations a delivered capability closes) — reused from the
Optimization renderer,
- injected Procedure/Control/Evidence links (Execution-owned; empty until linked).
Pure, deterministic, computed-not-stored. Chains optimization -> playbook (acyclic). No new corpus,
no new meta-model class (freeze v1.0). Python 3.9 compatible.
The curated content is an EXPERT DRAFT, never a normative requirement. When no playbook knowledge
exists for a capability yet, the renderer emits a `status: missing` stub — the honest signal that
the bottleneck is CONTENT (Knowledge Acquisition), not software.
"""
from __future__ import annotations
from typing import Any, Dict, List, Optional
from ..optimization import OptimizationPlan
from .schemas import Playbook, PlaybookStep
_MISSING_WHY = "(Playbook-Inhalt fehlt — Knowledge Acquisition offen.)"
_DRAFT_DISCLAIMER = (
"Kuratiertes Experten-Wissen (Erstentwurf), KEINE normative Anforderung. Tools/Schritte sind "
"Empfehlungen, kein Pflichtkatalog; Controls werden aus der Execution-Schicht injiziert."
)
def _steps(raw: Any) -> List[PlaybookStep]:
steps: List[PlaybookStep] = []
for i, s in enumerate(raw or [], 1):
steps.append(PlaybookStep(order=i, title=str(s.get("title", "")), detail=str(s.get("detail", ""))))
return steps
def build_playbook(
capability_id: str,
knowledge: Optional[Dict[str, Any]] = None,
closes_regulations: Optional[List[str]] = None,
control_links: Optional[List[str]] = None,
) -> Playbook:
"""Assemble the implementation journey for ONE capability.
`knowledge`: the curated playbook dict (None/empty -> a `missing` stub). `closes_regulations`:
the regulations a delivered capability closes (leverage, from `covers_targets`). `control_links`:
Execution-owned control refs, injected (default empty — no Execution data in Reasoning code).
"""
closes = sorted(set(closes_regulations or []))
if not knowledge:
return Playbook(
capability_id=capability_id, title=capability_id, why=_MISSING_WHY,
closes_regulations=closes, leverage=len(closes), controls=list(control_links or []),
status="missing", disclaimer=_DRAFT_DISCLAIMER,
)
return Playbook(
capability_id=capability_id,
title=str(knowledge.get("title", capability_id)),
why=str(knowledge.get("why", "")),
closes_regulations=closes,
leverage=len(closes),
tools=list(knowledge.get("tools", [])),
process_steps=_steps(knowledge.get("process_steps")),
expected_evidence=list(knowledge.get("expected_evidence", [])),
controls=list(control_links or []),
how_others_do_it=str(knowledge.get("how_others_do_it", "")),
status=str(knowledge.get("status", "draft")),
disclaimer=str(knowledge.get("disclaimer", _DRAFT_DISCLAIMER)),
)
def playbooks_for_plan(
plan: OptimizationPlan,
knowledge_by_cap: Dict[str, Dict[str, Any]],
top_k: Optional[int] = None,
control_links_by_cap: Optional[Dict[str, List[str]]] = None,
) -> List[Playbook]:
"""Render playbooks for the highest-leverage measures of an OptimizationPlan (Roadmap -> How).
Walks the ranked measures (top_k, or all) and builds each capability's playbook, using the
measure's own `covers` as the regulations it closes. Measures without curated knowledge become
`missing` stubs — surfacing exactly where playbook content is still owed.
"""
links = control_links_by_cap or {}
measures = plan.ranked_measures if top_k is None else plan.ranked_measures[: max(0, top_k)]
return [
build_playbook(
m.capability_id, knowledge_by_cap.get(m.capability_id),
closes_regulations=m.covers, control_links=links.get(m.capability_id),
)
for m in measures
]