cybedtools 0.4.1
First-time-user defect fixes found against the published v0.4.0 / PyPI 0.1.0, fixed identically in R and Python.
-
CSEC2017 held from the 2026.09.2 data release (owner correction, on this branch before the fixes below):
docs/data-release.ymlmovescsec2017fromshippedtoheld, pending steward confirmation. -
Slug alias resolution.
cybed_license()andframework_similarity()now accept either the versioned framework slug (e.g."nice-v2") or the short release-file slug (e.g."nice"), matchingcybed_fetch()’s existing behavior. The alias map is derived once, inR/slug-alias.R(cybedtools/_slug_alias.pyin Python), from the shippedframework_summary/framework_licensestables, reusing the short-slug rulescripts/030-export-release.R’srelease_license_row()applies.cybed_fetch()’s result now carries bothframework_slug(canonical, versioned) andrelease_slug(short) columns explicitly, rather than silently substituting one for the other. -
framework_similarity()errors on an unknownfrom/toslug with classcybedtools_framework_not_found(a specific exception in Python), listing the graph’s known slugs, instead of silently returning an empty result. -
Python
cybed_fetch()/load_graph()accept a bare string forframeworksas one slug, not an iterable of its characters. -
versionaccepts adata-v-prefixed value (e.g."data-v2026.09.2", matching a GitHub release tag) in bothcybed_fetch()implementations; the leadingdata-vis stripped. -
README and quick-start docs lead with the user path: install, then
cybed_fetch()/load_graph(), then query examples. The ingestion pipeline (scripts/000-build.R) moves to a separate “Rebuilding the graph from source (maintainers)” section, consistent acrossREADME.qmd,concordance/start/install.qmd, and thegetting-startedvignette. The Zenodo data-release DOI (10.5281/zenodo.22884320) is now named alongside the data release. -
Concordance framework pages’ footer
LICENSE/asset links are root-relative, fixing a 404 from any page under a subdirectory (e.g.frameworks/). -
CITATION.cffandDESCRIPTION’sDescriptionno longer describe cybedtools as an R-only pipeline or hand-list frameworks; both now point toframework_summary()for the current list and note the shared R/Python API.
cybedtools 0.4.0
New framework
-
CyBOK v1.1.0, the Cyber Security Body of Knowledge (July 2021) published by the National Cyber Security Centre, joins as a fourteenth framework with the slug
cybok, the framework idcybok-v1.1.0and the prefixcybok:, under the Open Government Licence v3.0 with CyBOK’s prescribed attribution. CyBOK publishes PDFs only, so the ingest reads the Introduction, the 21 Knowledge Trees and the A-to-Z Indicative Material index, each staged with its URL, its own version and its SHA256. 21 Knowledge Areas (cybok:KnowledgeArea,cybed:OrganizingUnit, nevercybed:Role) carry their category, one of 5, ascybok:categoryand their own document version asschema:version. The 119 Topics of the trees arecybok:Topicelements, and the 477 Indicative Material nodes drawn under them arecybed:Subpointchildren typedcybok:IndicativeMaterial. Which Topic a node hangs from is read from the tree drawing, not from node position. Every carried string is looked up in an independent extraction of its PDF, 622 of 622 found. The A-to-Z index is a cross-check only: 366 of its 482 Knowledge Area rows resolve to a Topic and term in the trees, and every other row is reported intables/a-to-z-resolution.csv, not corrected. The staged SFIA and ECSF crosswalks resolve to KA acronyms in full and are not wired into the graph yet. The sub-point parser is off. Held from data release 2026.09.1, which was cut before it joined. The other thirteen frameworks’ N-Triples are byte-identical. -
framework_summaryandframework_licensesgain acybok-v1.1.0row. Every value in the thirteen existing rows is unchanged. -
scripts/015-verify-ingestion.Ralso fails hard when a CyBOK carried string is missing from its check text. -
SCyWF 1.5, the Saudi Cybersecurity Workforce Framework (SCyWF – 1.5: 2026) issued by the National Cybersecurity Authority (NCA), joins as a thirteenth framework with the slug
scywf, the framework idscywf-1.5and the prefixscywf:, by NCA’s written permission of 2026-09-20. 40 job roles (scywf:JobRole,cybed:Role) link bycybed:hasElementto the 1,419 Task, Knowledge and Skill statements printed on their cards (4,794 links, every one resolving). Codes, titles and statement text are carried verbatim, and the ingest proves it: every carried string is looked up in an independent extraction of the PDF, 3,290 of 3,290 found. 24 competency areas, 12 specialty areas and 5 categories are organizing units that are not roles. The edges from role to specialty area and from specialty area to category are cybedtools-derived and sit on their own predicates,scywf:inSpecialtyAreaandscywf:inCategory. SCyWF reuses NICE-shaped codes: 296 are shared with NICE v2.2.0 and the text differs under every one, so the two are never joined on a bare code. The sub-point parser is off. The Career Progression companion document is staged and not ingested yet. Held from data release 2026.09.1, which was cut before it joined. The other twelve frameworks’ N-Triples are byte-identical. -
framework_summaryandframework_licensesgain ascywf-1.5row. The rebuild also bringsdigcomp-3.0in line with its parser being disabled: itssubpoint_countgoes from 97 to 0 and its with-examples columns follow. That change was committed earlier without a rebuild, and the summary build’s regression guard now names it as an acknowledged change. Every other existing value is unchanged. -
scripts/015-verify-ingestion.Rfails hard when a framework carried on a verbatim condition (SCyWF) has any carried string missing from its check text or any role-card code without a statement. -
CSTA PK-12 CS (2026), the 2026 CSTA PK-12 Computer Science Standards (DOI 10.1145/3820482), joins as a twelfth framework with the slug
csta-2026and the prefixcsta2026:. It sits alongside the 2017 edition rather than replacing it. The two share no identifier scheme, andcsta-2017comes out byte-identical. 331 standards, keyed by CSTA’s codes verbatim, are grouped into 53csta2026:StandardGroupunits: level x concept for the 196 foundational standards and tier x specialty area for the 135 specialty standards. Units are built from the pairs that occur, so X+CS, published at Specialty I only, has one unit. Every standard carriescsta2026:tier,csta2026:subconceptand, in the specialty tier,csta2026:specialtyArea, so the 27 Cybersecurity (CYB) standards can be selected directly. Boundary statements arecsta2026:boundaryStatementliterals on the standard. CSTA’s 652 implementation examples arecybed:Examplenodes reached throughcybed:hasExample, as the 2017 clarifications are. Practices, dispositions and progressions are not modelled yet. Licence CC BY-NC-SA 4.0, read from the document’s own licence page. The framework is held from data release 2026.09.1, which was cut before it joined. -
framework_summaryandframework_licensesgain acsta-2026row. Every value in the eleven existing rows is unchanged. - The release export’s licence lookup no longer treats
csta-2026as a version ofcsta. A slug that is a framework in its own right is excluded from another slug’s version-suffix match. -
scripts/015-verify-ingestion.Rchecks the SHA256 of every file a manifest lists undersource.files, not only a singleretrieval.file_sha256. - The sub-point parser is disabled for
csta-2026, the same treatment OTCCF gets: CSTA’s standards are published statements, and a parser-split fragment would be a unit the package invented rather than one CSTA printed. Its 45 previously-parsed Subpoints drop out; parent elements (331) and implementation examples (652) are unaffected.
Framework upgrade
-
DigComp 3.0 replaces DigComp 2.2 in place (owner decision, 2026-08-21). The versionless IRIs
digcomp:AREA-*anddigcomp:COMP-x.ysurvive unchanged, but the framework node is nowdigcomp-3.0and every element’s text changed (4 of 5 area names, 13 of 21 competence names revised; all descriptions rewritten). Source of record is the official JSON-LD data supplement (JRC144121), not a PDF scrape, hash-anchored and verified at ingest. The 7 official errata to the Learning Outcomes are applied (523 -> 522; seedata/raw/digcomp/v3.0/errata.csv). Structurally, elements move down from the 21 competences to the 362 Competence Statements, so competences become a second organizing-unit tier (digcomp:Competence) alongside the 5 areas (digcomp:CompetenceArea) – 26 organizing units total, both flat, neither acybed:Role(DigComp is a citizen self-assessment instrument). The 522 Learning Outcomes attach to their Competence ascybed:Exampleviacybed:hasExample, nevercybed:hasElement(no source-provided link to an individual statement). Proficiency levels (8-level descriptors with 4-level and CEFR-style 6-level crosswalks) and a 126-term glossary are staged but not yet emitted into the graph. DigComp 2.2’s raw source stays archived atdata/raw/digcomp/v2.2/. No other framework’s output changed.
Licensing
-
CCSSF is now full text, with attribution (owner decision, 2026-09-21). The Canadian Centre for Cyber Security gave cybedtools written permission for full-text publication with attribution, superseding the 2026-09-19 reading of its earlier reply as a reference-only instruction rather than a grant.
docs/framework-invariants.yml‘sccssfpolicy moves fromstructure_onlytofull_with_attribution;framework_licenses’ccssf-2022row now hasgranted = TRUEandlicense_short = "Government of Canada, with permission". Every remaining “Referenced as the Canadian Centre for Cyber Security asked” wording (creditText,license, ingestion comments,docs/ingestion-summary.md,docs/framework-data-sources.md,LICENSING.md,README) now reads “Copyright Government of Canada. Used with permission of the Canadian Centre for Cyber Security.” No other framework’s attribution changed. Data release 2026.09.1 is not revised; it was cut before this permission was received and still holds CCSSF for steward confirmation.
API (0.4.0, Python parity)
- Every
*_bindings()helper andframework_metadata()gain aframework_slugcolumn (a stable join key, e.g."nice-v2", derived from the framework IRI’s own local part). Existing columns and row order are unchanged. - New exported
unit_element_bindings(rdf), identical to the oldrole_element_bindings()output plusframework_slug.role_element_bindings()is now a deprecated alias that callsunit_element_bindings()and warns. It will be removed in a future minor version. - New exported
unit_relation_bindings(rdf): one row percybed:UnitRelationnode, columnsfrom_unit,relation,to_unit,framework_slug. - New exported
framework_similarity(rdf, from, to, n = 5): the one public entry point for cross-framework unit-text similarity, built on the existing internal tokenizer, Jaccard scorer, and ranking helpers (unchanged math). Compares eachfrom-framework organizing unit’s full document (its own name and text, plus every child element’s text) against everyto-framework unit, keeping the topnmatches with astrengthlabel. Reproduces the “full-document” pass used by the concordance NICE-vs-ECSF alignment script, generalized to any two frameworks. - New exported
cybed_fetch(frameworks = NULL, version = NULL)andload_graph(frameworks = NULL, version = NULL): download and SHA-256-verify per-framework release files intotools::R_user_dir("cybedtools", "cache"), never any other location, and parse them into an rdf graph. The release location is configurable via thecybedtools.release_urloption or theCYBEDTOOLS_RELEASE_URLenvironment variable, so tests (and air-gapped mirrors) can point at a localfile://release. The default base URL points at this repository’s GitHub release assets. - New
inst/conformance/directory: a hand-authored fixture graph (fixture.nt), a mock release directory forcybed_fetch()/load_graph()tests, and one golden CSV per public query function. This is the exact parity contract a Python port is built against; seeinst/conformance/README.mdfor the format (encoding, sort keys, rounding, NA handling).
cybedtools 0.3.1
CCSSF attribution no longer claims permission. The Canadian Centre for Cyber Security’s reply asked that its material be referenced when used; it did not grant permission. Every remaining “used with permission” wording for CCSSF (
creditText,license, ingestion comments,docs/ingestion-summary.md,docs/framework-invariants.yml, and the framework’s provenance manifest) now reads “Copyright Government of Canada. Referenced as the Canadian Centre for Cyber Security asked.” No other framework’s attribution changed, and the assembled graph is byte-identical for all ten other frameworks; only the two CCSSFcreditText/licensetriples differ.Organizing units and statements no longer share one identifier space. A node’s IRI was its framework prefix plus its framework-local id, which is safe only when a framework numbers its units and its statements separately. Two frameworks do not. DCWF draws work-role codes and task/KSA numbers from one numeric range, so 33 of its 74 work roles were fused with a statement node and two roles (801 and 632) were their own element. Cyber.org K-12 names a grade-band x sub-concept cell after its axes and names the standards inside it the same way, so 109 of its 116 cells were fused with their only standard and every one of those
cybed:hasElementlinks pointed at itself. Present since v0.1.0. No published count was affected: fusing a unit with a statement loses nothing, which is why it went unnoticed for three minor versions, and it is a modelling error all the same. Unit IRIs in those two frameworks now carry a discriminator declared asunit_iri_prefixindocs/framework-invariants.yml, so DCWF work role 462 isdcwf:role-462and a Cyber.org cell iscyberorg:cell-K-2.SEC.AUTH; each keeps its printed code as aschema:identifierliteral. Statement IRIs do not move, and neither do the other nine frameworks’ IRIs, which come out byte-identical. Anyone holding DCWF or Cyber.org K-12 unit IRIs taken from a locally built graph must rebuild. No graph file has ever been published, so nothing downstream of a release is affected. A new build stage,scripts/026-verify-graph.R, now fails the build on any IRI typed bothcybed:OrganizingUnitandcybed:RoleElementand on any self-referentialcybed:hasElementtriple, with no per-framework exemption;scripts/030-export-release.Rre-runs the same check before it writes. The same stage also enforces thegraph_invariantsblock ofdocs/framework-invariants.yml, which declared the assembled graph’s per-framework and combined counts but which nothing had ever read.
Licensing
- New dataset
framework_licensesand accessorcybed_license(): one row for the package’s own code and one per framework, with what each source’s own document says, the attribution wording a steward prescribed where there is one, the public-redistribution class, the terms URL, and the date the terms were last read. It is the single owner of licence facts. -
framework_summary$licenseis now derived fromframework_licenses$license_short, so the label and the detail cannot disagree. Nine labels change. SFIA read “SFIA Use Policy”; SFIA requires a licence for all use and its terms cover structure as well as text. NICE read as public domain alone; NIST also grants a worldwide royalty-free right that includes derivative works. ECSF read “ENISA re-use notice”; the report PDF is CC BY 4.0 and the ingested data files carry no notice. DigComp read “EU open re-use”; its imprint page states CC BY 4.0. CCSSF no longer says “used with permission”; the Centre asked that its material be referenced when used. Every other column offramework_summaryis unchanged for all eleven frameworks. -
docs/framework-invariants.ymlnow marks DigComp 2.2, ECSF, Cyber.org K-12 and CSTA asfull_with_attribution. They were unmarked, which read as unrestricted.
Documentation
- New article
ai-assistants: the rules an AI assistant needs to write cybedtools code that runs.AGENTS.mdandcontext7.jsongain theelement_text()androle_element_bindings()caveats. - The README links each framework to its steward’s page and notes that the documentation is indexed in Context7 and published as
llms.txt. - The invariants key
total_elements_strictis renamedtotal_elements_with_subpoints. It counted parents plus sub-points, which is not what “strict” means inframework_summary.
cybedtools 0.3.0
Eleven frameworks, up from eight. Two national frameworks join by written permission of their stewards, a third is referenced as its steward asked, and the vocabulary gains a way to say that one organizing unit relates to another.
New frameworks
- CyQUAL (Czech Republic, Masaryk University), open data version 1.2.0: 102 work roles, 1,168 tasks, 1,320 requirements, 59 competencies. Ingested from the English export, with the Czech export supported as a fallback. Attribution to CyQUAL and Masaryk University.
-
CCSSF, the Canadian Cyber Security Skills Framework (ITSM.00.039, 2022 edition), Canadian Centre for Cyber Security: 22 core work roles and 37 cyber adjacent roles, with tasks, competencies, and tools. Copyright Government of Canada. Referenced as the Canadian Centre for Cyber Security asked. The framework’s citations of 2017-era NICE work roles are recorded as
cybed:niceCrossReferenceliterals. -
OTCCF, the Operational Technology Cybersecurity Competency Framework version 1.1, Cyber Security Agency of Singapore: 15 job roles with key tasks, 30 technical skills with level statements, and the 310 role-to-skill requirements that join them. CSA’s permission covers the framework’s structure, for non-commercial, academic and research use. See
LICENSING.md. - Terms, attribution wording, and staging instructions for all three are in
docs/framework-data-sources.md. As before, the package ships ingestion code and no framework text. - Statement codes are unique only within a framework. CyQUAL reuses 2017 NICE task codes and shares the
T1xxxrange with current NICE for unrelated statements. Never join frameworks on a bare code. Graph identifiers are namespaced per framework and are safe.
Vocabulary (additive, nothing renamed)
-
cybed:relatedUnitandcybed:UnitRelation(withcybed:fromUnit,cybed:toUnit,cybed:relationLabel,cybed:proficiencyLevel): a relation between two organizing units, plain or qualified. Levels are stored as printed and are never numeric, since frameworks use scales that do not compare. New helpersbuild_related_unit_metadata()andbuild_unit_relation_node(), both experimental.assemble_framework_document()accepts optionalrelation_nodes. -
build_framework_node()gainsattribution(schema:creditText, the steward’s wording verbatim) andin_language(schema:inLanguage, for frameworks whose text is not English). -
cybed:niceCrossReference, a sibling ofcybed:ecfCrossReferenceandcybed:cybokCrossReference. -
cybed:jurisdictionnow also takes"CZ","CA", and"SG". - The three new frameworks’ subtypes are minted under
https://w3id.org/cybed/framework/<slug>#, not under the steward’s domain, so a package-coined type is never mistaken for an identifier the steward issued. - New exported helper
element_text()returns thecybed:elementTextstatement text keyed by element IRI, one row per literal the graph holds. Sub-points and examples carry text too; anti-joinsubpoint_framework_bindings()andexample_framework_bindings()for parent statements only.
framework_summary
- Now 11 rows and 16 columns. Every existing column keeps its definition, and values for the original eight frameworks are unchanged.
- New
role_count,elements_per_role_strict, andelements_per_role_with_examples. NICE, CyQUAL, and OTCCF each contribute more than one kind of organizing unit, so elements per organizing unit is not a per-role figure for them. The per-role columns are. They areNAfor frameworks that assert no roles. OTCCF’s per-role figure counts key tasks only, because its competency statements belong to its skill units. - New
unit_relation_count. - The build now stops, naming the framework, if the graph and the display table disagree about which frameworks exist. Before, a framework missing from the table was dropped without a message.
- Documentation now says exactly what
element_count_strictcounts (parent elements only) and notes thatdocs/framework-invariants.ymluses “strict” differently. -
Corrected 2026-08-14:
element_count_strictpreviously subtracted onlyexample_count, so any framework with nonzero Subpoints carried an inflated “strict” value that silently included non-parent content (NICE +4, SFIA +158, ECSF +16, CSTA +20, CSEC2017 +2). That is what produced the NICE 2,115-vs-NIST’s-2,111 discrepancy caught in the Concordance manuscript audit.
Framework data
- NICE upgraded to Framework Components v2.2.0 (NIST release 2026-04-28), replacing the v2.0.0-era data in place: 42 work roles (adds OG-WRL-017 Cybersecurity Supply Chain Risk Management), 962 tasks, 693 knowledge, 556 skills, 5,410 role-TKS associations. T1648 and K0908 were removed upstream. The skill S0768 ships in NIST’s JSON/CSV with zero role memberships but is absent from the companion XLSX (a contradiction internal to NIST’s release); it is retained per the orphan-retention policy, so the skills count is 556 rather than the XLSX’s 555.
- NICE competency areas (11) now enter the graph as
nice:CompetencyArea/cybed:OrganizingUnitnodes withcybed:hasElementlinks to their 412 member knowledge/skill statements. Previously the competency-areas table was staged but never assembled. - New
cybed:opmCodemulti-valued literal property on NICE work-role nodes carrying the v2.2.0 Federal-use OPM occupational-series codes (one role carries two codes; three roles carry none). Exposed through a newopm_codesparameter onbuild_role_node(). - NICE ingestion applies a declared erratum: the v2.2.0 source publishes a wrong description for the Investigation (IN) category (foreign-intelligence text, an upstream NIST regression). The correction is applied deterministically at ingest and recorded in a machine-readable errata table, with a hard stop if the upstream text changes.
- NICE licensing wording tightened from “public domain, safe to redistribute” to “US public domain (17 U.S.C. 105); foreign rights may be reserved; attribute NIST as source”.
Internal
- Now requires dplyr 1.1.0 or later. Building the vignettes requires knitr 1.35 or later.
-
parse_subpoints()input contract hardened:character(0)now returns the empty tibble (previously crashed at theis.na()guard) and length > 1 input signals a classed error (cybedtools_scalar_input) instead of a bare condition error. - New internal text-similarity layer (
R/similarity-helpers.R): canonicaltokenize(),jaccard(),similarity_stopwords()(both the k12 and workforce profiles),top_n_matches(), andsimilarity_strength(), promoted from the script-local copies triplicated acrossconcordance/_data-prep-*.R. The package versions harden the input contracts (character(0)-safe, classed errors on vector input), dropNAtokens injaccard(), break ranking ties deterministically by candidate id, and flag zero-similarity “best matches”. The concordance scripts still run their local copies; drift-tripwire tests pin those copies against each other and against the package profiles until the scripts are refactored. - Test additions from the 2026-08-20 coverage audit:
parse_subpointssemicolon fallback / last-introducer / connective filtering,build_role_element_nodeprovenance fields (the 2026-08-14 DCWFsourceCategoryregression),build_organizing_unit_nodeelement wiring and metadata-collision characterization, JSON-LD write/read round trip,expand_with_subpointsstructural edge cases,validate_jsonld_nodepositive paths, and script-helper tests for NICE relationship direction, ECSF slugging/flattening, and DCWF sheet identification. -
scripts/010-ingest-nice.R:extract_elements_of_type()now returns a schema-stable 5-column empty tibble on zero matches (previously a 0-column tibble frommap_dfr()over an empty list).
Documentation fixes
-
framework_summarydocumentation attributed the README headline density figure to the strict element count. The README uses the with-examples count; the strict count is the supplementary figure. - Regenerated
man/cybedtools-package.Rdto include the Concordance site URL in Useful links.
cybedtools 0.2.0
Breaking changes
This release introduces a structural redesign of the cybed: vocabulary to address two defects v0.1.1 documented but did not fix: cybed:Role was misapplied to non-workforce frameworks (SFIA enumerates skills, not roles; CSTA, Cyber.org K-12, CSEC2017, and DigComp 2.2 enumerate other organizing units), and cybed:Subpoint overstated what the source frameworks specify when it promoted Cyber.org K-12 and CSTA “Clarification statement:” pedagogical scaffolding to first-class sub-standards. Both fixes require breaking changes to the data model.
New abstract type: cybed:OrganizingUnit
cybed:OrganizingUnit (subClassOf skos:Concept) is the cross-framework abstract that every framework’s top-level enumerated unit asserts. Cross-framework SPARQL queries should target this type rather than cybed:Role. Adding a new framework in a future release introduces a new per-framework subtype but does not change existing cross-framework queries.
cybed:Role is now workforce-restricted
cybed:Role is retained as subClassOf cybed:OrganizingUnit but is asserted only on the three workforce frameworks where the unit is genuinely a work role or work profile: NICE work roles, DCWF work roles, and ENISA ECSF profiles. SFIA skills, Cyber.org K-12 grade-band concepts, CSTA level x concept cells, CSEC2017 Knowledge Areas, and DigComp competence areas no longer assert cybed:Role. Queries that filter on ?x a cybed:Role will return only workforce-framework parents under v0.2.0; for the cross-framework cut, switch to cybed:OrganizingUnit.
Migration snippet:
# v0.1.x cross-framework parent query (returned all 8 frameworks
# because all parents asserted cybed:Role):
SELECT ?p WHERE { ?p a cybed:Role }
# v0.2.0 equivalent (the same eight-framework cut, via the abstract):
SELECT ?p WHERE { ?p a cybed:OrganizingUnit }
# v0.1.x R helper (returned all 8 frameworks):
role_framework_bindings(rdf)
# v0.2.0 equivalent (cross-framework cut):
organizing_unit_framework_bindings(rdf)
# v0.2.0 workforce-only cut (returns NICE / DCWF / ECSF only):
role_framework_bindings(rdf)New atomic type: cybed:Example (with cybed:hasExample predicate)
cybed:Example (subClassOf cybed:RoleElement) is a new sibling of cybed:Subpoint for content lifted from “Clarification statement:” pedagogical scaffolding (Cyber.org K-12 and CSTA convention). Examples differ from Subpoints in three ways:
- Examples carry no framework-native subtype. A Cyber.org K-12 Example is typed
cybed:Exampleandcybed:RoleElementonly; it is not also typedcyberorg:Standard. Queries that filter on the per-framework subtype no longer pick up Examples by accident. - Examples are reachable only via the parent element’s
cybed:hasExamplepredicate. They are excluded from defaultcybed:hasElementtraversals, so role-level “all elements” queries remain restricted to framework-as-specified content. - Examples do not carry
cybed:elaboratesback-pointers. The parent owns the Example viacybed:hasExample; the Example does not carry the converse link.
Two source-data shapes route to cybed:Example. (1) Cyber.org K-12 stores Clarification statements inline in the standard text under a “Clarification statement:” header; the v0.1.1 parser extracted these as cybed:Subpoint, and v0.2.0 reroutes them to cybed:Example. (2) CSTA K-12 CS stores its clarifications in a separate clarification column rather than inline; v0.1.x did not extract this column at all, and v0.2.0 reads it directly to emit one cybed:Example per non-empty clarification (114 new graph nodes).
SFIA, NICE, ECSF, and CSEC2017 enumerations (from “such as”, “including”, and semicolon-list patterns rather than Clarification scaffolding) remain typed cybed:Subpoint.
Migration snippet:
# v0.1.x: a Cyber.org K-12 sub-point was typed as a sub-standard:
SELECT ?s WHERE { ?s a cyberorg:Standard } # picked up Clarification fragments
SELECT ?s WHERE { ?s a cybed:Subpoint } # picked up Clarification fragments
# v0.2.0: the same fragments are typed cybed:Example instead.
SELECT ?s WHERE { ?s a cybed:Example } # all Cyber.org + CSTA Clarifications
Per-framework subtype renames
Two cluster-type names were renamed because v0.1.x’s StandardCluster suffix did not match the framework’s own structural axes. Cyber.org K-12 and CSTA both organize their numbered standards by cells in multi-dimensional axes (grade band x sub-concept for Cyber.org K-12; level x concept for CSTA), but neither framework names the cell itself in published documentation. cybedtools therefore uses the descriptive StandardGroup label rather than coining a pedagogy term the source frameworks did not originate:
| Framework | v0.1.x type | v0.2.0 type |
|---|---|---|
| Cyber.org K-12 | cyberorg:StandardCluster |
cyberorg:StandardGroup |
| CSTA K-12 CS | csta:StandardCluster |
csta:StandardGroup |
SFIA’s sfia:Skill, CSEC2017’s csec:KnowledgeArea, and DigComp’s digcomp:CompetenceArea retain their existing names but no longer subclass cybed:Role; they now subclass cybed:OrganizingUnit directly. NICE / DCWF / ECSF parent subtypes are unchanged.
framework_summary column changes
The shipped framework_summary tibble has new column names that match v0.2.0 semantics. Two element-count columns are surfaced so analyses can choose the strict count (parents + Subpoints) or the inclusive count (parents + Subpoints + Examples).
| v0.1.x column | v0.2.0 column |
|---|---|
role_count |
organizing_unit_count |
element_count |
element_count_strict, element_count_with_examples, example_count
|
elements_per_role |
elements_per_organizing_unit_strict, elements_per_organizing_unit_with_examples
|
The README headline density figure now uses elements_per_organizing_unit_strict. The cross-framework-analysis vignette shows both the strict and with-examples columns and discusses the encoding heterogeneity that drives the difference.
New exported helpers
-
build_organizing_unit_node()— generic constructor for any framework’s parent unit. Passis_role = TRUEfor workforce frameworks.build_role_node()is retained as a thin wrapper. -
build_example_node()— constructor for pedagogical-scaffolding nodes parallel tobuild_subpoint_node(). -
organizing_unit_framework_bindings()— cross-framework parent-to- framework bindings. Returns all eight frameworks’ parents. -
example_framework_bindings()—cybed:Examplesubset ofelement_framework_bindings(). Returns only the Cyber.org K-12 and CSTA Clarification scaffolding.
Parser output schema
parse_subpoints() returns a third column, node_type, with values "Subpoint" (framework-as-specified enumeration) or "Example" (Clarification-statement scaffolding). The same parser handles both patterns; the routing happens via the node_type tag.
expand_with_subpoints() returns the result list with the index field renamed subpoint_index → subnode_index, and the index columns renamed subpoint_id → subnode_id plus the new node_type column.
extend_role_element_ids() now filters to node_type == "Subpoint" when back-filling a role’s cybed:hasElement collection. Examples are deliberately excluded from this collection so role-level “all elements” queries remain restricted to framework-as-specified content.
Resolved from v0.1.1’s “known limitations”
Both items the v0.1.1 NEWS flagged as known limitations carrying into v0.1.2 are addressed in this release: the cybed:Role abstraction is no longer applied to non-workforce frameworks, and the Cyber.org K-12 / CSTA Clarification fragments no longer carry cybed:Subpoint typing or framework-native subtypes. The version label moved from v0.1.2 to v0.2.0 because the changes are breaking and semver requires minor bumps for breaking changes in the 0.x range.
cybedtools 0.1.1
-
Hidden granularity fix. A 2026-05-08 audit of all eight frameworks found that several encode pedagogical or specification detail in prose (“Clarification statement:” segments, “such as” example lists, semicolon- delimited enumerations) inside
cybed:elementTextliterals rather than as discrete numbered standards. The naive element count under-represented the actual content density of those frameworks.v0.1.1 adds a uniform sub-point parser (
parse_subpoints()) that runs against every framework’s elementText literals at JSON-LD assembly time and promotes each parsed sub-point to a first-class child element node. Frameworks where the parser finds no sub-points (NICE, DCWF, DigComp 2.2) are unchanged. Affected frameworks gain sub-point children:Framework | v0.1.0 | v0.1.1 | Inflation NICE v2 | 2,111 | 2,115 | 1.00x DCWF v5.1 | 2,945 | 2,945 | 1.00x ECSF v1 | 374 | 390 | 1.04x SFIA 9 | 672 | 830 | 1.24x Cyber.org K-12 v1.0 | 123 | 500 | 4.07x CSTA K-12 CS (Rev 2017) | 120 | 140 | 1.17x ACM/IEEE CSEC2017 | 38 | 40 | 1.05x DigComp 2.2 | 21 | 21 | 1.00xCross-framework per-organizing-unit density recomputes from ~50x in v0.1.0 to ~12x in v0.1.1. The framing also shifts: the eight frameworks specify at incommensurable units of analysis (work role, skill level, competence, standard, Knowledge Area, competence area) and reflect different design philosophies. The cybedtools comparison layer makes them queryable in one graph but does not erase those structural distinctions. Density figures are comparison aids, not quality claims.
Parser robustness. The first iteration of
parse_subpoints()over- extracted on multi-sentence elementText (notably SFIA’s responsibility prose) by greedily consuming past sentence boundaries. Two refinements landed: a sentence-boundary stop (period + whitespace + uppercase) and a pure-connective filter (drops “and”/“or”/“the” artifacts from source- truncated lists). Re-spot-check brought SFIA from ~30% false-positive rate to 0/10 sampled, and CSEC2017 from ~33% to 0/2. All eight frameworks run with the parser enabled at release.New JSON-LD vocabulary. Two terms added to the
cybed:ontology:cybed:Subpoint(acybed:RoleElementsubtype tagging parsed sub-points) andcybed:elaborates(a predicate linking a sub-point to its parent standard). Sub-points retain framework-native subtypes for polymorphic queries: a Cyber.org K-12 sub-point is typed ascyberorg:Standard,cybed:Subpoint, andcybed:RoleElementsimultaneously.-
New exported helpers in
R/jsonld-helpers.R:-
parse_subpoints()heuristic regex parser -
build_subpoint_node()JSON-LD constructor for sub-points -
expand_with_subpoints()orchestrator that walks parent elements and emits sub-point children with deterministic IRIs (parent.sub.N) -
extend_role_element_ids()helper for role-builder integration
-
Per-framework opt-out. The environment variable
CYBED_DISABLE_SUBPOINT_PARSER(comma-separated framework slugs) disables sub-point parsing for the listed frameworks. Useful if a framework steward prefers numbered-only counts.Pipeline scripts now load the package directly. The 020-assemble-jsonld script previously sourced helpers from a hand-mirrored file path. v0.1.1 uses
pkgload::load_all()(when running from a working tree) orlibrary(cybedtools)(when running from an installed package).Tests. 52 new unit and semantic tests across parser determinism, sub-point IRI stability, type polymorphism,
cybed:elaboratestraversal, cluster-to-leaf reachability, and JSON-LD round-trip. 111 tests pass on release, no skips.-
Known limitations carrying into v0.1.2.
-
The
cybed:Roleabstraction is structurally coerced for frameworks that do not enumerate roles (SFIA enumerates skills; CSTA, Cyber.org K-12, CSEC2017, and DigComp 2.2 enumerate organizing units that are not roles). The “roles” column inframework_summaryis “the framework’s top-level organizing unit, whatever the framework calls it” rather than a count of roles in the workforce sense. v0.1.2 is slated to redesign or split this abstraction. Seedocs/framework-data-sources.mdfor the per-framework structural mapping. -
The
cybed:Subpointtype is overstated for Cyber.org K-12 and CSTA “Clarification statement:” examples. These are formally teacher- facing scaffolding describing the level-of-rigor expectation for the standard, not enumerable sub-standards. The current schema types them as if they were sub-standards, which is queryable but slightly overstates what the framework expects. v0.1.2 will introduce a distinctcybed:Exampletype and exclude these promoted nodes from defaultcybed:hasElementcollections.
-
The
