From 448819104ac0a3cc140f439e10d3e857503bac13 Mon Sep 17 00:00:00 2001 From: Scott Scoble Date: Wed, 29 Apr 2026 15:05:26 -0700 Subject: [PATCH] =?UTF-8?q?Merge=20v0.2-DP=20into=20SPEC.md=20=E2=80=94=20?= =?UTF-8?q?unified=20v0.2=20spec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Integrated §3.6 Dark Provenance primitives (provenance, review, derives, satisfies, author, source) - Added §3.6.5 Provenance-Aware Event Semantics - Added §3.6.6 SpeckBOM (bom block) - Added §3.6.7 Import Version Pinning - Expanded §4.4 Provenance Graph with PROV-O node/edge types - Added §4.5 Compilation Manifest with dual CycloneDX v1.6 + SPDX 3.0.1 output - Updated EBNF grammar with all new primitives - Updated examples 5.3 and 5.5 with provenance/bom/import-pinning - Added Appendix B reference tables (B.1-B.4) - Updated tooling section with CLI flags and speckl-compile status - Preserved v0.2-DP reference file (not deleted) --- speckdl/SPEC.md | 400 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 391 insertions(+), 9 deletions(-) diff --git a/speckdl/SPEC.md b/speckdl/SPEC.md index d26718a..440b5f5 100644 --- a/speckdl/SPEC.md +++ b/speckdl/SPEC.md @@ -1,4 +1,4 @@ -# SpeckDL Language Specification v0.1 +# SpeckDL Language Specification v0.2 > The specification-first language for auditable software. > Part of the [Speckl](https://os.scoble.me/forgejo/sscoble/speckl) project. MIT License. @@ -31,7 +31,7 @@ speck { } ``` -Members are drawn from: `input`, `output`, `constraint`, `verify`, `interface`, `import`, and `event`. +Members are drawn from: `input`, `output`, `constraint`, `verify`, `interface`, `import`, `event`, and the Dark Provenance primitives: `provenance`, `review`, `derives`, `satisfies`, `author`, `source`, and the SpeckBOM primitive: `bom`. ### 2.2 EBNF Grammar @@ -42,6 +42,9 @@ speck_def = "speck" IDENT "{" { member } "}" member = input_def | output_def | constraint_def | verify_def | interface_def | event_def + | provenance_def | review_def | derives_def + | satisfies_def | author_def | source_def + | bom_def input_def = "input" ":" type_expr output_def = "output" ":" type_expr @@ -70,7 +73,33 @@ method_sig = IDENT "(" [ { IDENT ":" type_expr "," } ] ")" ":" type_expr event_def = "event" IDENT "{" { IDENT ":" type_expr [","] } "}" -import_stmt = "import" STRING ["as" IDENT] +provenance_def = "provenance" "{" { provenance_clause } "}" +provenance_clause = "regulation" ":" STRING + | "design_decision" ":" STRING + | "parent_spec" ":" IDENT + | "external_doc" ":" STRING [ "at" STRING ] + +review_def = "review" ":" review_kind +review_kind = "manual" | "auto" | "hybrid" + +derives_def = "derives" "from" IDENT [ "via" STRING ] + +satisfies_def = "satisfies" IDENT [ "clause" STRING ] + +author_def = "author" ":" STRING [ "<" STRING ">" ] + +source_def = "source" ":" source_kind [ "ref" STRING ] +source_kind = "conversation" | "meeting" | "document" | "regulation" + | "architecture_review" | "threat_model" | "compliance_audit" + +bom_def = "bom" "{" { bom_clause } "}" +bom_clause = "compiler" ":" STRING ["version" STRING] + | "solver" ":" STRING ["version" STRING] + | "runtime" ":" STRING ["version" STRING] + | "license" ":" STRING + | "hash" ":" STRING + +import_stmt = "import" STRING ["as" IDENT] ["version" STRING] ["hash" STRING] literal = NAT_LIT | INT_LIT | REAL_LIT | BOOL_LIT | STRING_LIT IDENT = letter { letter | digit | "_" } @@ -172,6 +201,128 @@ event RetryAttempted { Events are emitted during execution and recorded as nodes in the provenance graph. They do not affect the verification pipeline — they exist for observability. +### 3.6 Dark Provenance Semantics + +Dark Provenance primitives make intent sources and verification boundaries explicit in the specification language. They compile to JSON-LD provenance graph nodes and edges. These primitives are optional — bare Specks (without any provenance annotations) still compile — but they are recommended for safety-critical and regulated systems. + +#### 3.6.1 `provenance` Block Semantics + +The `provenance` block declares where a Speck's intent originates: + +| Clause | Meaning | JSON-LD Output | +|--------|---------|----------------| +| `regulation: "DO-178C"` | Compliance requirement | `prov:wasInformedBy` → Regulation node | +| `design_decision: "ADR-0017"` | Architecture decision record | `prov:wasDerivedFrom` → Decision node | +| `parent_spec: ParentSpeck` | Decomposition from another Speck | `prov:wasDerivedFrom` → Parent Speck node | +| `external_doc: "RFC 8446" at "https://..."` | External reference | `prov:wasInformedBy` → Document node | + +Multiple clauses may appear; each creates a separate provenance edge. + +#### 3.6.2 `review` Directive Semantics + +The `review` directive marks verification boundaries: + +- `review: manual` — Requires human sign-off before deployment. Compiler emits a `ManualReviewRequired` node in the provenance graph. +- `review: auto` — Fully automated verification. No human gate required. +- `review: hybrid` — Automated verification with spot-check sampling. Compiler emits sampling parameters. + +Review status is checked at compile time; `manual` Specks without sign-off block the pipeline. + +#### 3.6.3 `derives` / `satisfies` Semantics + +These primitives create explicit edges in the provenance graph: + +**`derives from SpecName via "rationale"`** +- Creates a `prov:wasDerivedFrom` edge from the current Speck to `SpecName` +- Optional `via` clause records the derivation rationale as `rdfs:comment` +- Used for: refactoring, decomposition, specialization + +**`satisfies RequirementId clause "3.2.1"`** +- Creates a `speckl:satisfies` edge to a requirement node +- Optional `clause` specifies the exact subsection +- Used for: tracing to regulatory requirements, user stories, specs + +#### 3.6.4 `author` / `source` Metadata Semantics + +These primitives capture "who" and "why": + +**`author: "Name" <"email@example.com">`** +- Binds the Speck to a `prov:Agent` node +- Compiles to `prov:wasAttributedTo` edge +- Optional email used for agent deduplication in the provenance graph + +**`source: kind ref "identifier"`** +- Records what drove the creation of this Speck +- `kind`: `conversation`, `meeting`, `document`, `regulation`, `architecture_review`, `threat_model`, `compliance_audit` +- `ref`: Optional identifier (meeting ID, document URL, ticket number) +- Compiles to `prov:wasInformedBy` → Source node with `prov:type` + +#### 3.6.5 Provenance-Aware Event Semantics + +Events declared with the standard `event` syntax gain provenance edges automatically: + +``` +event DoseCalculated { volume: Real, safe: Bool } +``` + +When this event fires at runtime, the provenance graph records: +- The event instance node (`prov:Activity`) +- An edge to the declaring Speck (`prov:wasInformedBy`) +- An edge to the Speck's `provenance` sources (transitive intent tracing) +- An edge to the runtime WASM module that emitted it (`prov:wasGeneratedBy`) + +This creates complete audit trails: Event → Speck → Intent Source → Regulatory Requirement. + +#### 3.6.6 SpeckBOM: Bill of Materials + +A **SpeckBOM** is the specification analog of a Software Bill of Materials (SBOM). Where an SBOM lists software components, versions, and licenses, a SpeckBOM lists the complete dependency and artifact tree for a Speck system. + +The `bom` block declares **toolchain dependencies** — what compiler, solver, and runtime a Speck requires. Combined with `import`, `derives`, and `satisfies`, it provides a full bill of materials: + +| SpeckBOM concern | SpeckDL primitive | What it captures | +|---|---|---| +| **Spec dependencies** | `import` | Which other Specks this one depends on (with content hashes) | +| **Toolchain** | `bom { compiler, solver, runtime }` | What tools produced the verified artifacts | +| **Intent lineage** | `derives from`, `satisfies` | Which specs/requirements this one traces to | +| **Authorship** | `author`, `source` | Who wrote it and what drove it | +| **Artifact hashes** | `bom { hash }` | Content hash of the Speck source itself | +| **License** | `bom { license }` | Under what terms this spec can be used | +| **Compilation output** | *(auto-generated)* | Z3, DST, WASM hashes and solver results (see §4.5) | + +**Why this matters.** In regulated environments (DO-178C, IEC 62304), an auditor needs to know not just "what code runs" but "what was the complete chain from requirement to deployed artifact." The SpeckBOM answers this declaratively — it's machine-readable, hash-pinned, and queriable. + +**Example:** + +``` +speck DrugDosageCalculator { + bom { + compiler: "speckl-compile" version "0.2.0" + solver: "z3" version "4.12.5" + runtime: "wasm-runtime" version "1.0.0" + license: "MIT" + hash: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + + import "retry-handler.speck" as retry + ... +} +``` + +#### 3.6.7 Import Version Pinning + +The `import` statement supports optional `version` and `hash` fields for reproducible builds: + +``` +import "retry-handler.speck" as retry + version "1.2.0" + hash "sha256:abcdef1234567890..." +``` + +- **`version`**: Semantic version of the imported Speck. The compiler verifies the imported file declares this version in its `bom` block. +- **`hash`**: Content hash of the imported file. The compiler computes the hash at parse time and fails if it doesn't match. + +Version pinning is optional for local development but required for Specks with `review: manual` or `review: hybrid` — the compiler enforces that all imports are hash-pinned before allowing manual review sign-off. + --- ## 4. Compilation Pipeline @@ -227,12 +378,128 @@ Speck "RetryHandler" └── provenance: { author: "scott", timestamp: "2026-04-28T09:00:00Z", - tool: "speckl-compiler v0.1", + tool: "speckl-compiler v0.2", z3_version: "4.12.5" } ``` -The provenance graph is serialized as JSON-LD and stored alongside the compiled artifacts. +The provenance graph is serialized as **JSON-LD using the W3C PROV-O vocabulary** and stored alongside the compiled artifacts. + +#### 4.4.1 PROV-O Namespace and Context + +The JSON-LD output uses the standard PROV-O namespace: + +```json +{ + "@context": { + "prov": "http://www.w3.org/ns/prov#", + "speckl": "https://speckl.scoble.me/ns/v0.2#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#" + } +} +``` + +#### 4.4.2 Provenance Node Types + +| Node Type | PROV-O Class | Description | +|-----------|---------------|-------------| +| Speck | `prov:Entity` | The specification itself | +| Z3 Assertion Set | `prov:Entity` | Compiled SMT-LIB2 | +| DST | `prov:Entity` | Decision structure tree | +| WASM Module | `prov:Entity` | Compiled binary | +| Z3 Solver | `prov:Agent` | The verification tool | +| Compiler | `prov:Agent` | The compilation tool | +| Compilation Act | `prov:Activity` | A compilation stage | +| Author | `prov:Agent` | Person (from `author` primitive) | +| Source | `prov:Activity` | Intent origin (from `source` primitive) | +| Regulation | `prov:Entity` | Compliance requirement | +| Design Decision | `prov:Entity` | Architecture decision record | + +#### 4.4.3 Provenance Edge Types + +| Edge | PROV-O Property | From → To | +|------|-----------------|-----------| +| Compiled to | `prov:wasGeneratedBy` | Artifact → Compilation Act | +| Used tool | `prov:used` | Compilation Act → Tool (Agent) | +| Derived from | `prov:wasDerivedFrom` | Speck → Parent Speck | +| Informed by | `prov:wasInformedBy` | Speck → Regulation / Source | +| Attributed to | `prov:wasAttributedTo` | Speck → Author | +| Satisfies | `speckl:satisfies` | Speck → Requirement | + +### 4.5 Compilation Manifest: Dual BOM Output + +The compiler produces a **compilation manifest** containing both provenance and bill-of-materials data. The manifest supports two output formats: + +- **CycloneDX v1.6** (JSON) — OWASP standard, ECMA-424 +- **SPDX 3.0.1** (JSON-LD) — ISO 5962:2023 + +The `--bom-format` flag controls output: `cdx`, `spdx`, or `both` (default: `both`). + +#### 4.5.1 Output Files + +For a Speck named `Name`, the compiler produces: + +| File | Format | Content | +|------|--------|---------| +| `Name.prov.jsonld` | JSON-LD / PROV-O | Intent provenance graph | +| `Name.specbom.cdx.json` | CycloneDX v1.6 JSON | Composition BOM (CycloneDX) | +| `Name.specbom.spdx.json` | SPDX 3.0.1 JSON-LD | Composition BOM (SPDX) | + +#### 4.5.2 CycloneDX v1.6 Mapping + +| SpeckDL Primitive | CycloneDX Location | Field | +|---|---|---| +| `bom { compiler }`, `bom { solver }`, `bom { runtime }` | `metadata.tools[]` | Standard tool entries | +| `bom { license }` | `metadata.component.licenses[]` | SPDX expression | +| `bom { hash }` | `metadata.component.hashes[]` | SHA-256 | +| `import "X" as Y hash H version V` | `components[]` | Component entry with purl, hashes, properties | +| `derives from X` | `component.properties[]` | `speckl:derivesFrom` | +| `satisfies X clause Y` | `component.properties[]` | `speckl:satisfies` | +| `author: Name ` | `annotations[]` | `speckl:provenanceType: author` | +| `source: kind ref X` | `annotations[]` | `speckl:provenanceType: source` | +| `provenance { regulation: X }` | `annotations[]` | `speckl:provenanceType: regulation` | +| `review: manual` | `annotations[]` | `speckl:reviewType: manual` | +| `review: auto` | No additional annotation | N/A | +| `review: hybrid` | `annotations[]` | `speckl:reviewType: hybrid` | +| Compilation artifacts (Z3, DST, WASM) | `components[]` (nested) | Type + hash | +| Verification results (SAT/UNSAT) | `metadata.component.properties[]` | `speckl:verificationResult` | +| Reproducibility status | `metadata.component.properties[]` | `speckl:reproducible` | + +#### 4.5.3 SPDX 3.0.1 Mapping + +| SpeckDL Primitive | SPDX Location | Field | +|---|---|---| +| `bom { compiler }`, `bom { solver }`, `bom { runtime }` | `spdx:Build` (in `builtBy`) | Tool name + version | +| `bom { license }` | `spdx:licenseConcluded` | SPDX expression (native) | +| `bom { hash }` | `spdx:hash` | SHA-256 | +| `import "X" hash H version V` | `spdx:Software` element | Package with version + hash | +| `derives from X` | `spdx:Relationship` (derivesFrom) | Standard SPDX relationship | +| `satisfies X clause Y` | `speckl:satisfies` property | Extension on element | +| `author: Name ` | `spdx:Relationship` (wasAttributedTo) | Agent element | +| `source: kind ref X` | `spdx:Relationship` (wasInformedBy) | Activity element | +| `provenance { regulation: X }` | `spdx:Relationship` + element | Regulation node | +| `review: manual` | `spdx:Annotation` (REVIEW) | Standard annotation | +| `review: auto` | No additional annotation | N/A | +| `review: hybrid` | `spdx:Annotation` (REVIEW) | `speckl:reviewType: hybrid` | +| Compilation artifacts (Z3, DST, WASM) | `spdx:SoftwareArtifact` elements | With hashes | +| Verification results (SAT/UNSAT) | `speckl:verificationResult` | Extension property | +| Reproducibility status | `speckl:reproducible` | Extension property | + +#### 4.5.4 Two-Layer Architecture + +Speckl produces **three complementary outputs**: + +| Layer | Format | Concern | Standard | +|---|---|---|---| +| **Intent provenance** | JSON-LD / PROV-O | Who, why, what drove this specification | W3C PROV-O | +| **Composition BOM (CycloneDX)** | CycloneDX v1.6 JSON | What this spec depends on, builds with, produces | OWASP CycloneDX (ECMA-424) | +| **Composition BOM (SPDX)** | SPDX 3.0.1 JSON-LD | Same composition data, ISO-normative format | ISO 5962:2023 | + +These layers are orthogonal: +- The provenance graph answers *"Why does this constraint exist?"* (regulatory, design decision, conversation) +- The SpeckBOM answers *"What is this spec made of, and can I reproduce it?"* (dependencies, toolchain, artifacts) + +Together they form the complete audit trail: **intent** (PROV-O) + **composition** (CycloneDX or SPDX) = **full accountability**. --- @@ -270,6 +537,23 @@ speck ETLTransform { ``` speck DrugDosageCalculator { + provenance { + regulation: "FDA 21 CFR 820.30" + regulation: "IEC 62304 Class C" + design_decision: "ADR-0017: Separate dose calculation from administration" + } + review: manual + author: "Scott Scoble" <"scott@scoble.me"> + source: regulation ref "FDA 21 CFR 820.30" + + bom { + compiler: "speckl-compile" version "0.2.0" + solver: "z3" version "4.12.5" + runtime: "wasm-runtime" version "1.0.0" + license: "MIT" + hash: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + } + input: { patientWeight: Real, drugConcentration: Real, @@ -317,12 +601,32 @@ speck SpeckValidator { } ``` -### 5.5 Composed: Multi-Speck System +### 5.5 Composed: Multi-Speck System with Import Pinning ``` speck PaymentService { import "rate-limiter.speck" as limiter + version "1.0.0" + hash "sha256:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" import "retry-handler.speck" as retry + version "2.1.0" + hash "sha256:fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321" + + provenance { + regulation: "PCI DSS 4.0 Requirement 6" + design_decision: "ADR-0022: Payment isolation with rate limiting" + } + review: hybrid + author: "Scott Scoble" <"scott@scoble.me"> + source: compliance_audit ref "PCI-DSS-AUDIT-2026-Q2" + + bom { + compiler: "speckl-compile" version "0.2.0" + solver: "z3" version "4.12.5" + runtime: "wasm-runtime" version "1.0.0" + license: "MIT" + hash: "sha256:9876543210abcdef9876543210abcdef9876543210abcdef9876543210abcdef" + } input: { payment: Payment, apiKey: String } output: Result @@ -354,13 +658,23 @@ The reference compiler (`speckl-compile`) is a Node.js/TypeScript application th 4. Invokes Z3 and interprets results. 5. Compiles verified models to DSTs. 6. Compiles DSTs to WASM. -7. Emits provenance graph metadata (JSON-LD) at each stage. +7. Emits provenance graph metadata (JSON-LD / PROV-O) at each stage. +8. Emits SpeckBOM (CycloneDX v1.6 and/or SPDX 3.0.1) per §4.5. + +### CLI + +``` +speckl-compile --output-dir --bom-format +``` + +- `--output-dir`: Directory for output artifacts (default: `./out`) +- `--bom-format`: BOM output format — `cdx` (CycloneDX), `spdx` (SPDX), or `both` (default: `both`) ### Planned Tooling | Tool | Purpose | Status | |------|---------|--------| -| `speckl-compile` | Reference compiler | Spec only | +| `speckl-compile` | Reference compiler | In progress | | `speckl-lsp` | Language Server Protocol (IDE support) | Planned | | `speckl-playground` | Browser-based spec editor + live verification | Planned | | `speckl-fmt` | Formatter | Planned | @@ -386,4 +700,72 @@ The reference compiler (`speckl-compile`) is a Node.js/TypeScript application th --- -*This is a v0.1 specification. The language is evolving. Feedback and contributions are welcome via the [Speckl repository](https://os.scoble.me/forgejo/sscoble/speckl).* \ No newline at end of file +## Appendix B: Provenance and BOM Reference Mappings + +### B.1 PROV-O JSON-LD Reference + +| SpeckDL Primitive | PROV-O Class/Property | JSON-LD Key | +|---|---|---| +| `provenance { regulation: X }` | `prov:wasInformedBy` → `prov:Entity` (type: Regulation) | `wasInformedBy` | +| `provenance { design_decision: X }` | `prov:wasDerivedFrom` → `prov:Entity` (type: DesignDecision) | `wasDerivedFrom` | +| `provenance { parent_spec: X }` | `prov:wasDerivedFrom` → `prov:Entity` (type: Speck) | `wasDerivedFrom` | +| `provenance { external_doc: X }` | `prov:wasInformedBy` → `prov:Entity` (type: Document) | `wasInformedBy` | +| `author: Name ` | `prov:wasAttributedTo` → `prov:Agent` | `wasAttributedTo` | +| `source: kind ref X` | `prov:wasInformedBy` → `prov:Activity` (type: kind) | `wasInformedBy` | +| `derives from X via Y` | `prov:wasDerivedFrom` + `rdfs:comment` | `wasDerivedFrom`, `comment` | +| `satisfies X clause Y` | `speckl:satisfies` → `prov:Entity` | `speckl:satisfies` | +| `review: manual` | `prov:Activity` (type: ManualReview) | `speckl:reviewType` | +| `review: auto` | *(no node)* | N/A | +| `review: hybrid` | `prov:Activity` (type: HybridReview) | `speckl:reviewType` | + +### B.2 SpeckBOM — CycloneDX v1.6 + +| SpeckDL Primitive | CycloneDX Location | Field | +|---|---|---| +| `bom { compiler }`, `bom { solver }`, `bom { runtime }` | `metadata.tools[]` | Standard tool entries | +| `bom { license }` | `metadata.component.licenses[]` | SPDX expression | +| `bom { hash }` | `metadata.component.hashes[]` | SHA-256 | +| `import "X" as Y hash H version V` | `components[]` | Component entry with purl, hashes, properties | +| `derives from X` | `component.properties[]` | `speckl:derivesFrom` | +| `satisfies X clause Y` | `component.properties[]` | `speckl:satisfies` | +| `author: Name ` | `annotations[]` | `speckl:provenanceType: author` | +| `source: kind ref X` | `annotations[]` | `speckl:provenanceType: source` | +| `provenance { regulation: X }` | `annotations[]` | `speckl:provenanceType: regulation` | +| `review: manual` | `annotations[]` | `speckl:reviewType: manual` | +| `review: auto` | No additional annotation | N/A | +| `review: hybrid` | `annotations[]` | `speckl:reviewType: hybrid` | +| Compilation artifacts (Z3, DST, WASM) | `components[]` (nested) | Type + hash | +| Verification results (SAT/UNSAT) | `metadata.component.properties[]` | `speckl:verificationResult` | +| Reproducibility status | `metadata.component.properties[]` | `speckl:reproducible` | + +### B.3 SpeckBOM — SPDX 3.0.1 + +| SpeckDL Primitive | SPDX Location | Field | +|---|---|---| +| `bom { compiler }`, `bom { solver }`, `bom { runtime }` | `spdx:Build` (in `builtBy`) | Tool name + version | +| `bom { license }` | `spdx:licenseConcluded` | SPDX expression (native) | +| `bom { hash }` | `spdx:hash` | SHA-256 | +| `import "X" hash H version V` | `spdx:Software` element | Package with version + hash | +| `derives from X` | `spdx:Relationship` (derivesFrom) | Standard SPDX relationship | +| `satisfies X clause Y` | `speckl:satisfies` property | Extension on element | +| `author: Name ` | `spdx:Relationship` (wasAttributedTo) | Agent element | +| `source: kind ref X` | `spdx:Relationship` (wasInformedBy) | Activity element | +| `provenance { regulation: X }` | `spdx:Relationship` + element | Regulation node | +| `review: manual` | `spdx:Annotation` (REVIEW) | Standard annotation | +| `review: auto` | No additional annotation | N/A | +| `review: hybrid` | `spdx:Annotation` (REVIEW) | `speckl:reviewType: hybrid` | +| Compilation artifacts (Z3, DST, WASM) | `spdx:SoftwareArtifact` elements | With hashes | +| Verification results (SAT/UNSAT) | `speckl:verificationResult` | Extension property | +| Reproducibility status | `speckl:reproducible` | Extension property | + +### B.4 Two-Layer Architecture + +| Layer | Format | Concern | Standard | +|---|---|---|---| +| **Intent provenance** | JSON-LD / PROV-O | Who, why, what drove this specification | W3C PROV-O | +| **Composition BOM (CycloneDX)** | CycloneDX v1.6 JSON | Dependencies, toolchain, artifacts | OWASP CycloneDX (ECMA-424) | +| **Composition BOM (SPDX)** | SPDX 3.0.1 JSON-LD | Same data, ISO-normative format | ISO 5962:2023 | + +--- + +*This is a v0.2 specification. Dark Provenance and SpeckBOM primitives are optional but recommended for safety-critical and regulated systems. Feedback and contributions are welcome via the [Speckl repository](https://os.scoble.me/forgejo/sscoble/speckl).* \ No newline at end of file