SOUP Ingestion
RTMify Live ingests software of unknown provenance from dedicated SOUP JSON uploads, single-purpose SOUP workbooks, inbox file-drop, and an optional read-only SOUP Sync source. The resulting graph anchors each product to a software DesignBOM, its BOMItem component rows, and any explicit requirement or test references declared on those SOUP rows.
SOUP is not just an SBOM file
CycloneDX and SPDX are excellent automated software BOM formats, but they usually do not carry anomaly evaluation, safety class, or manual trace notes. Live treats SOUP as a software inventory with richer audit fields. Use the SOUP template when you need those software-specific columns and use automated SBOMs when your CI pipeline already emits them.
What Live supports now
| Source | Path | Notes |
|---|---|---|
| SOUP JSON payload | POST /api/v1/soup | Dedicated software inventory API with per-row errors, warnings, and one product anchor per submission. |
| SOUP workbook (.xlsx) | POST /api/v1/soup/xlsx or inbox drop | Workbook must contain a SOUP Components tab. API binds product by form field; inbox uses the SOUP__{full_product_identifier}.xlsx filename convention. |
| Secondary SOUP Sync | Dashboard Settings → SOUP Sync | Optional read-only secondary source. Supports Google Sheets, Excel Online, or a local XLSX file anchored to one product in config. |
| Automated SBOM | POST /api/v1/bom | CycloneDX and SPDX still ingest as software DesignBOMs, but they do not carry the richer SOUP-only fields. |
Product prerequisite
Every SOUP register is anchored to exactly one Product by full_product_identifier. That product must already exist in the primary RTM workbook.
SOUP Sync is stricter than grouped Design BOM ingest
The dedicated SOUP Sync source stores one product anchor in config. Save and validate fail if that product does not exist. SOUP does not create Product rows and does not infer the product per row from the workbook itself.
Workbook shape and column reference
The downloadable SOUP workbook is single-purpose. Live expects the exact SOUP Components tab and the columns below.
| Column | Required | Notes |
|---|---|---|
| component_name | Yes | Mapped to BOMItem.part. Blank rows are skipped with SOUP_MISSING_REQUIRED_FIELD. |
| version | Yes | Mapped to BOMItem.revision. "unknown" is allowed and surfaces as SOUP_VERSION_UNKNOWN. |
| supplier | No | Stored on the BOMItem. |
| category | No | Stored on the BOMItem. |
| license | No | Stored on the BOMItem. |
| purl | No | Stored on the BOMItem. |
| safety_class | No | Free-text SOUP field stored on the BOMItem. |
| known_anomalies | No | Free-text SOUP field stored on the BOMItem. |
| anomaly_evaluation | No | Free-text SOUP field stored on the BOMItem. |
| requirement_ids | No | Comma-, semicolon-, or pipe-separated Requirement IDs. |
| test_ids | No | Comma-, semicolon-, or pipe-separated Test or TestGroup IDs. |
| Notes | Ignored for ingest | Accepted in the workbook and ignored by Live. |
Template-first path
The published workbook already uses the supported column names. If your team is not generating CycloneDX or SPDX automatically, start with the template and keep it as the canonical software inventory for that product.
Requirement and test trace fields
SOUP rows can declare direct trace links, just like hardware Design BOM rows.
Requirement IDs
Live stores declared requirement_ids on each SOUP component and creates REFERENCES_REQUIREMENT edges for exact Requirement matches.
Test IDs
Live resolves exact IDs to Test first, then TestGroup, and creates REFERENCES_TEST edges for resolved matches.
Unresolved refs stay visible
If a declared ID does not resolve, the SOUP row still ingests. The raw IDs remain on the BOMItem and the component surfaces unresolved-ref statuses instead of failing the entire submission.
Ingest paths
Inbox drop
Drop a single-purpose SOUP workbook into the Live inbox. Successful ingests move to processed/; failures move to rejected/.
cp SOUP__ASM-1000-REV-C.xlsx ~/.rtmify/inbox/
Inbox SOUP workbooks use the SOUP__{full_product_identifier}.xlsx filename convention so Live can anchor the register to one product.
HTTP API
Use POST /api/v1/soup for dedicated SOUP JSON and POST /api/v1/soup/xlsx for the SOUP workbook path.
curl -X POST http://127.0.0.1:8000/api/v1/soup/xlsx \ -H "Authorization: Bearer <token>" \ -F "full_product_identifier=ASM-1000-REV-C" \ -F "file=@RTMify_SOUP_Template.xlsx"
The dedicated SOUP routes return rows received, rows ingested, row-level errors, and warnings instead of a single opaque result.
SOUP Sync
The dashboard settings expose an optional read-only secondary source named SOUP Sync. That source is separate from the primary RTM workbook and is anchored to one Product in config.
- —
GET /api/soup-sync - —
POST /api/soup-sync/validate - —
POST /api/soup-sync - —
DELETE /api/soup-sync
This source is read-only. Live ingests it but never writes status back into the workbook.
Replacement semantics
Same product + BOM name replaces the prior software inventory
SOUP replacement is keyed by (full_product_identifier, bom_type, bom_name). If a SOUP register and a CycloneDX/SPDX ingest target the same software key, last writer wins. If you want both inventories to coexist, give them distinct bom_name values.
Graph shape
Product (full_identifier = "ASM-1000-REV-C")
└─[HAS_DESIGN_BOM]→ DesignBOM (bom_name = "SOUP Components", bom_type = "software", bom_class = "design")
├─[CONTAINS qty=1]→ BOMItem (part = "FreeRTOS", revision = "10.5.1")
│ ├─ known_anomalies = "None known"
│ ├─ anomaly_evaluation = "No anomalies to evaluate"
│ ├─ safety_class = "C"
│ ├─[REFERENCES_REQUIREMENT]→ Requirement (REQ-001)
│ └─[REFERENCES_TEST]→ Test or TestGroup (TG-001)
└─[CONTAINS qty=1]→ BOMItem (part = "lwIP", revision = "unknown") SOUP components live on the same product graph as requirements, tests, risks, code evidence, and hardware Design BOMs, so software inventory questions stay on the same graph rather than in a separate spreadsheet silo.
How to query it
The key MCP affordances include:
list_software_bomsfor product-scoped software inventory across both manual SOUP and automated CycloneDX/SPDX ingestsget_soup_components,soup_by_safety_class,soup_by_license, plus unifiedbom_gapsandbom_impact_analysis- the
software-boms://,soup-components://<full_product_identifier>/<bom_name>, andsoup-component://...resources - prompts such as
soup_audit_prepandsoup_coverage
Dashboard report availability
The Reports group in the dashboard includes a product-scoped SOUP Register report in PDF, Markdown, and DOCX. The Software / SOUP workspace also exposes components, gaps, licenses, and safety-class views from the same graph.
SOUP vs automated SBOM
CycloneDX / SPDX
Best when your CI or build pipeline already emits a software BOM. Live ingests those formats through the generic BOM API and stores them as software DesignBOM nodes.
SOUP workbook or JSON
Best when you need richer, manual software evidence: known anomalies, anomaly evaluation, safety class, and explicit trace links. This is the better audit surface when those fields matter.
Known limits
- —SOUP Sync is a second concrete source, not a generalized multi-workbook attachment system.
- —The workbook is single-purpose. Live expects a
SOUP Componentstab, not a mixed Design BOM + SOUP workbook. - —Free-text SOUP fields are not vocabulary-validated. Live distinguishes blank vs nonblank and detects
unknownversion values, but it does not enforce controlled terminology for anomaly text or safety class. - —If SOUP and CycloneDX/SPDX target the same software key, last writer wins. Live does not merge them field-by-field.
Error and warning reference
| Code | Meaning |
|---|---|
| SOUP_PRODUCT_NOT_FOUND | The target Product does not exist for the current full_product_identifier. |
| SOUP_NO_PRODUCT_IDENTIFIER | Inbox workbook filename did not include the expected SOUP__{full_product_identifier}.xlsx anchor. |
| NO_SOUP_TAB | Workbook/XLSX ingest did not find the required SOUP Components tab. |
| invalid_json | The JSON payload shape was invalid for the dedicated SOUP API. |
| invalid_xlsx | The uploaded workbook could not be parsed as a valid XLSX file. |
| SOUP_MISSING_REQUIRED_FIELD | A row was skipped because component_name or version was blank. |
| SOUP_VERSION_UNKNOWN | The component version was explicitly set to unknown. |
| SOUP_NO_ANOMALY_EVALUATION | known_anomalies was nonblank while anomaly_evaluation was blank. |
| SOUP_NO_ANOMALIES_DOCUMENTED | Both known_anomalies and anomaly_evaluation were blank. |
| SOUP_NO_REQUIREMENT_LINKAGE | No requirement_ids were declared on the component row. |
| SOUP_NO_TEST_LINKAGE | No test_ids were declared on the component row. |
| SOUP_UNRESOLVED_REQUIREMENT_REF | One or more declared requirement IDs did not resolve. |
| SOUP_UNRESOLVED_TEST_REF | One or more declared test or test-group IDs did not resolve. |