ff100c1cb8
Adds a jurisdiction-cross-reference layer to the norms library. Each entry
maps an ISO/IEC/EN norm to its identifier in DIN (DE), ANSI/NFPA/UL/OSHA (US),
GB (CN), and JIS (JP), with explicit Relation (identical/equivalent/partial/
superseded_by/supersedes) and Confidence (verified/high/medium/low) fields.
Batch 1 covers IDs 1-100 in load order:
- 1a (50): A-norms + B1-norms + early B2-norms (ergonomics, vibration, noise)
- 1b (50): remaining B2 (ATEX, EMC, cybersec) + first C-norms (presses,
robots, conveyors, plastics, woodworking)
These are the foundational, internationally harmonized standards with the
strongest verified mappings (ISO 12100 ~> GB 15706 ~> JIS B 9700, EN 60204-1
~> NFPA 79 ~> GB 5226.1 ~> JIS B 9960-1, etc.).
API:
- GET /iace/norms-library?include_crossref=true → inline crossref
- GET /iace/norms-library/:id/crossref → single norm lookup
- GET /iace/norms-library/crossref → bulk dump
Strategic context: enables dual-use CE/US/CN/JP tech files without
re-authoring, and addresses the "Norm Translation Matrix" gap that the
US-export strategy memory entry calls out. 6 batches remaining (~571 norms)
to reach full library coverage.
Tests: 6 new tests; all pass via `go test -vet=off ./internal/iace/`.
(vet=off needed only to bypass an unrelated pre-existing typo in
document_export_sources.go.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
69 lines
3.2 KiB
Go
69 lines
3.2 KiB
Go
package iace
|
|
|
|
// Norm cross-reference matrix: maps a core ISO/IEC/EN standard to the
|
|
// jurisdiction-specific identifiers used in DIN (DE), ANSI / NFPA / UL (US),
|
|
// GB (China), and JIS (Japan). This is an identifier-only mapping — no
|
|
// copyrighted norm text is included. The matrix is used to render a
|
|
// "this requirement also satisfies X in market Y" hint in tech files,
|
|
// enabling dual-use compliance documents for CE + US/CN/JP export.
|
|
//
|
|
// IMPORTANT: each NormMapping carries an explicit Confidence and Relation.
|
|
// Do NOT treat "partial" or "medium" entries as 1:1 substitutes. They
|
|
// indicate scope overlap that must be verified by a competent person for
|
|
// the concrete machine before relying on the foreign standard.
|
|
|
|
// NormMapping is one entry in the cross-reference table.
|
|
type NormMapping struct {
|
|
Region string `json:"region"` // "EU-DIN", "US-ANSI", "US-NFPA", "US-UL", "US-OSHA", "CN-GB", "JP-JIS", "INTL-ISO"
|
|
Identifier string `json:"identifier"` // e.g. "DIN EN ISO 12100:2011"
|
|
Relation string `json:"relation"` // "identical", "equivalent", "partial", "supersedes", "superseded_by"
|
|
Confidence string `json:"confidence"` // "verified", "high", "medium", "low"
|
|
Notes string `json:"notes,omitempty"` // Optional scope clarification (e.g. "only chapters 4-6")
|
|
SourceURL string `json:"source_url,omitempty"` // Optional pointer to a public catalog entry
|
|
}
|
|
|
|
// NormCrossRef is the cross-reference entry for one NormReference.ID.
|
|
type NormCrossRef struct {
|
|
NormID string `json:"norm_id"` // Matches NormReference.ID (e.g. "ISO-12100")
|
|
Mappings []NormMapping `json:"mappings"` // International equivalents
|
|
Notes string `json:"notes,omitempty"` // General notes about the cross-walk
|
|
BatchID string `json:"batch_id"` // Tracking which batch added this entry
|
|
}
|
|
|
|
// crossRefRegistry is the in-memory registry, populated by init() in each batch file.
|
|
var crossRefRegistry = map[string]NormCrossRef{}
|
|
|
|
// registerCrossRefs is called by each batch file's init() to append entries.
|
|
func registerCrossRefs(entries []NormCrossRef) {
|
|
for _, e := range entries {
|
|
crossRefRegistry[e.NormID] = e
|
|
}
|
|
}
|
|
|
|
// GetNormCrossRef returns the cross-reference entry for a given NormReference.ID,
|
|
// or a zero value with NormID set if no mapping exists yet.
|
|
func GetNormCrossRef(normID string) NormCrossRef {
|
|
if entry, ok := crossRefRegistry[normID]; ok {
|
|
return entry
|
|
}
|
|
return NormCrossRef{NormID: normID, Mappings: []NormMapping{}}
|
|
}
|
|
|
|
// ListNormCrossRefs returns every entry in the registry. Used by the
|
|
// /norms-library/crossref bulk endpoint and for tech-file batch rendering.
|
|
func ListNormCrossRefs() []NormCrossRef {
|
|
out := make([]NormCrossRef, 0, len(crossRefRegistry))
|
|
for _, v := range crossRefRegistry {
|
|
out = append(out, v)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// CrossRefCoverage returns counters that let the UI render a progress bar
|
|
// ("X of Y norms have a cross-reference"). The "total" comes from the
|
|
// caller (norms library size) since the cross-ref package does not depend
|
|
// on the norms library to avoid a cyclic import.
|
|
func CrossRefCoverage(totalNorms int) (covered, total int) {
|
|
return len(crossRefRegistry), totalNorms
|
|
}
|