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>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""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
|
||||
]
|
||||
Reference in New Issue
Block a user