fix(onboarding): apply hypothesis/vocabulary review decisions (ISO13485, patch-policy rationale, summary)

Two reviewed knowledge decisions (2026-06-28) + the deferred cosmetic counter, before #59.

1. ISO13485 removed from the incident_management hypothesis. ISO 13485 CAPA / quality-safety incident
   handling is NOT security incident management — the mapping was too broad and would seed false
   hypotheses for the empirical loop. A dedicated manage_quality_and_safety_incidents capability can come
   later IF a target needs it; not forced now. (ISO27001/TISAX/IEC62443 keep incident_management.)

2. patch_policy_doc -> secure_signed_update_distribution stays `partial`, but the curated rationale is
   sharpened: "indicates update governance, does not evidence signed distribution" (a patch policy is not
   proof of SIGNED distribution). New optional SignalMapping.rationale field carries the curated note.
   (github_actions_ci -> SDL and dependency_scanning -> vuln-mgmt reviewed and APPROVED as-is.)

3. Cosmetic (folded in since we touched the file): the silent-intake summary now counts detected and
   indications SEPARATELY ("N automatisch erkannt, M Indikation(en)") instead of lumping partial signals
   into "automatisch erkannt" — consistent with the three-state model just shipped.

Tests: ISO13485 no longer resolves to incident_management; summary counts split correctly. 29 onboarding
tests pass, mypy --strict clean, demo runs, check-loc 0. Runtime-visible (hypothesis resolution + summary
text) -> deploy + smoke.
This commit is contained in:
Benjamin Admin
2026-06-28 16:18:28 +02:00
parent 3202e555ab
commit 77459d06d6
5 changed files with 23 additions and 5 deletions
@@ -41,6 +41,7 @@ class SignalMapping(BaseModel):
evidence: Optional[str] = None # the artifact found (already in hand -> no upload needed)
product_fact: Optional[str] = None # e.g. "connected_to_internet"
fact_value: str = "true"
rationale: str = "" # curated note: WHY only indicative (esp. for partial mappings)
class DetectedCapability(BaseModel):
@@ -111,10 +112,12 @@ def silent_intake(
detected = [caps[k] for k in sorted(caps)]
product_facts = [facts[k] for k in sorted(facts)]
requirements_seen = sorted(requirements)
n_detected = sum(1 for d in detected if d.relationship == "detected") # concrete artifacts -> auto-detected
n_indication = len(detected) - n_detected # partial -> indication, still asked
summary = (
"Stille Vorbefüllung: %d Fähigkeit(en) automatisch erkannt, %d Produktfakt(en), %d Nachweis(e) "
"bereits vorhanden, %d Anforderung(en) erkannt (nicht als vorhanden gewertet)."
% (len(detected), len(product_facts), len(evidence), len(requirements_seen))
"Stille Vorbefüllung: %d Fähigkeit(en) automatisch erkannt, %d Indikation(en), %d Produktfakt(en), "
"%d Nachweis(e) bereits vorhanden, %d Anforderung(en) erkannt (nicht als vorhanden gewertet)."
% (n_detected, n_indication, len(product_facts), len(evidence), len(requirements_seen))
)
return SilentIntakeResult(
detected_capabilities=detected, product_facts=product_facts,