Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/generate_perspectives_registry.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Generate Perspectives Registry

on:
push:
branches:
- 'master'
- 'main'
- '2.0-dev'
paths:
- '.github/workflows/generate_perspectives_registry.yml' # self
- 'tools/src/main/js/perspectives-registry/**'
- 'schema/perspectives-defs.schema.json'
- 'perspectives/**'
workflow_dispatch: # Allows manual trigger

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token
permissions: {}

jobs:
generate-registry:
name: Generate Registry
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write # Required to push the update branch
pull-requests: write # Required to open the pull request
env:
REGISTRY_FILE: schema/perspectives-defs.json
BASE_BRANCH: ${{ github.ref_name }}
UPDATE_BRANCH: update-perspectives-registry/${{ github.ref_name }}
steps:
- name: Checkout repository
# see https://github.com/actions/checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Node.js
# see https://github.com/actions/setup-node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24.x'
- name: Generate registry
# registers catalog document versions that are not registered yet;
# fails if a catalog document changed without a version bump
run: |
set -eux
node tools/src/main/js/perspectives-registry/generate-perspectives-registry.js
- name: Create Pull Request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -eu

if git diff --quiet -- "$REGISTRY_FILE"
then
echo "No changes to the perspectives registry"
exit 0
fi

git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"

git checkout -b "$UPDATE_BRANCH"
git add "$REGISTRY_FILE"
git commit -m "chore: update perspectives registry"

git push -u "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "$UPDATE_BRANCH" --force

