Repository navigation
Data model for verification methods (follow-up to #101 / #186) #191
Description
Activity
Thanks, @a-moskvin. This is a well-reasoned proposal, and it answers all three problems from #186. I checked its claims against current
mainbefore replying.What holds up
- Separating method review from link review is the right split. "Is this method well written?" and "does it verify this control?" are different judgments. Keeping them apart is what lets a reviewed method be reused without re-review.
- Both link levels are justified by the data. Re-measured on
main: 93.8% of the 3,771 mapping rows use a control that's also mapped to another risk in the same framework. Your CoSAIWS4-AGT-2.2example is real: it's mapped to ASI03, ASI05 and ASI07, and also to LLM06 and four DSGAI entries. - You're right about the registries, and it corrects my earlier suggestion. On feat(schema): optional verification_method field + Agentic_AIUC1 pilot #186 I proposed holding methods on the registry controls.
ingest-framework.mjswrites the whole registry on re-ingest, so they'd be wiped on the next sync. A separate links file is better. - Deprecating rather than reusing method IDs matches a lesson this repo learned the hard way: several retired ASVS and ATLAS identifiers now name different requirements upstream.
examine/interview/testfrom SP 800-53A is a good, recognisable vocabulary. Thanks for the disclosure, too.
Before implementation
-
Allow citing a source whose licence isn't CC BY-SA-compatible. As written,
source.licensemust be compatible andsource.textis required verbatim. That rules out the case from feat(schema): optional verification_method field + Agentic_AIUC1 pilot #186: pointing at AIUC-1's own evidence (its terms are proprietary) or at ISO. Proposal: makesource.textoptional, and forbidden when the licence isn't compatible, so a method can cite a source byid+urlwithout reproducing it. A validator rule enforces that. It also lets a link point at a framework's canonical verification instead of an alternative to it. -
Make the
frameworkkey explicit. §2.4 says the registry id (aiuc-1), but mapping rows are keyed by display name (AIUC-1). The id is the better key, because display names change: ASVS was just renamed from 4.0.3 to 5.0.0. Rule 10 then needs to state that it resolves id → registrynamebefore matching the row. -
Keep review states from overstating each other. Two validator warnings:
- a link with a non-empty
reviewed_bywhose method is stilldraft; - a row-level link on a mapping row that is itself
unreviewed.
Otherwise a consumer could show "reviewed" on top of unreviewed data. Proposal:
reviewed_byfollows the existing schema v2 convention (named humans, perdocs/SCHEMA_V2_MIGRATION.md) rather than introducing GitHub handles, so all three review fields mean the same thing. - a link with a non-empty
-
Scope the consumers. The proposal says what's stored but not what reads it. Suggest v1 = data, schemas and validator only: no
generate.js, export or webapp changes. The webapp is frozen except by maintainer approval, and OLIR has no field for this anyway. Consumers can follow once the data exists. -
Merge conflicts. Parallel PRs that each append to one
linksarray will conflict at its end. Proposal: one links file per framework (data/verification-links/<framework-id>.json), or a single file with a sort order the validator enforces. -
Small consistency fixes in the text:
- there are two §1.5 headings;
- §1.2 points to "see 1.2" / "see 1.3" for
method_typeandfrequency, which live in §1.3 and §1.4; - §1.7 changes
unmodifiedtoadapted, but neither value is defined anywhere.
Suggested first PR
Once this settles:
- the two schemas, the validator rules (with tests) and the link files;
- a pilot of up to 10 methods, all
draft, on one framework with no verification layer of its own. Your choice of framework; name it here first.
#186 can then be closed as superseded when that PR lands.
Thanks @emmanuelgjr .
All six points accepted:
- Licences:
source.textis optional, so a source under a non-compatible licence (e.g. AIUC-1, ISO) is cited byid+urlonly. I've left licence compatibility to contributor and reviewer judgment rather than a validator rule: a fixed list of compatible licences would need maintaining across licences and versions.licensestays required, so the licence is always visible in review. - Framework key: the registry id. Row-level links resolve id → registry
namebefore matching the mapping row. - Review states: two warnings, for a reviewed link on a draft method and for a reviewed row-level link on an unreviewed row.
reviewed_byholds named humans, perSCHEMA_V2_MIGRATION.md. - Consumers: v1 is data, schemas and validator only.
- Merge conflicts: one links file per framework (
data/verification-links/<framework-id>.json, withframeworkdeclared once per file), plus an enforced sort order. - Text fixes: done in
docs/VERIFICATION_METHODS.md, which becomes the spec.
I'd like to split delivery:
- PR 1 with the schemas, validator rules, tests and docs, and no methods;
- PR 2 with the pilot of up to 10 draft methods.
That keeps the model reviewable on its own. I'll name the pilot framework here before PR 2.
- Licences:
Opened PR 1 with the schemas, validator rules, tests and docs, and no methods: #215
Opened PR 2 #216 : pilot framework: NIST AI RMF 1.0.
Scope: the pilot links only to the 6 subcategories whose registry titles match AI RMF 1.0 (GV-1.6, GV-1.7, MP-2.3, MP-4.1, MP-5.1, MS-2.6). The other 5 mapped subcategories have confusing labelling in the registry; I'll open a separate issue with the details.
10 draft methods: 6 control-level and 4 row-level links (ASI01, ASI02, ASI03, ASI10); 8 adapted from the NPW catalogue v2.4.0 and 2 project-authored (
source: null). Alldraft, none reviewed.- added a commit that references this issue
on Oct 9, 2026
Context
#101 identified a gap: control tables say what a control requires, not how to check it is implemented.
#186 piloted this as a free-text
verification_methodcolumn onAgentic_AIUC1.md. Review on #186 found three problems:DRAFT — … (NPW C02)), so tools can't read them, and no field records who reviewed a method.Goal
This issue proposes a structured data model for verification methods:
Overview
Two new source files, hand-edited through PRs similar to
incidents.json, each with a companion schema:data/verification-methods.jsondata/verification-methods-schema.jsondata/verification-links.jsondata/verification-links-schema.json1. Method file:
data/verification-methods.json1.1 File structure
The file holds the method objects (1.2) in a
methodsarray:{ "version": "1.0", "description": "Verification methods: how to check a control is implemented. Methods with a `source` are adapted from the cited source; the original wording is in `source.text`.", "methods": [ { "...": "method objects, see 1.2" } ] }1.2 Method object
id^VM-\d{4}$.namemethod_typeexamine,interview,test(see 1.2).procedureexpected_resultsourcenullfor a method authored in the project (see 1.4, 1.5).statusdraft,reviewed,deprecated(see 1.6).reviewed_bydraft.frequencyevidencereview_datestatus_notestatusisdeprecated: the reason, and the replacement ID if there is one.1.3
method_typevaluesBased on the assessment methods in NIST SP 800-53A.
examineinterviewtest1.4
frequency(optional)A recommended minimum, not a requirement.
modevaluecontinuousperiodicevent_drivenfrequencyis an object, not a plain string, so that details such asintervalortriggerscan be added later without breaking existing data (section 5).1.5 Provenance
Provenance is expressed by
source:sourcepresent: the method is derived from the cited source. The source's original wording is kept insource.text.source: null: the method was originated in the project.1.5
sourceobjectnameversionidC02)urllicensetext1.6
statusdraftreviewedreviewed_bydeprecatedstatus_noteDeprecated methods stay in the methods file for consistency, and ID never used for something else.
1.7 Change rules
unmodifiedbecomesadapted.deprecated, withstatus_notenaming the replacement (e.g. "Replaced by VM-0031"). Its links should be re-pointed in the same PR (2.1).1.8 Examples
Adapted from an external catalogue:
{ "id": "VM-0001", "name": "Injection test across ingestion paths", "method_type": "test", "procedure": "Submit a maintained injection payload set through each distinct ingestion path (user input, retrieved documents, tool output).", "expected_result": "No payload alters the agent goal or triggers an unauthorised action; all attempts are logged.", "source": { "name": "NPW Agentic AI Control Catalogue", "version": "2.4.0", "id": "C02", "url": "https://www.newpacificway.com/ai-controls", "license": "CC BY-SA 4.0", "text": "Injection test executed through each distinct ingestion path." }, "status": "draft", "reviewed_by": [], "frequency": { "mode": "event_driven" }, "evidence": "Test report with payload set version and per-path results." }Originated in the project:
{ "id": "VM-0002", "name": "Supply-chain scope of third-party adversarial testing", "method_type": "examine", "procedure": "Review the scope section of the current third-party adversarial test report.", "expected_result": "Tools, connectors and MCP servers used by the agent are explicitly in scope.", "source": null, "status": "draft", "reviewed_by": [] }2. Links file:
data/verification-links.json2.1 Why a separate links file
Links are stored once, in their own file, rather than inside method records or framework registries for the following reasons:
draft. Linking a reviewed method to a new control does not touch the method record, so its review stands.scripts/ingest-framework.mjswrites a framework registry whole on re-ingest, so links stored on registry controls would be lost on the next sync.2.2 Control level and row level
A link is applied either to a control (control level) or to risk–control pair (row level). Both levels are needed:
WS4-AGT-2.2"Agent cybersecurity baseline" is mapped to ASI03 (identity: verify authentication), ASI05 (code execution: verify input validation) and ASI07 (inter-agent communication: verify secure channels). These three threats require different verification methods for the same control.Rule for contributors: does the method verify the control the same way regardless of the risk?
entry_id: null.entry_idset to the risk entry.2.3 File structure
The file holds the link objects (2.4) in a
linksarray:{ "version": "1.0", "links": [ { ... }, { ... } ] }2.4 Link object
method_idverification-methods.jsonframeworkdata/frameworks/<id>.jsoncontrol_idcontrol_idindata/frameworks/<id>.jsonentry_idnull: the link applies to the control. An entry ID from a risk list (LLM01,ASI04,DSGAI07,AST01): the link applies only to that risk–control row.reviewed_byCombination (
method_id,framework,control_id,entry_id) is unique. No separate link ID or status field is needed.2.5 Link lifecycle
reviewed_by(draft). It counts as reviewed once an SME adds their handle.reviewed_byis cleared.3. Validation rules (
scripts/validate.js)Methods file
verification-methods-schema.json, including enum values,additionalProperties: falseand the 80-characternamelimit.^VM-\d{4}$.reviewedrequires a non-emptyreviewed_by.deprecatedrequiresstatus_note.sourceis present, all its fields are required.Links file
verification-links-schema.json.method_id,framework,control_id,entry_id) is unique.method_idexists in the methods file. A link to a deprecated method is a warning, not an error.framework,control_id) resolves to a control indata/frameworks/.entry_idis set, a mapping row exists for that entry, framework and control IDs.4. Considerations for future development
elements that can be added later without impacting existing data:
frequency.intervalperiodic(e.g.P3M)frequency.triggersevent_driven(e.g.model_change,tool_change)supersededstatus +superseded_bystatus_noteis insufficientstatusandreview_dateDisclosure: NPW (New Pacific Way Ltd.) is my company, and the NPW Agentic AI Control Catalogue is its catalogue. Methods derived from it will say so in their
sourcefield and in the PR.