docs: add agent bootstrap and contract read router
This commit is contained in:
117
rules/patterns/bom-decomposition/README.md
Normal file
117
rules/patterns/bom-decomposition/README.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# BOM Decomposition Pattern Notes
|
||||
|
||||
This file keeps examples and reference types. The normative rules live in `contract.md`.
|
||||
|
||||
## Canonical JSON Shape
|
||||
|
||||
```json
|
||||
{
|
||||
"sort_order": 10,
|
||||
"item_code": "SYS-821GE-TNHR",
|
||||
"quantity": 3,
|
||||
"description": "Vendor bundle",
|
||||
"unit_price": 12000.00,
|
||||
"total_price": 36000.00,
|
||||
"component_mappings": [
|
||||
{ "component_ref": "CHASSIS_X13_8GPU", "quantity_per_item": 1 },
|
||||
{ "component_ref": "PS_3000W_Titanium", "quantity_per_item": 2 },
|
||||
{ "component_ref": "RAILKIT_X13", "quantity_per_item": 1 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Project-specific aliases are acceptable if the semantics stay identical:
|
||||
|
||||
- `item_code` -> `vendor_partnumber`
|
||||
- `component_ref` -> `lot_name`
|
||||
- `component_mappings` -> `lot_mappings`
|
||||
- `quantity_per_item` -> `quantity_per_pn`
|
||||
|
||||
## Persistence Example
|
||||
|
||||
```json
|
||||
{
|
||||
"vendor_spec": [
|
||||
{
|
||||
"sort_order": 10,
|
||||
"vendor_partnumber": "ABC-123",
|
||||
"quantity": 2,
|
||||
"description": "Bundle",
|
||||
"lot_mappings": [
|
||||
{ "lot_name": "LOT_CPU", "quantity_per_pn": 1 },
|
||||
{ "lot_name": "LOT_RAIL", "quantity_per_pn": 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Wrong Shape
|
||||
|
||||
```json
|
||||
{
|
||||
"vendor_spec": [
|
||||
{
|
||||
"sort_order": 10,
|
||||
"vendor_partnumber": "ABC-123",
|
||||
"primary_lot": "LOT_CPU",
|
||||
"secondary_lots": ["LOT_RAIL"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Reference Go Types
|
||||
|
||||
```go
|
||||
type BOMItem struct {
|
||||
SortOrder int `json:"sort_order"`
|
||||
ItemCode string `json:"item_code"`
|
||||
Quantity int `json:"quantity"`
|
||||
Description string `json:"description,omitempty"`
|
||||
UnitPrice *float64 `json:"unit_price,omitempty"`
|
||||
TotalPrice *float64 `json:"total_price,omitempty"`
|
||||
ComponentMappings []ComponentMapping `json:"component_mappings,omitempty"`
|
||||
}
|
||||
|
||||
type ComponentMapping struct {
|
||||
ComponentRef string `json:"component_ref"`
|
||||
QuantityPerItem int `json:"quantity_per_item"`
|
||||
}
|
||||
```
|
||||
|
||||
## Normalization Sketch
|
||||
|
||||
```go
|
||||
func NormalizeComponentMappings(in []ComponentMapping) ([]ComponentMapping, error) {
|
||||
if len(in) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
merged := map[string]int{}
|
||||
order := make([]string, 0, len(in))
|
||||
|
||||
for _, m := range in {
|
||||
ref := strings.TrimSpace(m.ComponentRef)
|
||||
if ref == "" {
|
||||
continue
|
||||
}
|
||||
if m.QuantityPerItem <= 0 {
|
||||
return nil, fmt.Errorf("component %q has invalid quantity_per_item %d", ref, m.QuantityPerItem)
|
||||
}
|
||||
if _, exists := merged[ref]; !exists {
|
||||
order = append(order, ref)
|
||||
}
|
||||
merged[ref] += m.QuantityPerItem
|
||||
}
|
||||
|
||||
out := make([]ComponentMapping, 0, len(order))
|
||||
for _, ref := range order {
|
||||
out = append(out, ComponentMapping{
|
||||
ComponentRef: ref,
|
||||
QuantityPerItem: merged[ref],
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user