Defense & Aerospace
ADL v0.3 for Defense & Aerospace
Reference ADL domains for defense and aerospace — engineering-change management, export control / ITAR, requirements and certification traceability, and CMMC — built to the ADL v0.3 specification.
Defense and aerospace programs live and die by control: who may change a design, who may see export-controlled data, whether every requirement traces to a verified test, and whether a contractor can prove its security posture on demand. This paper works four such domains in the Application Definition Language (ADL): engineering change management, ITAR access control, DO-178C requirements traceability, and CMMC compliance tracking. It shows how authorization, separation of duties, lifecycle state, and audit history are declared as data and enforced by the Kalos runtime rather than hand-written per application.
Each domain below is a complete, runnable ADL definition. Together they demonstrate a single thesis: the controls a program office actually cares about are structural properties of the application, and structure is exactly what ADL makes explicit.
Domain 1: Engineering Change Management (changemgmt)
domain:
name: changemgmt
version: "1.0.0"
description: >
Engineering Change Proposal lifecycle with CCB approval, structural
segregation of duties, and a complete audit narrative. Independence is
enforced by AEL guards, not policy: the originator cannot approve, the
implementer cannot verify, and admin cannot bypass either gate.
channels:
email:
provider: smtp
host: ${SMTP_HOST}
port: ${SMTP_PORT:587}
from: "cm-noreply@example.com"
objects:
Timestamp:
createdAt: { type: datetime, autoNow: create }
updatedAt: { type: datetime, autoNow: update }
enums:
EcpStatus:
values:
draft: { label: "Draft", color: "#94a3b8" }
submitted: { label: "Submitted", color: "#3b82f6" }
technical_review: { label: "Technical Review", color: "#8b5cf6" }
ccb_review: { label: "CCB Review", color: "#f59e0b" }
approved: { label: "Approved", color: "#10b981" }
implementing: { label: "Implementing", color: "#f97316" }
verification: { label: "Verification", color: "#06b6d4" }
closed: { label: "Closed", color: "#059669", final: true }
rejected: { label: "Rejected", color: "#ef4444", final: true }
deferred: { label: "Deferred", color: "#64748b" }
EcpClass:
values:
class_i: { label: "Class I - Major Change",
description: "Affects form, fit, or function. Requires government approval." }
class_ii: { label: "Class II - Minor Change",
description: "Does not affect form, fit, or function. Contractor authority." }
EcpPriority:
values:
routine: { label: "Routine", color: "#94a3b8" }
urgent: { label: "Urgent", color: "#f59e0b" }
emergency: { label: "Emergency", color: "#ef4444" }
ControlMarking:
values:
cui: { label: "CUI - Controlled Unclassified" }
fouo: { label: "FOUO - For Official Use Only" }
itar_usml: { label: "ITAR - USML" }
ear_ccl: { label: "EAR - CCL" }
resources:
Proposal:
description: >
An Engineering Change Proposal (ECP). Single-word resource name so the
generated route segment is unambiguous: /api/v1/changemgmt/proposals.
object:
id: { type: uuid, primaryKey: true }
ecpNumber: { type: string, required: true, unique: true, immutable: true, maxLength: 40 }
title: { type: string, required: true, minLength: 10, maxLength: 200 }
configurationItem: { type: string, required: true, maxLength: 120 }
ciBaseline: { type: string, required: true, maxLength: 60 }
ecpClass: { $ref: '#/enums/EcpClass', required: true }
priority: { $ref: '#/enums/EcpPriority', default: routine }
status: { $ref: '#/enums/EcpStatus', default: draft }
description: { type: markdown, required: true }
justification: { type: markdown, required: true }
impactAssessment: { type: markdown }
rejectionReason: { type: text } # was required by transitions but missing from the model
affectedDocuments: { type: json }
affectedHardware: { type: json }
affectedSoftware: { type: json }
costImpact: { type: money }
scheduleImpactDays: { type: integer, min: 0 }
weightImpactKg: { type: float }
# createdById matches the owner-resolution convention (createdById → userId → authorId),
# so the `owner` symbol resolves.
createdById: { type: string, required: true, immutable: true, maxLength: 100 }
originatorName: { type: string, required: true, maxLength: 120 }
leadEngineerId: { type: string, maxLength: 100 }
leadEngineerName: { type: string, maxLength: 120 }
implementerId: { type: string, maxLength: 100 } # set by beginImplementation; consumed by the verify SoD guard
ccbChairId: { type: string, maxLength: 100 }
ccbChairName: { type: string, maxLength: 120 }
ccbDecision: { type: text }
ccbMeetingDate: { type: date }
implementationPlan: { type: markdown }
verificationMethod: { type: text }
verificationResult: { type: text }
closedAt: { type: datetime }
contractNumber: { type: string, maxLength: 60 }
programName: { type: string, required: true, maxLength: 120 }
classificationLevel: { $ref: '#/enums/ControlMarking', default: cui }
itarControlled: { type: boolean, default: false }
$merge: { $ref: '#/objects/Timestamp' }
indexes:
- { fields: [status] }
- { fields: [programName] }
- { fields: [createdById] }
- { fields: [priority] }
stateMachine:
field: status
initial: draft
states:
draft:
transitions:
submit:
to: submitted
guards: [owner, engineer, admin]
requiredFields: [description, justification, configurationItem]
submitted:
transitions:
assignReviewer:
to: technical_review
guards: [chiefEngineer, programManager, admin]
requiredFields: [leadEngineerId]
reject:
to: rejected
guards: [chiefEngineer, admin]
requiredFields: [rejectionReason]
technical_review:
transitions:
recommendApproval:
to: ccb_review
guard: "field('leadEngineerId') == userId() || hasRole('chiefEngineer')"
requiredFields: [impactAssessment]
requestRevision:
to: draft
guards: [owner, chiefEngineer, admin]
reject:
to: rejected
guards: [chiefEngineer, admin]
requiredFields: [rejectionReason]
ccb_review:
transitions:
approve:
to: approved
# Structural SoD: the CCB chair approves, and cannot be the
# originator or the assigned lead engineer. No admin bypass.
guard: >
hasRole('ccbChair')
&& field('createdById') != userId()
&& field('leadEngineerId') != userId()
requiredFields: [ccbDecision, ccbMeetingDate]
sets:
ccbChairId: "$user.id"
ccbChairName: "$user.username"
defer:
to: deferred
guards: [ccbChair, admin]
reject:
to: rejected
guards: [ccbChair, admin]
requiredFields: [ccbDecision]
deferred:
transitions:
resubmitToCcb:
to: ccb_review
guards: [chiefEngineer, programManager, admin]
approved:
transitions:
beginImplementation:
to: implementing
guards: [leadEngineer, chiefEngineer, admin]
requiredFields: [implementationPlan]
sets:
implementerId: "$user.id"
implementing:
transitions:
completeImplementation:
to: verification
guards: [leadEngineer, chiefEngineer, admin]
requiredFields: [verificationMethod]
verification:
transitions:
verify:
to: closed
# Structural SoD: verifier must be independent of both the
# implementer and the originator. No admin bypass.
guard: >
(hasRole('qualityEngineer') || hasRole('chiefEngineer'))
&& field('implementerId') != userId()
&& field('createdById') != userId()
requiredFields: [verificationResult]
sets:
closedAt: "now()"
failVerification:
to: implementing
guards: [qualityEngineer, admin]
rejected:
final: true
closed:
final: true
validation:
classOneNeedsContract:
rule: "ecpClass != 'class_i' || contractNumber != null"
message: "Class I changes require a contract number for government approval routing"
rejectionNeedsReason:
rule: "status != 'rejected' || rejectionReason != null"
message: "A rejected ECP must record the rejection rationale"
features:
audit: true
versioning: true # full pre-update snapshots
search: true
audit:
exclude: [updatedAt]
history:
events:
created:
on: create
capture: [ecpNumber, title, configurationItem, ecpClass, priority, originatorName, programName]
label: "ECP {ecpNumber} created - {title}"
detail: "CI: {configurationItem}. Class: {ecpClass}. Priority: {priority}. Originator: {originatorName}"
icon: lucide:file-plus
severity: info
submitted:
on: transition
transition: submit
label: "ECP submitted for review"
icon: lucide:send
severity: info
technicalReviewStarted:
on: transition
transition: assignReviewer
capture: [leadEngineerName]
label: "Technical review assigned to {leadEngineerName}"
icon: lucide:user-plus
severity: info
recommendedForCcb:
on: transition
transition: recommendApproval
capture: [impactAssessment, costImpact, scheduleImpactDays]
label: "Recommended for CCB - cost impact {costImpact}, schedule {scheduleImpactDays} days"
icon: lucide:arrow-up-circle
severity: info
ccbApproved:
on: transition
transition: approve
capture: [ccbChairName, ccbDecision, ccbMeetingDate]
label: "CCB APPROVED by {ccbChairName}"
detail: "Decision: {ccbDecision}. Meeting date: {ccbMeetingDate}"
icon: lucide:check-circle
severity: success
ccbRejected:
on: transition
transition: reject
capture: [ccbDecision, rejectionReason]
label: "REJECTED"
detail: "{ccbDecision}"
icon: lucide:x-circle
severity: error
ccbDeferred:
on: transition
transition: defer
label: "Deferred by CCB"
icon: lucide:pause
severity: warning
implementationStarted:
on: transition
transition: beginImplementation
capture: [implementationPlan]
label: "Implementation started"
icon: lucide:hammer
severity: info
implementationComplete:
on: transition
transition: completeImplementation
capture: [verificationMethod]
label: "Implementation complete - verification pending"
detail: "Verification method: {verificationMethod}"
icon: lucide:check
severity: info
verificationPassed:
on: transition
transition: verify
capture: [verificationResult]
label: "Verification PASSED - ECP closed"
detail: "{verificationResult}"
icon: lucide:shield-check
severity: success
verificationFailed:
on: transition
transition: failVerification
label: "Verification FAILED - returned to implementation"
icon: lucide:shield-x
severity: error
emergencyEscalation:
on: fieldChange
field: priority
condition: "priority == 'emergency'"
capture: [ecpNumber, title, priority]
label: "EMERGENCY PRIORITY - {ecpNumber}: {title}"
icon: lucide:alert-octagon
severity: error
classIChange:
on: create
condition: "ecpClass == 'class_i'"
capture: [ecpNumber, title, configurationItem]
label: "CLASS I CHANGE - government approval required"
detail: "ECP {ecpNumber}: {title}. CI: {configurationItem}"
icon: lucide:alert-triangle
severity: warning
roles: [programManager, ccbChair, contractingOfficer, admin]
itarDataInvolved:
on: create
condition: "itarControlled == true"
capture: [ecpNumber, classificationLevel]
label: "ITAR-CONTROLLED DATA - export control applies"
icon: lucide:lock
severity: warning
roles: [exportControlOfficer, securityManager, admin]
specificationChanged:
on: update
fields: [description, impactAssessment, implementationPlan]
capture: [title]
label: "ECP specification updated"
icon: lucide:edit
severity: info
permissions:
list: [authenticated]
get: [authenticated]
create: [engineer, seniorEngineer, chiefEngineer, admin]
update: [engineer, seniorEngineer, chiefEngineer, programManager, qualityEngineer, ccbChair, admin]
delete: [admin]
fields:
ccbDecision: { write: [ccbChair, admin] }
ccbMeetingDate: { write: [ccbChair, admin] }
verificationResult: { write: [qualityEngineer, chiefEngineer, admin] }
classificationLevel: { write: [securityManager, admin] }
itarControlled: { write: [exportControlOfficer, securityManager, admin] }
implementerId: { write: [admin] } # normally set only via the beginImplementation transition
Domain 2: ITAR Access Control (exportcontrol)
domain:
name: exportcontrol
version: "1.0.0"
description: >
ITAR/EAR access authorization lifecycle. The US-person determination is a
controlled enum written only by security roles — not a free-text citizenship
string. Expiration is driven by a tiered schedule, so the 30-day warning and
the expiry transition actually fire.
channels:
email:
provider: smtp
host: ${SMTP_HOST}
port: ${SMTP_PORT:587}
from: "exportcontrol-noreply@example.com"
objects:
Timestamp:
createdAt: { type: datetime, autoNow: create }
updatedAt: { type: datetime, autoNow: update }
enums:
AuthorizationStatus:
values:
requested: { label: "Requested", color: "#3b82f6" }
screening: { label: "Under Screening", color: "#f59e0b" }
approved: { label: "Approved", color: "#10b981" }
denied: { label: "Denied", color: "#ef4444", final: true }
revoked: { label: "Revoked", color: "#64748b", final: true }
expired: { label: "Expired", color: "#94a3b8", final: true }
ControlCategory:
values:
itar_usml: { label: "ITAR - USML" }
ear_ccl: { label: "EAR - CCL" }
cui: { label: "CUI - Controlled Unclassified" }
fouo: { label: "FOUO - For Official Use Only" }
PersonStatus:
values:
us_person: { label: "U.S. Person",
description: "U.S. citizen, lawful permanent resident, or protected individual under 8 U.S.C. 1324b(a)(3)" }
non_us_person: { label: "Non-U.S. Person",
description: "Requires an export license or exemption before access to ITAR-controlled data" }
resources:
Authorization:
description: >
A request to grant one person access to controlled technical data on one
program. Route: /api/v1/exportcontrol/authorizations.
object:
id: { type: uuid, primaryKey: true }
requestNumber: { type: string, required: true, unique: true, immutable: true, maxLength: 40 }
personnelId: { type: uuid, required: true, immutable: true }
personnelName: { type: string, required: true, maxLength: 120 }
# The legal determination, distinct from citizenship. A green-card holder
# is a US person; citizenship alone does not decide ITAR access.
personStatus: { $ref: '#/enums/PersonStatus', required: true }
citizenshipCountry: { type: country, required: true }
clearanceLevel: { type: string, maxLength: 40 }
programName: { type: string, required: true, maxLength: 120 }
controlCategory: { $ref: '#/enums/ControlCategory', required: true }
usmlCategory: { type: string, maxLength: 20 }
status: { $ref: '#/enums/AuthorizationStatus', default: requested }
justification: { type: text, required: true }
technologyControlPlan: { type: text }
screeningResult: { type: text }
denialReason: { type: text }
createdById: { type: string, required: true, immutable: true, maxLength: 100 }
approvedById: { type: string, maxLength: 100 }
approvedByName: { type: string, maxLength: 120 }
approvedAt: { type: datetime }
expirationDate: { type: date }
revocationReason: { type: text }
$merge: { $ref: '#/objects/Timestamp' }
indexes:
- { fields: [status] }
- { fields: [programName] }
- { fields: [personnelId] }
- { fields: [personStatus] }
stateMachine:
field: status
initial: requested
states:
requested:
transitions:
screen:
to: screening
guards: [exportControlOfficer, admin]
screening:
transitions:
approve:
to: approved
# SoD: the approving export control officer cannot be the requester.
guard: "hasRole('exportControlOfficer') && field('createdById') != userId()"
requiredFields: [screeningResult, expirationDate]
sets:
approvedAt: "now()"
approvedById: "$user.id"
approvedByName: "$user.username"
deny:
to: denied
guards: [exportControlOfficer, admin]
requiredFields: [denialReason]
approved:
transitions:
revoke:
to: revoked
guards: [exportControlOfficer, securityManager, admin]
requiredFields: [revocationReason]
expire:
to: expired
# Executed automatically by the accessExpiry schedule (system actor).
# Manual execution restricted to admin.
guards: [admin]
denied:
final: true
revoked:
final: true
expired:
final: true
validation:
nonUsApprovalNeedsTcp:
rule: "status != 'approved' || personStatus != 'non_us_person' || technologyControlPlan != null"
message: "Approving a non-U.S. person requires a Technology Control Plan (license or exemption basis)"
approvalNeedsExpiry:
rule: "status != 'approved' || expirationDate != null"
message: "An approved authorization must carry an expiration date"
features:
audit: true
history:
events:
accessRequested:
on: create
capture: [requestNumber, personnelName, personStatus, citizenshipCountry, programName, controlCategory, justification]
label: "Access requested - {personnelName} ({personStatus})"
detail: "Program: {programName}. Category: {controlCategory}. Justification: {justification}"
icon: lucide:user-plus
severity: info
screeningStarted:
on: transition
transition: screen
label: "Export control screening initiated"
icon: lucide:search
severity: info
accessGranted:
on: transition
transition: approve
capture: [approvedByName, screeningResult, expirationDate]
label: "Access APPROVED by {approvedByName}"
detail: "Screening: {screeningResult}. Expires: {expirationDate}"
icon: lucide:shield-check
severity: success
accessDenied:
on: transition
transition: deny
capture: [denialReason]
label: "Access DENIED"
detail: "{denialReason}"
icon: lucide:shield-x
severity: error
accessRevoked:
on: transition
transition: revoke
capture: [revocationReason]
label: "Access REVOKED"
detail: "{revocationReason}"
icon: lucide:lock
severity: error
accessExpired:
on: transition
transition: expire
label: "Access authorization expired"
icon: lucide:clock
severity: warning
nonUsPersonRequest:
on: create
condition: "personStatus == 'non_us_person'"
capture: [personnelName, citizenshipCountry, controlCategory, programName]
label: "NON-US PERSON ACCESS REQUEST - {personnelName} ({citizenshipCountry})"
detail: "Category: {controlCategory}. Program: {programName}. License or exemption required."
icon: lucide:alert-octagon
severity: error
roles: [exportControlOfficer, securityManager, admin]
permissions:
list: [exportControlOfficer, securityManager, programManager, admin]
get: [exportControlOfficer, securityManager, programManager, admin]
create: [programManager, admin]
update: [exportControlOfficer, securityManager, admin]
delete: [admin]
fields:
personStatus: { write: [exportControlOfficer, securityManager, admin] }
screeningResult: { write: [exportControlOfficer, admin] }
denialReason: { write: [exportControlOfficer, admin] }
approvedById: { write: [admin] } # normally set only via the approve transition
revocationReason: { write: [exportControlOfficer, securityManager, admin] }
clearanceLevel: { write: [securityManager, admin] }
technologyControlPlan: { write: [exportControlOfficer, securityManager, admin] }
# Time-based behavior lives here, not in fieldChange events.
schedules:
accessExpiry:
description: "Warn 30 days before authorization expiry; expire on the date"
type: relative
source:
resource: Authorization
filter: "status == 'approved'"
relativeTo: expirationDate
tiers:
- daysUntil: 30
action: notify
tag: 30day
channels: [email]
recipients: { roles: [exportControlOfficer, securityManager] }
template:
subject: "Access authorization expires in 30 days"
body: "Authorization {requestNumber} for {personnelName} on {programName} expires {expirationDate}."
- daysUntil: 0
action: transition
transition: expire
tag: expire
Domain 3: DO-178C Requirements Traceability (certtrace)
domain:
name: certtrace
version: "1.0.0"
description: >
Bidirectional requirements traceability for DO-178C. Parent traces and test
linkage are real relationships with referential integrity, not free-text IDs
— a typo cannot silently satisfy a trace. Gap detection uses stored computed
fields, so the auditor query is a filtered list, not a log reconstruction.
objects:
Timestamp:
createdAt: { type: datetime, autoNow: create }
updatedAt: { type: datetime, autoNow: update }
enums:
RequirementLevel:
values:
system: { label: "System Requirement" }
hlr: { label: "High-Level Requirement" }
llr: { label: "Low-Level Requirement" }
derived: { label: "Derived Requirement" }
RequirementStatus:
values:
draft: { label: "Draft", color: "#94a3b8" }
baselined: { label: "Baselined", color: "#3b82f6" }
implemented: { label: "Implemented", color: "#f59e0b" }
verified: { label: "Verified", color: "#10b981" }
closed: { label: "Closed", color: "#059669", final: true }
VerificationMethod:
values:
test: { label: "Test" }
analysis: { label: "Analysis" }
inspection: { label: "Inspection" }
review: { label: "Review of Design" }
Dal:
values:
a: { label: "Level A - Catastrophic" }
b: { label: "Level B - Hazardous" }
c: { label: "Level C - Major" }
d: { label: "Level D - Minor" }
e: { label: "Level E - No Effect" }
resources:
Requirement:
object:
id: { type: uuid, primaryKey: true }
reqId: { type: string, required: true, unique: true, immutable: true, maxLength: 40 }
title: { type: string, required: true, maxLength: 200 }
description: { type: markdown, required: true }
level: { $ref: '#/enums/RequirementLevel', required: true }
dal: { $ref: '#/enums/Dal', required: true }
status: { $ref: '#/enums/RequirementStatus', default: draft }
parentId: { type: uuid } # FK — mutable by design: requirements are re-parented during decomposition
sourceDocument: { type: string, maxLength: 120 }
rationale: { type: text }
verificationMethod: { $ref: '#/enums/VerificationMethod' }
sourceCodeRef: { type: string, maxLength: 255 }
implementedById: { type: string, maxLength: 100 } # set by implement; consumed by the verify SoD guard
verifiedById: { type: string, maxLength: 100 }
verifiedByName: { type: string, maxLength: 120 }
verifiedAt: { type: datetime }
programName: { type: string, required: true, maxLength: 120 }
configurationItem: { type: string, required: true, maxLength: 120 }
baselineVersion: { type: string, maxLength: 40 }
$merge: { $ref: '#/objects/Timestamp' }
relationships:
parent: { type: belongsTo, target: Requirement, foreignKey: parentId, onDelete: restrict }
children: { type: hasMany, target: Requirement, foreignKey: parentId }
testCases:
type: belongsToMany
target: TestCase
through: RequirementTestCase
foreignKey: requirementId
otherKey: testCaseId
indexes:
- { fields: [parentId] }
- { fields: [status] }
- { fields: [level] }
- { fields: [programName] }
computed:
# Stored so they are filterable: the auditor gap query is a list filter.
# A system requirement legitimately has no parent; a derived requirement
# by definition lacks an upward trace (DO-178C 5.2.1) and is handled by
# the derivedRequirementCreated event instead of a gap flag.
hasTraceUp:
type: boolean
formula: "level == 'system' || level == 'derived' || parentId != null"
stored: true
updateOn: [parentId, level]
hasTraceDown:
type: boolean
formula: "sourceCodeRef != null && sourceCodeRef != ''"
stored: true
updateOn: [sourceCodeRef]
testCaseCount:
type: integer
formula: "count(testCases)"
stored: true
updateOn: [testCases.create, testCases.update, testCases.delete]
stateMachine:
field: status
initial: draft
states:
draft:
transitions:
baseline:
to: baselined
guards: [systemsEngineer, chiefEngineer, admin]
requiredFields: [description, level, dal, baselineVersion]
baselined:
transitions:
implement:
to: implemented
guards: [softwareEngineer, admin]
requiredFields: [sourceCodeRef]
sets:
implementedById: "$user.id"
revise:
to: draft
guards: [systemsEngineer, admin]
implemented:
transitions:
verify:
to: verified
# Structural SoD: the verifier cannot be the implementer. No admin bypass.
guard: "hasRole('verificationEngineer') && field('implementedById') != userId()"
requiredFields: [verificationMethod]
sets:
verifiedAt: "now()"
verifiedById: "$user.id"
verifiedByName: "$user.username"
revise:
to: draft
guards: [systemsEngineer, chiefEngineer, admin]
verified:
transitions:
close:
to: closed
guards: [chiefEngineer, certificationLiaison, admin]
failVerification:
to: implemented
guards: [verificationEngineer, admin]
closed:
final: true
validation:
testMethodNeedsTests:
rule: "status != 'verified' || verificationMethod != 'test' || testCaseCount > 0"
message: "Verification by test requires at least one linked test case"
derivedNeedsRationale:
rule: "level != 'derived' || rationale != null"
message: "Derived requirements must record a rationale for the system safety assessment (DO-178C 5.2.1)"
features:
audit: true
versioning: true
history:
events:
created:
on: create
capture: [reqId, title, level, dal, programName, configurationItem]
label: "Requirement {reqId} created - {title}"
detail: "Level: {level}. DAL: {dal}. CI: {configurationItem}"
icon: lucide:file-plus
severity: info
baselined:
on: transition
transition: baseline
capture: [reqId, baselineVersion]
label: "Requirement {reqId} baselined"
detail: "Baseline: {baselineVersion}"
icon: lucide:bookmark
severity: info
implemented:
on: transition
transition: implement
capture: [reqId, sourceCodeRef]
label: "Implemented - {sourceCodeRef}"
icon: lucide:code
severity: info
verified:
on: transition
transition: verify
capture: [reqId, verificationMethod, verifiedByName]
label: "Verified by {verifiedByName} via {verificationMethod}"
icon: lucide:check-circle
severity: success
verificationFailed:
on: transition
transition: failVerification
label: "Verification FAILED - returned for rework"
icon: lucide:x-circle
severity: error
closed:
on: transition
transition: close
capture: [reqId]
label: "Requirement {reqId} closed"
icon: lucide:lock
severity: success
specificationChanged:
on: update
fields: [description, rationale]
capture: [reqId, title]
label: "Requirement {reqId} specification updated"
icon: lucide:edit
severity: warning
traceabilityGap:
# Legitimate fieldChange: status genuinely changes to 'implemented'.
on: fieldChange
field: status
condition: "status == 'implemented' && (hasTraceUp == false || hasTraceDown == false)"
capture: [reqId, hasTraceUp, hasTraceDown]
label: "TRACEABILITY GAP - {reqId}"
detail: "Trace up: {hasTraceUp}. Trace down: {hasTraceDown}. DO-178C requires bidirectional traceability."
icon: lucide:alert-octagon
severity: error
roles: [certificationLiaison, qualityEngineer, chiefEngineer, admin]
derivedRequirementCreated:
on: create
condition: "level == 'derived'"
capture: [reqId, title, rationale]
label: "DERIVED REQUIREMENT - {reqId}: {title}"
detail: "Rationale: {rationale}. DO-178C 5.2.1 requires derived requirements be provided to the system safety assessment."
icon: lucide:alert-triangle
severity: warning
roles: [systemsEngineer, certificationLiaison, admin]
dalARequirement:
on: create
condition: "dal == 'a'"
capture: [reqId, title, configurationItem]
label: "DAL A REQUIREMENT - {reqId}: {title}"
detail: "CI: {configurationItem}. Maximum verification rigor required. Independent verification mandatory."
icon: lucide:shield
severity: warning
roles: [certificationLiaison, chiefEngineer, qualityEngineer, admin]
permissions:
list: [authenticated]
get: [authenticated]
create: [systemsEngineer, softwareEngineer, chiefEngineer, admin]
update: [systemsEngineer, softwareEngineer, verificationEngineer, chiefEngineer, certificationLiaison, admin]
delete: [admin]
fields:
dal: { write: [systemsEngineer, chiefEngineer, admin] }
verificationMethod: { write: [verificationEngineer, chiefEngineer, admin] }
baselineVersion: { write: [chiefEngineer, certificationLiaison, admin] }
sourceCodeRef: { write: [softwareEngineer, admin] }
implementedById: { write: [admin] } # normally set only via the implement transition
TestCase:
description: >
A verification test case. Linked to requirements through the
RequirementTestCase junction — link/unlink via the relationship endpoints.
object:
id: { type: uuid, primaryKey: true }
testId: { type: string, required: true, unique: true, immutable: true, maxLength: 40 }
title: { type: string, required: true, maxLength: 200 }
procedure: { type: markdown, required: true }
expected: { type: text, required: true }
lastResult: { type: string, enum: [pass, fail, blocked, not_run], default: not_run }
lastRunAt: { type: datetime }
programName: { type: string, required: true, maxLength: 120 }
$merge: { $ref: '#/objects/Timestamp' }
relationships:
requirements:
type: belongsToMany
target: Requirement
through: RequirementTestCase
foreignKey: testCaseId
otherKey: requirementId
indexes:
- { fields: [programName] }
- { fields: [lastResult] }
features:
audit: true
permissions:
list: [authenticated]
get: [authenticated]
create: [verificationEngineer, softwareEngineer, admin]
update: [verificationEngineer, admin]
delete: [admin]
Domain 4: CMMC Compliance Tracking (cmmc)
domain:
name: cmmc
version: "1.0.0"
description: >
NIST SP 800-171 control assessment with POA&M tracking. Sheet mode enables
assessment-specific evidence columns. Overdue POA&Ms and review reminders
are driven by schedules — a due date passing is not a field change and
cannot be detected by fieldChange events.
channels:
email:
provider: smtp
host: ${SMTP_HOST}
port: ${SMTP_PORT:587}
from: "cmmc-noreply@example.com"
objects:
Timestamp:
createdAt: { type: datetime, autoNow: create }
updatedAt: { type: datetime, autoNow: update }
enums:
ControlStatus:
values:
not_assessed: { label: "Not Assessed", color: "#94a3b8" }
under_assessment: { label: "Under Assessment", color: "#3b82f6" }
compliant: { label: "Compliant", color: "#10b981" }
non_compliant: { label: "Non-Compliant", color: "#ef4444" }
partially_compliant: { label: "Partially Compliant", color: "#f59e0b" }
ImplementationStatus:
values:
implemented: { label: "Implemented" }
partially_implemented: { label: "Partially Implemented" }
planned: { label: "Planned" }
not_applicable: { label: "Not Applicable" }
RiskLevel:
values: [low, moderate, high, critical]
resources:
Assessment:
mode: sheet
description: >
An assessment of one NIST SP 800-171 control. Dynamic columns hold
assessment-cycle-specific evidence links and notes.
object:
id: { type: uuid, primaryKey: true }
controlId: { type: string, required: true, unique: true, immutable: true, maxLength: 20 }
controlFamily: { type: string, required: true, maxLength: 60 }
controlTitle: { type: string, required: true, maxLength: 200 }
cmmcLevel: { type: integer, required: true, min: 1, max: 3 }
status: { $ref: '#/enums/ControlStatus', default: not_assessed }
implementationStatus: { $ref: '#/enums/ImplementationStatus' }
implementationDescription: { type: text }
evidenceLinks: { type: json }
assessorId: { type: string, maxLength: 100 }
assessorName: { type: string, maxLength: 120 }
assessmentDate: { type: date }
nextReviewDate: { type: date }
poamRequired: { type: boolean, default: false }
poamDescription: { type: text }
poamDueDate: { type: date }
riskLevel: { $ref: '#/enums/RiskLevel' }
sprsScore: { type: integer, min: -203, max: 110 }
$merge: { $ref: '#/objects/Timestamp' }
indexes:
- { fields: [status] }
- { fields: [controlFamily] }
- { fields: [poamDueDate] }
- { fields: [nextReviewDate] }
dynamicFields:
enabled: true
allowTypes: [string, text, date, boolean]
maxColumns: 30
permissions:
addColumn: [ciso, assessor, admin]
deleteColumn: [admin]
stateMachine:
field: status
initial: not_assessed
states:
not_assessed:
transitions:
assess:
to: under_assessment
guards: [assessor, ciso, admin]
sets:
assessorId: "$user.id"
assessorName: "$user.username"
under_assessment:
transitions:
markCompliant:
to: compliant
guards: [assessor, ciso, admin]
requiredFields: [implementationDescription, evidenceLinks]
sets:
poamRequired: false
markNonCompliant:
to: non_compliant
guards: [assessor, ciso, admin]
requiredFields: [implementationDescription]
markPartiallyCompliant:
to: partially_compliant
guards: [assessor, ciso, admin]
requiredFields: [poamDescription, poamDueDate]
sets:
poamRequired: true
compliant:
transitions:
reassess:
to: under_assessment
guards: [assessor, ciso, admin]
non_compliant:
transitions:
remediate:
to: under_assessment
guards: [assessor, itSecurity, admin]
partially_compliant:
transitions:
closePoam:
to: compliant
guards: [assessor, ciso, admin]
requiredFields: [implementationDescription, evidenceLinks]
sets:
poamRequired: false
reassess:
to: under_assessment
guards: [assessor, ciso, admin]
validation:
compliantNeedsReviewDate:
rule: "status != 'compliant' || nextReviewDate != null"
message: "A compliant control must schedule its next review"
features:
audit: true
history:
events:
assessmentStarted:
on: transition
transition: assess
capture: [controlId, controlTitle, assessorName]
label: "{controlId} - assessment started by {assessorName}"
icon: lucide:clipboard-check
severity: info
foundCompliant:
on: transition
transition: markCompliant
capture: [controlId, controlTitle, assessorName]
label: "{controlId} - COMPLIANT"
icon: lucide:check-circle
severity: success
foundNonCompliant:
on: transition
transition: markNonCompliant
capture: [controlId, controlTitle, implementationDescription]
label: "{controlId} - NON-COMPLIANT"
detail: "{implementationDescription}"
icon: lucide:x-circle
severity: error
poamCreated:
on: transition
transition: markPartiallyCompliant
capture: [controlId, poamDescription, poamDueDate]
label: "{controlId} - POA&M created"
detail: "{poamDescription}. Due: {poamDueDate}"
icon: lucide:alert-triangle
severity: warning
poamClosed:
on: transition
transition: closePoam
capture: [controlId, controlTitle]
label: "{controlId} - POA&M closed, now compliant"
icon: lucide:check-circle
severity: success
permissions:
list: [assessor, itSecurity, ciso, admin]
get: [assessor, itSecurity, ciso, admin]
create: [ciso, admin]
update: [assessor, itSecurity, ciso, admin]
delete: [admin]
fields:
sprsScore: { write: [ciso, admin] }
riskLevel: { write: [assessor, ciso, admin] }
schedules:
poamEscalation:
description: "Warn 14 days before a POA&M due date; escalate when overdue"
type: relative
source:
resource: Assessment
filter: "status == 'partially_compliant'"
relativeTo: poamDueDate
tiers:
- daysUntil: 14
action: notify
tag: 14day
channels: [email]
recipients: { roles: [assessor, itSecurity] }
template:
subject: "POA&M due in 14 days - {controlId}"
body: "{poamDescription}. Due: {poamDueDate}."
- daysUntil: 0
action: notify
tag: overdue
channels: [email]
recipients: { roles: [ciso, assessor, itSecurity] }
template:
subject: "POA&M OVERDUE - {controlId}"
body: "{poamDescription}. Was due: {poamDueDate}."
reviewReminder:
description: "Remind 30 days before a compliant control's review date"
type: relative
source:
resource: Assessment
filter: "status == 'compliant'"
relativeTo: nextReviewDate
tiers:
- daysUntil: 30
action: notify
tag: 30day
channels: [email]
recipients: { roles: [assessor, ciso] }
template:
subject: "Control review due in 30 days - {controlId}"
body: "Next review: {nextReviewDate}."
Auditor queries
These queries use the documented /api/v1/ prefix, id-based paths, and
supported history filters:
Configuration audit: complete ECP lifecycle
# Resolve the business key to the record id, then fetch its timeline
curl -s "$BASE/api/v1/changemgmt/proposals?filter[ecpNumber]=ECP-2026-0047" \
-H "Authorization: Bearer $TOKEN" | jq -r '.data.items[0].id'
curl -s "$BASE/api/v1/changemgmt/proposals/{id}/history" \
-H "Authorization: Bearer $TOKEN"
ITAR audit: non-US person access on a program
# Resource-level filters (programName is not a history query param)
curl -s "$BASE/api/v1/exportcontrol/authorizations?filter[programName]=MERIDIAN&filter[personStatus]=non_us_person" \
-H "Authorization: Bearer $TOKEN"
# Cross-record event stream for the flagged requests
curl -s "$BASE/api/v1/exportcontrol/authorizations/history?event=nonUsPersonRequest" \
-H "Authorization: Bearer $TOKEN"
DO-178C audit: traceability gaps
# Stored computed fields are directly filterable — no log reconstruction
curl -s "$BASE/api/v1/certtrace/requirements?filter[status]=implemented&filter[hasTraceUp]=false" \
-H "Authorization: Bearer $TOKEN"
curl -s "$BASE/api/v1/certtrace/requirements?filter[status]=implemented&filter[hasTraceDown]=false" \
-H "Authorization: Bearer $TOKEN"
CMMC audit: POA&M status
# Open POA&Ms by due date
curl -s "$BASE/api/v1/cmmc/assessments?filter[status]=partially_compliant&sort=poamDueDate" \
-H "Authorization: Bearer $TOKEN"
# Evidence that the overdue detection ran (scheduler execution log)
curl -s "$BASE/api/v1/cmmc/schedules/poamEscalation/log?since=2025-11-01" \
-H "Authorization: Bearer $TOKEN"
# POA&Ms closed since the last assessment
curl -s "$BASE/api/v1/cmmc/assessments/history?event=poamClosed&after=2025-11-01" \
-H "Authorization: Bearer $TOKEN"