Prior gitea push's build-ai-sdk failed on a transient registry push (arm64 built
clean on macmini; amd64 cross-compile is green) and last-build/main got poisoned
to that SHA, so a plain re-run scopes to nothing. A real touch in ai-compliance-sdk/
re-scopes the build. Also documents the synced-copy contract for
data/obligations/obligation_join_keys.json.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Aligns provide_security_updates -> SI-2 evidence to the curated acceptance set:
config_export (secure-update mechanism config) + test_report (patch verification).
For "provide updates" the patch-verification test is more on-point than a vuln
scan; repo_scan stays on CM-7 for attack-surface.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Schema-Papier statt capabilities.json (User-Entscheidung). Befund: die 8 SHARED_CAPABILITY-
Cluster zerfallen in Typ-1 (technische Capabilities: mfa/tls/code_signing/session/anomaly)
und Typ-2 (Sicherheitsziele: attack_surface_min/software_integrity = die #4-Gaps). Empfehlung
Modell C: Capability = EINZIGE neue Klasse; Sicherheitsziele = CORE Legal Obligations
(CORE/DOMAIN existiert bereits). Kanten-Graph (realized_by/specializes/...). guidance_basis
gehört konzeptionell an die Capability. 4 Entscheidungen offen (User). #5b Materialisierung
GEGATED auf Modell-Annahme — keine Daten verschoben.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Registry filled proposed_obligation_id for the 3 NIST primary_implementation
controls: SI-7->signed_update_integrity, SI-2->provide_security_updates,
CM-7->remote_access_attack_surface_min. Adopted onto cra_nist.jsonl so the join
is now EXACT (obligation_id) instead of the coarse citation_unit fallback.
obligation-status now surfaces SI-2 under provide_security_updates; test extended.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Vertical slice over the Compliance Execution Graph: obligation_id -> accepted
controls -> required evidence -> status. NEVER auto-asserts fulfillment - with
no evidence collection wired (MVP), a mapped obligation is "not_assessed" and
every required evidence is "missing". Fail-closed: no id -> 400; unknown id ->
unknown_obligation; mapped-but-no-control -> unmapped; graph not loaded -> 503.
- ComplianceGraphHandlers (separate from the DB-backed ObligationsHandlers):
loads Registry join keys + accepted control mappings + evidence once at start.
- LoadComplianceGraph: candidate-path resolution across dev/container/test.
- Data plumbing: Dockerfile now COPYs data/{control_mappings,evidence_requirements,
obligations}; data/obligations/obligation_join_keys.json is a SYNCED COPY of the
repo-root Registry contract (re-sync on Registry growth).
- Table-driven handler test (mapped/unmapped/unknown/400 + no-fulfillment-claim).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds SI-7/SI-2/CM-7 to controls_for_obligation_mapping.json (7 OWASP -> 10),
mapping_type=primary_implementation (the single canonical control per obligation).
proposed_obligation_id left empty for the Registry to assign. Notes aligned to the
updates family (join_keys 93): SI-2 -> provide_security_updates (strong),
SI-7 -> signed_update_integrity (partial; SI-7 broader), CM-7 ->
remote_access_attack_surface_min (partial; CM-7 broader).
Origin-only (data/tooling; backend does not load obligations/* at runtime) -> no Orca.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CRA Annex I Part I (2)(e)/(2)(l)/(2)(i) had no clean OWASP target (rejected:
"Mapping ueber NIST/BSI erforderlich"). Their NIST home, curated + accepted:
(2)(e) Integritaet -> SI-7 (Software/Firmware/Information Integrity)
(2)(l) Sichere Updates -> SI-2 (Flaw Remediation)
(2)(i) Angriffsflaeche -> CM-7 (Least Functionality)
New mapping_type=primary_implementation = the single canonical control per
obligation (stronger than implements/supports); related controls (SC-3(3),
RA-5, AC-6, SI-16, ...) follow later as supports.
Evidence is framework-AGNOSTIC: SI-7/SI-2/CM-7 reuse the shared evidence_type
catalog (config_export/test_report/repo_scan) - same types carry CRA, NIST,
ISO 27001, IEC 62443, BSI. (framework,control) is only the link, not the type.
obligation_id left empty: the Obligation Registry assigns it (exported via
controls_for_obligation_mapping.json), then we adopt. go test ./internal/ucca green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Obligation Registry filled proposed_obligation_id (7/7) + cut the logging
family (obligations 47->66). Adopted obligation_id onto our 7 accepted CRA->OWASP
mappings; the join now prefers the EXACT obligation_id over the coarse
citation_unit (which stays as fallback for not-yet-adopted rows).
Effect: semantic coverage 2->4 (user_authentication_required,
credential_confidentiality_protection, auth_key_management,
event_logging_security_events). Befund 1 resolved: V11.2.1 crypto now sits under
credential_confidentiality_protection, not user_authentication_required.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
V6.x->user_authentication_required, V11.2.1->credential_confidentiality_protection,
V11.7.1->auth_key_management; semantisch (NICHT CRA-Anker, die sind approximativ).
V16.x pending bis Logging-Cut. anchor_quality_note dokumentiert.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
obligations/controls_for_obligation_mapping.json — the Compliance Execution
Graph's accepted controls (V6 auth / V11 crypto / V16 logging) handed to the
Obligation Registry to propose the SEMANTIC control->obligation_id, replacing
the coarse citation_unit interim join (Befund 1). Registry fills
proposed_obligation_id; we then adopt it into control_mapping.obligation_id.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AssessObligationStatus traverses obligation_id -> (citation_unit) -> accepted
controls -> required evidence -> status (erfuellt|offen|unklar). Evidence
presence is a callback; MVP passes nil (nothing collected yet) -> offen.
citation_spans = "pending" until the Legal-Knowledge-Graph session attaches
them. This is the vertical slice that makes the graph a product feature:
"CRA obligation fulfilled because evidence X/Y/Z is present", not "a doc exists".
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Consumes the cross-session contract obligations/obligation_join_keys.json (47
obligation_ids). Interim bridge = citation_unit (our source_norm <-> registry
citation_units), to be hardened to the stable obligation_id (field now optional
on ControlMapping).
ComputeObligationCoverage joins the 47 registry obligations to our accepted
control mappings: covered=2 (user_authentication_required, firmware_software_
authentication), mapped_rejected=3 ((2)(e) -> our OWASP mappings rejected,
route via NIST/BSI), uncovered=42. This coverage signal is the feedback to the
Obligation session for what to cut/refine next.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Macht meine Seite des Cross-Session-Vertrags konkret: obligation_id ist der stabile Join-Key
zwischen Legal Knowledge Graph (citation_spans -> obligation_id) und Compliance Execution Graph
(control_mapping.source_norm -> obligation_id). Export aller 47 obligation_ids (CRA: 11 sbom +
7 vuln + 29 auth) mit citation_units als Interim-Brücke. Disziplin: obligation_id nie neu
vergeben (re-link, Pendant zu span_id/control_uuid).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The last edge of the compliance graph: what concrete, fresh evidence proves a
framework control is met (config_export/test_report/sbom/audit_log/pentest/...
from github/ci/scanner/manual_upload, with a freshness requirement).
Seeded for all 7 accepted CRA->OWASP controls (Auth/Crypto/Logging). A graph
test enforces connectivity: every accepted control must carry >=1 required
evidence — no dangling node in Obligation -> Control -> Evidence.
This is what will let the Advisor state "the CRA requirement is fulfilled" from
present evidence, not from the mere existence of a document.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
7 accepted, 13 rejected (reviewed_by=benjamin, 2026-06-25). The accepted set is
the first audited ground truth of the compliance graph:
(2c) Zugriff -> V6.3.1, V6.1.1 (Auth)
(2d) Crypto -> V11.2.1, V11.7.1 (corrected from the retriever's wrong V14)
(2k) Logging -> V16.3.3, V16.3.4, V16.1.1
Rejected stay as audit trail. (2e) integrity, (2l) updates, (2i) attack surface
rejected with reason "OWASP ASVS not the right target standard, map via NIST/BSI"
— architectural proof for the multi-framework framework_* layer.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- DROP confidence from the persisted mapping: a curated mapping is a
professional statement, not an AI guess (retriever score -> rationale only).
- ADD mapping_status (candidate|accepted|rejected|superseded) — the review state.
- ADD audit trail (reviewed_by/review_date/review_reason); accepted/rejected
fail-closed without it.
- EXTEND mapping_type: + implements, + contradicts.
- Advisor truth = mapping_status=accepted (acceptedOnly filter).
- migrate the 18 CRA->OWASP rows to mapping_status=candidate.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
18 retriever_candidate mappings generated via the sdk-dev control-intent
retriever. All marked retriever_candidate (NOT curated truth) — the review
step turns the good ones into human_curated.
Empirical validation of the A-decision: the retriever proposes, but produces
wrong candidates (e.g. encryption -> V14 Config instead of V11 Crypto;
V14.2.4 over-appears) that only human review catches. Review notes inline.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Versioned JSONL store + Go model for Regulation->Control mappings, per the
A-decision: the retriever only PROPOSES candidates; the curated mapping is the
audited truth the Advisor uses at runtime, never re-invented per query.
- ControlMapping struct (source_norm/source_role/target_framework/target_control/
mapping_type/confidence/provenance/rationale/version)
- enum validation (rule layer), fail-closed loader, forward+reverse index,
curated-only filter (IsCurated)
- seed: 2 retriever_candidate rows CRA Annex I -> OWASP ASVS (not yet curated)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Schließt die Lücke Obligation→Procedure→Control→Evidence (Schritt 3, Compliance-OS-Ebene).
Procedure = Umsetzungs-/Nachweisebene EINER Obligation, KEINE neue Pflicht (LEGAL_MINIMUM
bleibt an der Obligation; Procedure beschreibt Umsetzung; Evidence belegt sie).
- 11 Procedures (5 SBOM + 6 Vuln), 2 Worked Examples; source_role=procedural_requirement
(Konvergenz mit der Legal-Knowledge-Engine der anderen Session)
- fulfills_obligations[] referenziert die cra.json-Obligations (alle gültig, volle Abdeckung)
- steps/controls/evidence je Procedure; KEINE tier/legal_basis-Felder (kein Pflicht-Duplikat)
- citation_spans: [] / pending_span_anchor (Join folgt mit dem zitierfähigen Re-Ingest)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
9 docs + index in docs-src/architecture/ documenting the deterministic
retrieval engine: retrieval pipeline, authority rerank, source_class,
source_role, control-intent + diversity, assessment, confidence,
explainability + supersede, framework_* layer. Each doc carries the exact
constants, the rationale behind them, code refs, and the failure class
it addresses. Audit/onboarding reference.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
On an implementation question impl_guidance (ENISA) keeps its earned semantic
Top-1, but the top-K now surfaces the best operational_requirement and
control_standard from the pool (ensureControlDiversity) — so different source
roles are visible instead of one role flooding the list, without forcing the
binding sources to Top-1.
A recognised standard NAME (NIST/OWASP/ISO 27001/CIS/CSA CCM/Grundschutz) now
overrides a mis-applied supervisory_guidance source_class in classifyAuthority,
so those standards classify and rank as technical_standard (control_standard
role). The corpus tags many standards as guidance (weight 70); the name wins.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
11 human-reasoned Beziehungskanten in cra.json gemerged (dedupliziert gegen die
Pipeline-Kanten), getaggt review_status=proposed / source=human_reasoned_preview /
confidence=high. Nur die kleine Sprache depends_on / supports / produces_evidence_for;
gerichtet. Cross-Family SBOM→Vuln-Kanten erlauben dem Advisor Ursachen-/Wirkungsketten.
Damit ist der CRA-v1-Baustein vollständig: Obligations · legal_basis · guidance_basis ·
out_of_scope · relationships · pending citation anchors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1 complete. GT #3 recall 84% -> 100% (25/25 matched), no regression:
- HP2207 backflow / potable-water contamination (EN 1717) + measure M2209
(Rueckflussverhinderer / Systemtrenner) — the only genuinely new hazard.
- HP2208 cut on sharp edges/screens (new sharp_edge tag from scharfe-Kante/Sieb).
- HP2209 unexpected restart during maintenance (dedicated dom_warewashing pattern;
avoids flooding the log via the broad moving_part tag).
- Spray-arm contact now covered by the enclosure-re-scoped contact patterns.
Kistenhub 97.1% and Bremse pinned mappings unchanged; 0/28 hazards without a
measure. Completes the commercial-dishwasher (white-goods Phase 1) coverage.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Phase 1 of the commercial white-goods expansion (EN ISO 10472 family). Extend
GT #3 with 8 completeness hazards a Fachmann expects but that were neither in
the GT nor previously questioned: dry-run boiler overheating, residual/stored
electrical energy, sharp-edge cut, tipping, interlock-failure, unexpected
restart, backflow (EN 1717), microbial/legionella. Enrich the UC-M narrative
with the real features so existing library patterns can fire.
Result: 4/8 auto-covered by existing patterns (dry-run, residual voltage,
tipping, interlock-failure) — recall 84% (21/25). Remaining gaps documented:
spray-arm contact (4.3), sharp-edge cut (4.6), backflow (2.3), restart (6.4).
Gate the re-surfaced CNC leak ("spanende Bearbeitung", high_temperature-only)
via dom_cnc. Kistenhub 97.1% and Bremse pinned mappings unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Schreibt das Zielmodell fest: Legal Obligation = gemeinsame Sprache zwischen
Legal Knowledge Graph (Chat) und Compliance Execution Graph (Engine).
- Registry-Schema v1 (id/tier/legal_basis/guidance_basis/facets/citation_anchor_ids/
relationships/decision_method)
- Zitierfähigkeit hängt an der OBLIGATION, nicht an Controls (Regulierungsänderung =
Anchor tauschen, Controls unverändert)
- legal_basis (Primärrecht) vs guidance_basis (NIST/OWASP/...) + source_role
(LEGAL_BASIS/GUIDANCE/EVIDENCE/IMPLEMENTATION/OUT_OF_SCOPE)
- HARTE Regel: LEGAL_MINIMUM nur mit Primärrechts-Anker
- Beziehungsgraph: requires/implements/supports/produces_evidence_for/depends_on/derived_from
- Citation-Anchor-Pipeline Document→Obligation (KEIN Re-Ingest zum Control-Neubau)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Class E1. A multi-category pattern (e.g. "Motorueberlast" [electrical, thermal],
"Lagerschaden" [mechanical, thermal]) created one hazard per category, so the
same scenario+zone appeared twice in the CE hazard log under different labels.
InitializeProject now breaks after the primary (first eligible) category — one
hazard per pattern.
This aligns production with the GT benchmark, which already scores one hazard per
matched pattern. Cyber-skip, per-category cap and cross-pattern measure-merge
still use continue (unchanged). Handlers + iace suites green; Kistenhub/Bremse
unchanged.
Note (E2, not fixed): some scenarios exist as TWO separate patterns (e.g.
"Sicherheitssoftware manipuliert" in hazard_patterns_final_c.go and _final_d.go)
— library redundancy that E1's per-pattern break cannot merge. Left for a
separate, GT-guarded library-dedup audit.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Class D (generic keyword hygiene, GT-guarded). Two over-broad keyword->component
mappings produced ghost components:
- "kuehl"/"cool" -> Kuehlaggregat (C095) matched product variants
("Cool-Ausfuehrung") and outputs ("kuehle Glaeser"). Narrowed to cooling-UNIT
terms (kuehlaggregat, kuehlanlage, kuehler, kaeltemaschine, chiller, rueckkuehl).
- "filter" -> Absauganlage/Oelnebelabscheider (C124) matched any filter
(Laugen-/Wasser-/Oelfilter). Keep "filteranlage" only.
No pattern or GT test depends on these mappings (Kistenhub/Bremse use hand-crafted
inputs). UC-M now parses 6 plausible components (was 8 incl. the two ghosts).
Warewashing GT recall 82.4% and Kistenhub/Bremse pins unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Class C (phase-aware, generic EN ISO 14120). A contact/entanglement hazard from
a moving part is removed during NORMAL operation when the part is behind an
interlocked guard; it remains only when the guard is open (maintenance/cleaning).
- New HazardPattern.GuardableByEnclosure flag; set on HP096 (friction at
rotating surfaces) and HP101 (entanglement of hair/clothing).
- Narrative emits interlocked_enclosure for an interlocked door/hood.
- pattern_enclosure.go: suppressedByEnclosure (drop in normal-op-only contexts)
+ guardedLifecycles (re-scope to maintenance/cleaning).
- GT #3 gains the maintenance-phase entanglement/friction rows.
Generic + regression-safe: machines that do not emit interlocked_enclosure are
unaffected. GT #3 recall 80% -> 82.4%, one false positive removed (Aufwickeln).
Kistenhub 97.1% and all 26 Bremse pinned mappings unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add ground_truth_warewashing.json + TestWarewashing_GTCoverage. The test runs
the UC-M narrative through the SAME chain as production (ParseNarrative ->
engine -> relevance + cyber filter), so keyword/gating fixes are measured on
the real hazard set, and false positives show up as "extra".
Class A (generic keyword hygiene): spuelarm/spuelfeld no longer map to library
component C004 ("Drehtisch" / rotary table) — that mislabelled the spray arm.
Keep the rotating_part tag. Removes the bogus "Drehtisch" hazard.
GT #3 baseline -> after Class A: recall 80% (unchanged), one false positive
(Drehtisch) removed. Kistenhub 97.1% and Bremse pinned mappings unchanged.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>