gh pr create \
--title "chore: update perspectives registry" \
--body "This PR updates \`${REGISTRY_FILE}\` with the catalog document versions registered by \`tools/src/main/js/perspectives-registry/generate-perspectives-registry.js\` for \`${BASE_BRANCH}\`." \
--base "$BASE_BRANCH" \
--head "$UPDATE_BRANCH" || echo "Pull request already exists"
238 changes: 238 additions & 0 deletions perspectives/model-card-perspective.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
{
"$schema": "https://cyclonedx.org/schema/2.0/cyclonedx-2.0.schema.json",
"specFormat": "CycloneDX",
"specVersion": "2.0",
"version": 1,
"metadata": {
"timestamp": "2026-09-04T12:00:00Z"
},
"perspectives": [
{
"bom-ref": "perspective-model-card",
Comment thread
taleodor marked this conversation as resolved.
"name": "Model Card",
"description": "Defines the data elements of a machine learning model card, following the industry-standard model card structure: model details, intended use, training data and procedure, quantitative analysis, technical limitations, and ethical, fairness, and environmental considerations. The mappings project that structure onto the CycloneDX 2.0 decomposition of the former first-class modelCard entity: intrinsic technical characteristics live in modelProperties, which may only appear on components of type machine-learning-model; training datasets are components of type data; intended use cases are use case definitions referenced from the model; and ethical and fairness considerations are entries in the document's risk model. This perspective assumes the AI/ML model properties proposed in CycloneDX/specification#990. Model data is located by descendant search so the perspective applies whether models are declared at the document root, in inventories, or in definitions; related data such as training datasets and use cases is reached through traversal steps from the model's references.",
"domains": [
"machine-learning",
"artificial-intelligence",
"transparency",
"ethics"
],
"mappings": [
{
"expression": "$..[?(@.type=='machine-learning-model')]['name','version','description']",
"nativeName": "Model Details",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure what "native" means.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is part of the existing perspective model and means the domain-specific term the target audience uses for that data, so a perspective can translate CycloneDX nomenclature into a familiar vocabulary. If you want this adjusted for this case, lmk.

"nativeDescription": "The identifying facts of the model: its name, version, and a description of what it is and does.",
"relevance": "required",
"weight": 1.0,
"rationale": "A model card is meaningless without stating which model, and which revision of it, the card describes."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].identifiers",
"nativeName": "Model Identifiers",
"nativeDescription": "Identifiers under which the model is published or catalogued, such as a Package-URL for a model hub entry, grouped by the party asserting them.",
"relevance": "recommended",
"weight": 0.7,
"rationale": "Name and version alone are ambiguous across hubs and forks; asserted identifiers let a card be matched to the published artefact."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].parties[?(@.roles[?(@.role=='supplier')])]",
"nativeName": "Developed By",
"nativeDescription": "The organization or individuals responsible for developing and supplying the model.",
"relevance": "required",
"weight": 0.9,
"rationale": "Accountability for a model's behaviour requires knowing who produced it. Expressed through the party model with the supplier role."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].licenses",
"nativeName": "License",
"nativeDescription": "The license under which the model, and by extension its weights, may be used.",
"relevance": "required",
"weight": 0.8,
"rationale": "Model cards conventionally state usage terms; license determines whether a given use is permitted at all."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.tasks",
"nativeName": "Supported Tasks",
"nativeDescription": "The machine learning tasks the model is designed to perform.",
"relevance": "required",
"weight": 0.9,
"rationale": "Tasks anchor the card: they determine the applicable inputs, outputs, and evaluation metrics."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.learningTypes",
"nativeName": "Learning Paradigms",
"nativeDescription": "The learning paradigms applied when training the model, such as supervised or reinforcement learning.",
"relevance": "recommended",
"weight": 0.5,
"rationale": "Helps readers judge what kinds of data and feedback shaped the model's behaviour."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.architecture",
"nativeName": "Model Architecture",
"nativeDescription": "The architecture family and structural characteristics of the model.",
"relevance": "recommended",
"weight": 0.7,
"rationale": "Architecture contextualizes capability and performance claims and supports reproducibility."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties['inputs','outputs']",
"nativeName": "Input and Output Parameters",
"nativeDescription": "The modalities, formats, and constraints of the data the model consumes and produces.",
"relevance": "recommended",
"weight": 0.6,
"rationale": "Input and output specifications define the model's operational envelope and integration contract."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties['parameterCount','quantization']",
"nativeName": "Model Size and Quantization",
"nativeDescription": "The parameter count of the model and any quantization applied to its weights.",
"relevance": "optional",
"weight": 0.3,
"rationale": "Size and quantization inform deployment cost and can affect accuracy relative to the unquantized model."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.training",
"nativeName": "Training Data and Procedure",
"nativeDescription": "How the model was trained: the training formula and the datasets used.",
"relevance": "recommended",
"weight": 0.8,
"rationale": "Training data provenance is central to assessing bias, capability boundaries, and data protection obligations."
},
{
"expression": "$.formulation[*]",
"via": [
{
"refs": "$..[?(@.type=='machine-learning-model')].modelProperties.training.formula"
}
],
"nativeName": "Training Procedure",
"nativeDescription": "The formula describing how the model was trained: its workflows and tasks, such as pre-training, fine-tuning, and alignment stages, and the data each consumed.",
"relevance": "recommended",
"weight": 0.7,
"rationale": "Training stages and the datasets each consumed show how the data was used, which a description of the datasets alone cannot convey."
},
{
"expression": "$..[?(@.type=='data')]['name','version','identifiers','licenses']",
"via": [
{
"refs": "$..[?(@.type=='machine-learning-model')].modelProperties.training.datasets[*]"
}
],
"nativeName": "Dataset Identity and Licensing",
"nativeDescription": "Which dataset was used, at which version, under which identifiers and licence terms.",
"relevance": "required",
"weight": 0.8,
"rationale": "A dataset a model card reader cannot identify or check licence terms for cannot be assessed; identity and licensing are the minimum the EU AI Act's data documentation expects."
},
{
"expression": "$..[?(@.type=='data')].data[*]['type','description','contents']",
"via": [
{
"refs": "$..[?(@.type=='machine-learning-model')].modelProperties.training.datasets[*]"
}
],
"nativeName": "Dataset Description and Contents",
"nativeDescription": "What the dataset is: its general theme, a description of its size and role, and its contents or where they are held.",
"relevance": "recommended",
"weight": 0.6,
"rationale": "Describing composition and contents lets a reader judge coverage and representativeness of the training data."
},
{
"expression": "$..[?(@.type=='data')].data[*]['classification','sensitiveData']",
"via": [
{
"refs": "$..[?(@.type=='machine-learning-model')].modelProperties.training.datasets[*]"
}
],
"nativeName": "Dataset Classification and Sensitive Data",
"nativeDescription": "The protection level the dataset requires and any sensitive or personal data it contains.",
"relevance": "recommended",
"weight": 0.7,
"rationale": "Sensitive-data declarations drive data protection obligations and are a primary concern of AI regulation."
},
{
"expression": "$..[?(@.type=='data')].data[*].governance",
"via": [
{
"refs": "$..[?(@.type=='machine-learning-model')].modelProperties.training.datasets[*]"
}
],
"nativeName": "Dataset Governance",
"nativeDescription": "The parties accountable for the dataset through its lifecycle: owners, stewards, and custodians.",
"relevance": "recommended",
"weight": 0.5,
"rationale": "Governance names who is accountable for the data, which regulators and downstream users need to trace provenance and responsibility."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.evaluation",
"nativeName": "Quantitative Analysis",
"nativeDescription": "Evaluation results: performance metrics, per-slice measurements, confidence intervals, and supporting graphics.",
"relevance": "recommended",
"weight": 0.8,
"rationale": "Metrics, including slice-level results, substantiate capability claims and surface performance disparities between groups."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.useCases",
"nativeName": "Intended Use",
"nativeDescription": "References to the use cases the model is intended for.",
"relevance": "required",
"weight": 0.9,
"rationale": "Intended use separates in-scope application from misuse; it is the card section most consulted by adopters and assessors."
},
{
"expression": "$.definitions.useCases[*]",
"via": [
{
"refs": "$..[?(@.type=='machine-learning-model')].modelProperties.useCases[*]"
}
],
"nativeName": "Use Case Definitions",
"nativeDescription": "The use case definitions that the model's intended-use references resolve to.",
"relevance": "recommended",
"weight": 0.6,
"rationale": "The model links to use cases by reference; the definitions carry the actual descriptions a card reader needs."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].parties[?(@.roles[?(@.role=='end-user')])]",
"nativeName": "Intended Users",
"nativeDescription": "The audiences the model is intended to be used by.",
"relevance": "recommended",
"weight": 0.5,
"rationale": "Stating who the model is for frames the expertise assumed of its operators. Expressed through the party model with the end-user role."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.limitations",
"nativeName": "Technical Limitations",
"nativeDescription": "Known technical limitations of the model, including constraints on accuracy, reasoning, scalability, and appropriate use, and relevant performance tradeoffs.",
"relevance": "required",
"weight": 0.9,
"rationale": "Limitations are the card's primary safeguard against use outside the model's competence."
},
{
"expression": "$.risks.risks[?(@.domains[?(@.type=='ethical')])]",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the feeling Steve may be reworking "risk" as the object includes perhaps too much... The goal is to isolate risks, harms and benefits more effectively so perhaps they can be disassociated from most of the risk object (and optionally tied/bound to risks) and include them in "considerations" (for model design).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably shouldn't be in scope for this PR

"nativeName": "Ethical Considerations",
"nativeDescription": "Risks in the ethical domain associated with the model, including affected parties, benefits, harms, and mitigations.",
"relevance": "required",
"weight": 0.9,
"rationale": "Ethical considerations are expressed as entries in the document's risk model rather than as card-local prose, gaining structured likelihood, impact, and response data. Risks reference the components they affect, not the other way round, so this mapping is evaluated over the whole document rather than through a traversal step; tooling may narrow it to risks whose `affects` include the scoped model."
},
{
"expression": "$.risks.risks[?(@.inherentRisk.impact.categories[?(@=='fairness' || @=='bias')])]",
"nativeName": "Fairness Assessments",
"nativeDescription": "Risks whose impact is categorized as fairness or bias, describing groups at risk and observed disparities.",
"relevance": "recommended",
"weight": 0.6,
"rationale": "Fairness assessments identify demographic or group-level performance disparities; slice-level evaluation metrics provide their quantitative backing. Risks reference the components they affect, not the other way round, so this mapping is evaluated over the whole document rather than through a traversal step; tooling may narrow it to risks whose `affects` include the scoped model."
},
{
"expression": "$..[?(@.type=='machine-learning-model')].modelProperties.environmental",
"nativeName": "Environmental Considerations",
"nativeDescription": "Energy consumption and carbon cost of model activities such as training and inference.",
"relevance": "recommended",
"weight": 0.5,
"rationale": "Environmental impact is an established model card section and increasingly a reporting obligation."
}
]
}
]
}
9 changes: 9 additions & 0 deletions schema/2.0/model/cyclonedx-definition-2.0.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
},
"businessObjectives": {
"$ref": "cyclonedx-business-objective-2.0.schema.json#/$defs/businessObjectives"
},
"perspectives": {
"type": "array",
"uniqueItems": true,
"title": "Perspectives",
"description": "Reusable perspective declarations. Each entry is a complete inline perspective, identified by its bom-ref, that may be applied from the document's perspectives by reference, optionally scoped to different parts of the document at each application. A definition declares no scopes of its own.",
"items": {
"$ref": "cyclonedx-perspective-2.0.schema.json#/$defs/perspectiveDefinition"
}
}
}
}
Expand Down
Loading