compliance-personnel-verification-udm¶
compliance-personnel-verification-udm0.1.0noneTags: compliance sfi rst personnel-verification veras pre-award conflict-of-interest research-security-training udm structured-extraction json
Audience: sponsored-programs-staff, pre-award-teams, compliance-officers
Manifestations in repo: prompt.md
Automates the SFI (Significant Financial Interest) disclosure and RST (Research Security Training) compliance check across every person named on a federal research proposal. Joins three input sources — the VERAS proposal package, the institutional SFI disclosure records, and the most recent daily RST completion spreadsheet — into a per-person compliance matrix that a Sponsored Programs Administrator (SPA) reviews in seconds rather than minutes per person. Covers the source PROC-SFI-RST-COMPLIANCE-CHECK process (10 steps, 80% automatable per the source process map).
Output contract: schema.json
Contract scope: repo-local, UDM-aligned
Inputs¶
Three workflow documents must be uploaded together in Vandalizer:
- VERAS proposal package — at minimum Section 2 (PI / senior key personnel) and Section 6.6 (personnel requiring SFI disclosures).
- Institutional SFI disclosure records — the searchable export, scanned correspondence, or extracted records the SPA would otherwise grep through manually.
- Daily RST completion spreadsheet — typically the UI Bridge daily export.
When any of the three is missing, the contract requires the workflow to emit null in the affected fields and capture the gap in verification_status.notes. The contract never silently assumes compliance.
Outputs¶
A single JSON object with six structured blocks:
proposal_metadata—proposal_type(enum),sponsor_type(enum),sfi_rst_required(boolean)personnel_identification—section_66_personnel[],section_2_personnel[](with role + department),consolidated_personnel[](deduplicated union withsource_sections),personnel_discrepancies[]sfi_verification— array of{name, disclosure_found, disclosure_date, days_since_disclosure, valid_within_365_days, status}(five-value status enum)rst_verification—{spreadsheet_date, spreadsheet_source, records[]}where each record is{name, found_in_spreadsheet, completion_date, status}(three-value status enum)non_compliant_personnel— array of{name, issue, required_action, priority}(three-value priority enum)verification_status—total_personnel_checked, three compliant counts,overall_status(three-value enum),notes
See schema.json for the authoritative definition and prompt.md for encoding rules (365-day validity window, ambiguous-match flagging, no-assumption-of-compliance rule).
Contract scope¶
Repo-local, UDM-aligned. The proposal record itself resolves to UDM Proposal; personnel resolve to UDM Personnel.First_Name / Personnel.Last_Name; the verification matrix itself is a repo-local compliance surface that does not (yet) have a shared UDM table.
Triad integration¶
- Evaluation datasets: none yet — planned: a synthetic federal research proposal exercise with three deliberately-mismatched personnel records (one SFI valid, one SFI expired, one SFI not found) and at least one RST-incomplete person, validated by a compliance officer.
- Harness notes: canonical manifestation is
prompt.md. Validation surface isschema.json. The contract assumes the SFI records and RST spreadsheet are uploaded as workflow documents alongside the VERAS proposal — the workflow does not call external systems. - Shared UDM relationship: aligned, not owning. The per-person verification rows do not map to a shared UDM compliance table — they are a repo-local extension of UDM Personnel records.
Relationship to other components¶
| Concern | Source of truth |
|---|---|
| SFI disclosure + RST completion check across federal research proposal personnel | compliance-personnel-verification-udm (this component) |
| Section 2 PI / Co-PI eligibility against APM 45.22 | section2-personnel-eligibility-udm |
| Proposal-document-completeness gap analysis (different VERAS sections, document-level requirements) | proposal-document-completeness-udm |
The three pre-award compliance components are versioned independently and intended to run together on a single proposal upload to produce a comprehensive readiness review.
Runtime topology — the Vandalizer workflow¶
The canonical runtime for this component is the compliance-personnel-verification workflow shipped at the top level of this repo. The single source of truth is workflows/compliance-personnel-verification/manifest.yaml; the companion .vandalizer.json envelope is generated by scripts/build_vandalizer_workflows.py and committed alongside. The runtime mirrors the source ui-insight/ProcessMapping/workflows/compliance-personnel-verification/ workflow:
- Step 1 (parallel Extraction) — two Extraction tasks mirror the source workflow one-for-one: personnel-identification (pulls Sections 6.6 and 2, derives the consolidated list and the
sfi_rst_requiredflag) and compliance-status-verification (per-person SFI + RST lookup with status flags). - Step 2 (Consolidation Prompt) — assembles the two JSON fragments into the schema-conformant six-block object, builds the cross-product compliance matrix, derives
non_compliant_personnelandverification_statusfrom the per-person status records, and enforces the no-assumption-of-compliance rule.
Regenerate the workflow JSON whenever this component bumps MINOR or MAJOR (or whenever the workflow manifest changes); CI fails if the committed .vandalizer.json drifts from a fresh build.
Manifestations¶
prompt.md— canonical, LLM-agnostic prompt
Evals¶
See evals/ for reference inputs and known-good outputs. Initial case pending: a synthetic federal research proposal with a deliberately mixed compliance profile validated by a compliance officer.
Provenance¶
Authored 2026-05-20 against the compliance-personnel-verification (Workflow_ID: WF-COMPLIANCE-PERSONNEL-VERIFY) process-mapping workflow in ui-insight/ProcessMapping at commit 2c1f47f46474130743af5aee44d074bcd21787e9, which was built from the PROC-SFI-RST-COMPLIANCE-CHECK process map (10 steps, 80% automatable). Created to make the SPA's pre-award compliance check a harness-evaluatable, versioned artifact rather than a manual email-folder-and-spreadsheet workflow.
Contract scope¶
-
Output format:
json_object -
Contract scope:
shared_udm_semantics_repo_local_schema -
Validation surfaces:
json_schema -
Schema entrypoints:
# -
Notes: Repo-local SFI + RST personnel-verification contract for federal research proposals. Six structured blocks (proposal_metadata, personnel_identification, sfi_verification, rst_verification, non_compliant_personnel, verification_status) covering the consolidated cross-section personnel list, per-person SFI / RST status with five-value and three-value enums, derived non-compliance flags with priority, and overall summary counts. The workflow requires three workflow documents to be uploaded together (VERAS proposal, SFI disclosure records, daily RST completion spreadsheet); missing sources do not produce silent compliance — they produce non-compliant defaults and a notes gap-flag.
-
Machine-readable catalog entry:
component_catalog.json
Triad integration¶
-
UDM alignment:
shared_udm_semantics_repo_local_schema— section_2_personnel[].name resolves to UDM Personnel.First_Name / Personnel.Last_Name; the proposal record itself resolves to UDM Proposal. The per-person SFI / RST verification matrices are repo-local — no shared UDM compliance table exists for them yet. -
Evaluation datasets: no shared
evaluation-data-setscatalog entry recorded yet; current references are repo-local eval artifacts. -
Harness notes: Validate JSON outputs against schema.json. Canonical single-call invocation surface is prompt.md. The companion top-level workflows/compliance-personnel-verification Vandalizer workflow at v0.1.0 implements the contract as two parallel Extraction tasks (personnel identification + compliance status verification) plus a Consolidation Prompt that derives non_compliant_personnel from the SFI / RST per-person status records and computes the five verification_status counts. Campaign authors should record both single-call and post-consolidation signals when both are available.
-
Related component:
section2-personnel-eligibility-udm(sibling_pre_award_personnel_check) — Both components run against the same VERAS Section 2 personnel. compliance-personnel-verification-udm checks SFI disclosure + RST completion (compliance state); section2-personnel-eligibility-udm checks APM 45.22 PI / Co-PI eligibility (role state). -
Related component:
proposal-document-completeness-udm(sibling_pre_award_review) — Both components run on a VERAS upload during pre-award review. proposal-document-completeness-udm checks document-level inventory and gap analysis; compliance-personnel-verification-udm checks per-person SFI and RST compliance.
Prompt body¶
Source: prompt.md.
Show prompt
Compliance Personnel Verification (SFI & RST) — UDM JSON¶
Purpose: Automate the SFI (Significant Financial Interest) disclosure and RST (Research Security Training) compliance check on every person named in a federal research proposal. Extract personnel from VERAS Sections 2 and 6.6, cross-reference each person against SFI disclosure records and the daily RST completion spreadsheet, and produce a per-person compliance matrix that a Sponsored Programs Administrator (SPA) can review without manually searching email folders and spreadsheets.
Expected input: The VERAS proposal package PLUS the institutional SFI disclosure records and the most recent daily RST completion spreadsheet, all uploaded into Vandalizer as workflow documents. The workflow runs against the federation of these documents.
Expected output: A single JSON object that validates against
schema.json. No prose, no markdown outside the JSON.
When to use this contract¶
This component automates the most repetitive part of an SPA's pre-award review on federal research proposals. The SPA must confirm that every PI, Co-PI, and Senior/Key Person:
-
has a current Significant Financial Interest (SFI) disclosure on file (valid within 365 days of submission), and
-
has completed Research Security Training (RST) per the institution's record.
The source process-mapping workflow (PROC-SFI-RST-COMPLIANCE-CHECK) is 80% automatable but currently requires an SPA to email-search the SFI records folder and spreadsheet-lookup the daily RST export. This component produces the same compliance matrix from the same three input documents.
Federal research proposals only. SFI and RST checks do not apply to non-research proposals or non-federal sponsors. The contract captures proposal_type and sponsor_type explicitly, and the boolean sfi_rst_required drives whether the consumer (SPA, downstream automation) should act on the compliance matrix at all.
This component does not cover Section 2 PI eligibility against APM 45.22 — that lives in section2-personnel-eligibility-udm. It does not cover Conflict-of-Interest management plans beyond the SFI disclosure presence check.
Prompt¶
You are verifying SFI disclosure and RST completion status for every person named on a federal research proposal. You will receive THREE document sources as workflow input:
-
The VERAS proposal package (Section 2 = PI / senior key personnel; Section 6.6 = personnel requiring SFI disclosures),
-
The institutional SFI disclosure records (extracted, emailed, or scanned), and
-
The most recent daily RST completion spreadsheet from UI Bridge.
If any of the three is missing, emit null in the corresponding output fields and flag the missing source explicitly in verification_status.notes. Do not assume compliance without positive evidence.
Be 100% accurate. Quote dates verbatim. Use ISO YYYY-MM-DD for SFI disclosure dates whenever the source is unambiguous. When in doubt about an ambiguous name match (e.g., two people share a last name and you cannot disambiguate by department), flag the person as "Review Required" rather than guessing.
Return a single JSON object that validates against schema.json with these top-level keys:
-
proposal_metadata— object describing the proposal and the determination of whether SFI / RST checks apply. -
personnel_identification— object describing the personnel pulled from VERAS Sections 2 and 6.6 and the consolidated check list. -
sfi_verification— array of per-person SFI status records. -
rst_verification— object with the spreadsheet metadata and array of per-person RST status records. -
non_compliant_personnel— array of per-person flags for any compliance issue. -
verification_status— object summarizing overall compliance.
proposal_metadata¶
-
proposal_type— one of"Research","Non-Research","Not specified". Required. -
sponsor_type— one of"Federal","State","Non-Federal","Not specified". Required. -
sfi_rst_required— boolean. Required.truewhenproposal_type == "Research"ANDsponsor_type == "Federal".falsein every other combination.
personnel_identification¶
-
section_66_personnel— array of strings. Names listed in VERAS Section 6.6 requiring SFI disclosures. Required (may be empty). -
section_2_personnel— array of{name, role, department}objects from VERAS Section 2 PIs and Senior/Key Personnel. Required (must contain at least one entry, since every research proposal has a PI). Eachroleis one of"PI","Co-PI","Senior/Key Personnel".departmentisnullwhen not stated. -
consolidated_personnel— array of{name, role, department, source_sections}objects representing the deduplicated union ofsection_66_personnelandsection_2_personnel. Required.source_sectionsis an array containing one or both of"6.6","2". -
personnel_discrepancies— array of strings. Differences between the two source sections (e.g., person in Section 2 but missing from Section 6.6). Empty array when lists match.
sfi_verification¶
Array of per-person {name, disclosure_found, disclosure_date, days_since_disclosure, valid_within_365_days, status} objects. One entry per person in consolidated_personnel.
-
disclosure_found— boolean. -
disclosure_date— string in ISOYYYY-MM-DDwhen found;nullotherwise. -
days_since_disclosure— integer whendisclosure_foundistrue;nullotherwise. -
valid_within_365_days— boolean whendisclosure_foundistrue;nullotherwise. -
status— one of"Valid","Expiring Soon"(valid but ≤ 30 days from expiration),"Expired","Not Found","Review Required"(ambiguous match).
rst_verification¶
-
spreadsheet_date— string in ISOYYYY-MM-DD. Required. Date of the RST completion spreadsheet used. -
spreadsheet_source— string. Source label (e.g.,"UI Bridge daily export"). Required. -
records— array of per-person{name, found_in_spreadsheet, completion_date, status}objects. One entry per person inconsolidated_personnel. -
found_in_spreadsheet— boolean. -
completion_date— string in ISOYYYY-MM-DDwhen found;nullotherwise. -
status— one of"Complete","Incomplete","Review Required"(ambiguous match).
non_compliant_personnel¶
Array of {name, issue, required_action, priority} objects. One entry per compliance issue (a single person may have multiple entries if both SFI and RST fail).
-
issue— short string describing the issue (e.g.,"SFI disclosure not found","SFI disclosure expired","RST not completed"). -
required_action— short string describing the remediation (e.g.,"Submit SFI disclosure before proposal submission"). -
priority— one of"Critical"(blocks submission),"High"(must renew immediately),"Medium"(expires within 30 days).
Empty array when every person is compliant.
verification_status¶
-
total_personnel_checked— integer. -
sfi_compliant_count— integer. -
rst_compliant_count— integer. -
fully_compliant_count— integer (both SFI and RST compliant). -
overall_status— one of"All Compliant","Non-Compliance Found","Not Applicable"(whensfi_rst_requiredisfalse). -
notes— string ornull. Use for source-document warnings, e.g.,"SFI disclosure records not provided as a workflow document — cannot determine SFI status.".
Encoding rules¶
-
Dates are ISO
YYYY-MM-DD. When the source spreadsheet usesMM/DD/YYYYor another format, convert to ISO. -
Booleans are JSON booleans, not the strings
"true"/"false"or"Yes"/"No". -
Days-since-disclosure is a JSON integer, computed from the disclosure date relative to the proposal submission date (or today's date if the proposal date is not in the documents).
-
Counts are JSON integers, not quoted strings.
-
Ambiguous matches are flagged, not guessed. When two records could match the same name, emit
status: "Review Required"and capture the ambiguity inverification_status.notes. -
Do NOT assume compliance. A person missing from the SFI records is
"Not Found", not"Valid". A person missing from the RST spreadsheet is"Incomplete", not"Complete".
Output¶
A single JSON object. No surrounding markdown.
Output schema¶
Source: schema.json.
Show schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/AI4RA/prompt-library/components/compliance-personnel-verification-udm/schema.json",
"title": "Compliance Personnel Verification (SFI & RST) \u2014 UDM Output",
"description": "JSON contract for verifying SFI disclosure status and Research Security Training (RST) completion across every person named on a federal research proposal. The workflow joins three inputs (VERAS proposal package, institutional SFI disclosure records, daily RST completion spreadsheet) and produces a per-person compliance matrix with non-compliance flags and remediation priorities. Mirrors the source ui-insight/ProcessMapping compliance-personnel-verification workflow.",
"version": "0.1.0",
"type": "object",
"additionalProperties": false,
"required": [
"proposal_metadata",
"personnel_identification",
"sfi_verification",
"rst_verification",
"non_compliant_personnel",
"verification_status"
],
"properties": {
"proposal_metadata": {
"type": "object",
"additionalProperties": false,
"required": [
"proposal_type",
"sponsor_type",
"sfi_rst_required"
],
"properties": {
"proposal_type": {
"type": "string",
"enum": [
"Research",
"Non-Research",
"Not specified"
],
"description": "Whether the proposal is a research proposal. Required by source workflow."
},
"sponsor_type": {
"type": "string",
"enum": [
"Federal",
"State",
"Non-Federal",
"Not specified"
],
"description": "Whether the sponsor is federal, state, or non-federal. Required by source workflow."
},
"sfi_rst_required": {
"type": "boolean",
"description": "Whether SFI and RST checks are required for this proposal. Required by source workflow. True when proposal_type == 'Research' AND sponsor_type == 'Federal'; false otherwise."
}
}
},
"personnel_identification": {
"type": "object",
"additionalProperties": false,
"required": [
"section_66_personnel",
"section_2_personnel",
"consolidated_personnel",
"personnel_discrepancies"
],
"properties": {
"section_66_personnel": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"description": "Names listed in VERAS Section 6.6 requiring SFI disclosures. Required by source workflow (may be empty when the section is not present)."
},
"section_2_personnel": {
"type": "array",
"minItems": 1,
"description": "PIs and Senior/Key Personnel from VERAS Section 2. Required by source workflow. Must contain at least one entry (every proposal has a PI). Resolves to UDM Personnel.First_Name / Personnel.Last_Name.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"role"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"role": {
"type": "string",
"enum": [
"PI",
"Co-PI",
"Senior/Key Personnel"
]
},
"department": {
"type": [
"string",
"null"
]
}
}
}
},
"consolidated_personnel": {
"type": "array",
"description": "Deduplicated union of Section 6.6 and Section 2 personnel that require SFI and / or RST verification. Required by source workflow.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"role",
"source_sections"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"role": {
"type": "string",
"enum": [
"PI",
"Co-PI",
"Senior/Key Personnel"
]
},
"department": {
"type": [
"string",
"null"
]
},
"source_sections": {
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"enum": [
"6.6",
"2"
]
},
"description": "Which VERAS source section(s) listed this person."
}
}
}
},
"personnel_discrepancies": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"description": "Differences between the Section 6.6 and Section 2 personnel lists (e.g., person in Section 2 but missing from Section 6.6). Empty array when the lists match."
}
}
},
"sfi_verification": {
"type": "array",
"description": "Per-person SFI disclosure verification records, one entry per person in consolidated_personnel.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"disclosure_found",
"status"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"disclosure_found": {
"type": "boolean"
},
"disclosure_date": {
"type": [
"string",
"null"
],
"description": "ISO YYYY-MM-DD when found; null otherwise."
},
"days_since_disclosure": {
"type": [
"integer",
"null"
],
"minimum": 0,
"description": "Days between disclosure_date and the proposal submission date. JSON integer. Null when disclosure_found is false."
},
"valid_within_365_days": {
"type": [
"boolean",
"null"
],
"description": "True when days_since_disclosure <= 365. Null when disclosure_found is false."
},
"status": {
"type": "string",
"enum": [
"Valid",
"Expiring Soon",
"Expired",
"Not Found",
"Review Required"
],
"description": "Valid = within 365 days; Expiring Soon = valid but within 30 days of expiration; Expired = > 365 days; Not Found = no disclosure on file; Review Required = ambiguous match."
}
}
}
},
"rst_verification": {
"type": "object",
"additionalProperties": false,
"required": [
"spreadsheet_date",
"spreadsheet_source",
"records"
],
"properties": {
"spreadsheet_date": {
"type": "string",
"description": "ISO YYYY-MM-DD date of the RST completion spreadsheet used for verification. Required by source workflow."
},
"spreadsheet_source": {
"type": "string",
"minLength": 1,
"description": "Source label for the spreadsheet (e.g., 'UI Bridge daily export'). Required by source workflow."
},
"records": {
"type": "array",
"description": "Per-person RST completion records, one entry per person in consolidated_personnel.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"found_in_spreadsheet",
"status"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"found_in_spreadsheet": {
"type": "boolean"
},
"completion_date": {
"type": [
"string",
"null"
],
"description": "ISO YYYY-MM-DD when found; null otherwise."
},
"status": {
"type": "string",
"enum": [
"Complete",
"Incomplete",
"Review Required"
]
}
}
}
}
}
},
"non_compliant_personnel": {
"type": "array",
"description": "Per-person compliance issue records (one person may have multiple entries when both SFI and RST fail). Empty array when every person is compliant.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"issue",
"required_action",
"priority"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"issue": {
"type": "string",
"minLength": 1
},
"required_action": {
"type": "string",
"minLength": 1
},
"priority": {
"type": "string",
"enum": [
"Critical",
"High",
"Medium"
],
"description": "Critical = blocks submission (no SFI on file or RST not completed); High = SFI expired needs immediate renewal; Medium = SFI expires within 30 days."
}
}
}
},
"verification_status": {
"type": "object",
"additionalProperties": false,
"required": [
"total_personnel_checked",
"sfi_compliant_count",
"rst_compliant_count",
"fully_compliant_count",
"overall_status"
],
"properties": {
"total_personnel_checked": {
"type": "integer",
"minimum": 0
},
"sfi_compliant_count": {
"type": "integer",
"minimum": 0
},
"rst_compliant_count": {
"type": "integer",
"minimum": 0
},
"fully_compliant_count": {
"type": "integer",
"minimum": 0
},
"overall_status": {
"type": "string",
"enum": [
"All Compliant",
"Non-Compliance Found",
"Not Applicable"
],
"description": "All Compliant = every person passed; Non-Compliance Found = at least one non-compliant entry; Not Applicable = sfi_rst_required is false."
},
"notes": {
"type": [
"string",
"null"
],
"description": "Source-document warnings (e.g., SFI records not provided, ambiguous name matches). Null when no notes apply."
}
}
}
}
}
Changelog¶
Source: CHANGELOG.md.
All notable changes to this component. Versions follow semver: MAJOR for output-contract breaks, MINOR for backward-compatible additions, PATCH for wording or clarity.
[0.1.0] — 2026-05-20¶
- Initial experimental release.
- Schema derived from the
compliance-personnel-verificationv1 Vandalizer workflow inui-insight/ProcessMapping(two parallel extraction tasks, 10 source fields, two cross-field rules, four validation-plan checks). - Six-block shape (
proposal_metadata+personnel_identification+sfi_verification+rst_verification+non_compliant_personnel+verification_status) covers both the per-person verification matrices and the proposal-level applicability metadata + summary counts. proposal_typeexposed as the three-value enum (Research,Non-Research,Not specified) andsponsor_typeas the four-value enum (Federal,State,Non-Federal,Not specified) — matches the source workflow.- SFI per-person
statusexposed as a five-value enum (Valid,Expiring Soon,Expired,Not Found,Review Required) per the source workflow's task instructions; RST per-personstatusas three-value (Complete,Incomplete,Review Required); non-compliancepriorityas three-value (Critical,High,Medium); overalloverall_statusas three-value (All Compliant,Non-Compliance Found,Not Applicable). - Source
Is_Required: truefields mirrored intorequiredlists at the block level (proposal_type,sponsor_type,sfi_rst_required,section_66_personnel,section_2_personnel,consolidated_personnel,spreadsheet_date, the five summary counts). - Counts (
total_personnel_checked,sfi_compliant_count,rst_compliant_count,fully_compliant_count) typed as JSON integers, not quoted strings.days_since_disclosureis a JSON integer withminimum: 0. - UDM column bindings preserved at the leaf level:
section_2_personnel[].name→Personnel.First_Name/Personnel.Last_Name. The verification matrices themselves are repo-local — no shared UDM compliance table exists for them yet. - Multi-source input model documented explicitly: the contract assumes the SFI disclosure records and RST completion spreadsheet are uploaded as workflow documents alongside the VERAS proposal. When any input is missing, the contract requires the workflow to emit
nulland capture the gap inverification_status.notesrather than silently assuming compliance. - No eval cases yet — status
experimentaluntil at least one golden extraction is added underevals/cases/.