CML — the sixth tab
A lossy export today. The parking tray is the honest part.Context Mapper’s CML is a validated text model with a real generator pipeline behind it, and it is the closest thing to a source of truth this board has. It is also missing roughly half of what an event storming board holds: policies, read models, hotspots, phases, geometry, threads, the glossary. So the tab follows the §16 rule — generate, don’t duplicate, park what doesn’t map — and the tray is deliberately the loudest thing on the screen.
Valid CML. Half the board is missing from it, by design.
ContextMap VendorOnboardingChange {
type = SYSTEM_LANDSCAPE
state = AS_IS
contains IntakeAndTriage, RiskAndCompliance, Finance, Scheduling, VendorMasterData, ChangeExecution, ServiceNow
Scheduling -> ChangeExecution {
}
ChangeExecution -> IntakeAndTriage {
}
RiskAndCompliance [U,S]->[D,C] Finance {
implementationTechnology = "REST · POST /budget-reservations"
downstreamRights = INFLUENCER
exposedAggregates = RiskAssessment
}
Finance -> RiskAndCompliance {
}
RiskAndCompliance [U,OHS,PL]->[D] Scheduling {
implementationTechnology = "Kafka topic · change.approved.v2"
downstreamRights = VETO_RIGHT
exposedAggregates = ChangeRequest, RiskRating
}
Scheduling -> VendorMasterData {
}
VendorMasterData -> ChangeExecution {
}
ChangeExecution -> IntakeAndTriage {
}
ChangeExecution -> Scheduling {
}
IntakeAndTriage -> ChangeExecution {
}
ServiceNow -> IntakeAndTriage {
}
RiskAndCompliance -> Finance {
}
}
Domain VendorOnboardingChangeDomain {
Subdomain IntakeAndTriageSubdomain {
type = SUPPORTING_DOMAIN
}
Subdomain RiskAndComplianceSubdomain {
type = CORE_DOMAIN
}
Subdomain FinanceSubdomain {
type = SUPPORTING_DOMAIN
}
Subdomain SchedulingSubdomain {
type = GENERIC_SUBDOMAIN
}
Subdomain VendorMasterDataSubdomain {
type = GENERIC_SUBDOMAIN
}
Subdomain ChangeExecutionSubdomain {
type = SUPPORTING_DOMAIN
}
}
BoundedContext IntakeAndTriage implements IntakeAndTriageSubdomain {
domainVisionStatement = "Take a change request in through either channel and decide whether it is worth assessing."
businessModel = "costReduction"
evolution = PRODUCT_RENTAL
responsibilities = "gatewayContext"
Aggregate ChangeRequest {
Entity ChangeRequest {
aggregateRoot
}
Command SubmitChangeRequest
Command TriageRequest
Command CloseChangeRequest
DomainEvent ChangeRequestSubmitted
DomainEvent RequestAcceptedForAssessment
DomainEvent ChangeRequestClosed
}
}
Stakeholders of IntakeAndTriage {
Stakeholder RequestingManager {
influence = MEDIUM
interest = HIGH
}
Stakeholder ServiceDesk {
influence = LOW
interest = MEDIUM
}
}
BoundedContext RiskAndCompliance implements RiskAndComplianceSubdomain {
domainVisionStatement = "Decide whether a proposed change may proceed, and record why. Owns risk rating, security review and CAB routing for every change request; owns nothing about scheduling or vendor data."
businessModel = "compliance"
evolution = CUSTOM_BUILT
responsibilities = "analysisContext"
Aggregate RiskAssessment {
Entity RiskAssessment {
aggregateRoot
}
Command AssessVendorRisk
Command RequestSecurityReview
Command ApproveChange
DomainEvent RiskRatingAssigned
DomainEvent SecurityReviewPassed
DomainEvent ChangeApprovedByCAB
}
Application {
Event EmergencyChangeRoutedAsAStandardChange
}
}
Stakeholders of RiskAndCompliance {
Stakeholder RiskAnalyst {
influence = MEDIUM
interest = HIGH
}
Stakeholder CABChair {
influence = HIGH
interest = HIGH
}
}
BoundedContext Finance implements FinanceSubdomain {
domainVisionStatement = "Reserve and release the money a change needs."
businessModel = "costReduction"
evolution = COMMODITY
responsibilities = "executionContext"
Application {
Command ReserveBudget
Command ReRunCreditCheck
Event BudgetReserved
Event FinanceReChecksTheBudget
}
}
Stakeholders of Finance {
Stakeholder FinancePartner {
influence = MEDIUM
interest = MEDIUM
}
}
BoundedContext Scheduling implements SchedulingSubdomain {
domainVisionStatement = "Find a window that collides with nothing else."
evolution = COMMODITY
responsibilities = "executionContext"
Aggregate ChangeWindow {
Entity ChangeWindow {
aggregateRoot
}
Command ScheduleChangeWindow
Command ImplementChange
DomainEvent WindowScheduled
DomainEvent ChangeImplementedInProduction
}
}
Stakeholders of Scheduling {
Stakeholder ChangeManager {
influence = HIGH
interest = HIGH
}
}
BoundedContext VendorMasterData implements VendorMasterDataSubdomain {
domainVisionStatement = "Hold the one vendor record everything else refers to."
evolution = PRODUCT_RENTAL
responsibilities = "executionContext"
Aggregate Vendor {
Entity Vendor {
aggregateRoot
}
Command CreateVendorRecord
Command ActivateVendor
DomainEvent VendorRecordCreated
DomainEvent VendorActivatedInMasterData
}
}
Stakeholders of VendorMasterData {
Stakeholder MDMSteward {
influence = LOW
interest = HIGH
}
}
BoundedContext ChangeExecution implements ChangeExecutionSubdomain {
domainVisionStatement = "Carry the change out and prove that it landed."
evolution = CUSTOM_BUILT
responsibilities = "executionContext"
}
Stakeholders of ChangeExecution {
Stakeholder PlatformEngineer {
}
}
BoundedContext ServiceNow {
}
Parking tray
- POLICIES
- 4
- READ MODELS
- 6
- HOTSPOTS / QUESTIONS
- 6
- ASSUMED STICKIES
- 3
- UNKNOWN SPANS
- 2
- PHASES · TIMEBOXES
- 4
- GLOSSARY TERMS
- 4
- THREADS · FACILITATOR
- 2
- ALL GEOMETRY
- —
- NAME COLLIDES IN CML
- 0
- NOT ITEMISED
- 7
The tray is not a warning to dismiss. It is the list of things a reader of the CML file will not know, and it prints with the export.
- Export, not round trip The tab is one-way and read-only. Nothing typed in CML comes back, so there is still one source of truth and §16’s promise holds.
- What it buys A diffable, git-native artifact for the change pack, plus everything downstream of CML: PlantUML, MDSL service contracts, the generated map.
- Open — the store The intent is that CML becomes where the board lives between sessions. That cannot happen on plain CML; it needs the extended dialect above, owned and versioned by us. Decide that before building the L1 change pack on top of it.