ArchiMate Layers as Executable Architecture:
Connecting Motivation to Process via pkg/ea, pkg/ifml, and pkg/integration
Enterprise architecture models are traditionally documentation artifacts: PowerPoint slides, Archi exports, PDF reports. They describe the enterprise accurately but cannot be executed. The gap between an ArchiMate diagram and a running process is bridged by hand, imperfectly, at the cost of months of integration work. By the time the process is live, the diagram is stale.
Priostack eliminates this gap. Every ArchiMate 4.0 layer — Motivation,
Strategy, Business, Application, Technology, and Implementation &
Migration — has a corresponding Go type in pkg/ea that carries
both its structural metadata and a ToPetriFragment()
method. IFML application interfaces compile to execution nets via
pkg/ifml.BuildIFMLNet. EIP channels connect the resulting net
fragments via pkg/integration. The same ArchiMate model you
view in Archi is the model the engine runs.
This article is a complete technical walkthrough of that integration, using
the loan origination domain from examples/e2e/models/ea_model.archimate
as the running example throughout.
Contents
- The six ArchiMate layers and their Go counterparts
- The dependency rule: why pkg/ea imports nothing
- Motivation layer: Drivers as stimuli, Goals as SLA sinks, Constraints as blockers
- Strategy layer: CourseOfAction and ValueStream as plan nets
- Business layer: BusinessObject URIs, BusinessService as EIP endpoint anchor
- Application layer: ApplicationComponent, ApplicationInterface, and IFML models
- The IFML bridge: from ViewContainer to BPMN process fire
- Technology layer: TechComponent and TechService as infrastructure fragments
- Migration layer: Plateau and WorkPackage as timed execution roadmaps
- Vertical integration: the complete spine from Motivation to Technology
- End-to-end walkthrough: loan origination in the ArchiMate model
- Data tracing: ea.DataObject → pkg/items.DataItem → GeomTrace
1. The six ArchiMate layers and their Go counterparts
ArchiMate 4.0 organises an enterprise into six layers. Each layer answers
a different question about the enterprise. In pkg/ea, each
layer is a set of Go types that carry the layer's metadata and
compile to Petri net fragments when execution is needed.
The complete ArchiMate Registry in pkg/ea stores all six layers
in a single thread-safe structure. An enterprise architecture team maintains
one Registry; the process engine, the integration layer, and the UI layer all
read from it.
2. The dependency rule: why pkg/ea imports nothing
The architecture of pkg/ea follows a strict rule:
pkg/ea imports nothing from qubit-core except
pkg/core (which itself imports only the standard library).
This means every other package can import pkg/ea; no circular
dependencies are possible. The import graph is a directed acyclic graph (DAG)
that flows in one direction only:
The consequence is that you can load, validate, and test an
ea.Registry in complete isolation — no BPM engine, no
integration bus, no database. This is architecturally correct: the
enterprise model is a fact base that does not depend on how it is executed.
pkg/ea imports pkg/core only to return
*core.PetriFragment from ToPetriFragment() methods.
It never imports pkg/bpm because the BPM engine owns process
definitions; the EA model owns business concepts. The mapping between them
is expressed by ID references (strings), not by type dependencies.
3. Motivation layer: Drivers as stimuli, Goals as SLA sinks, Constraints as blockers
The Motivation layer is unusual among ArchiMate layers because it deals in intents rather than structures. Priostack makes these intents executable by compiling them to specific Petri net elements that have well-defined operational semantics.
Driver → entry place (stimulus injection)
driver := &ea.Driver{
ID: "an-regulatory_pressure",
Name: "Regulatory Compliance Pressure",
// GDPR, AML, KYC requirements driving process automation
}
// Compiles to: one entry place p_driver_an-regulatory_pressure
// Token type: "motivation:driver"
// An external event feed injects a token when the regulation activates;
// the engine can then enable all transitions guarded by this driver.
frag := driver.ToPetriFragment()
// frag.EntryPlaces = ["p_driver_an-regulatory_pressure"]
In the loan origination example, two drivers are declared:
an-customer_experience (applicants expect real-time decisions)
and an-regulatory_pressure (GDPR/AML/KYC compliance). Both
are permanently active in the To-Be plateau — no token injection needed
after initial setup.
Goal → sink place with optional SLA timer
goal := &ea.Goal{
ID: "an-approve_90pct_within_48h",
Name: "Approve 90% of clean applications within 48 hours",
// TargetPlaceID links to the BPMN process's notification-complete place
TargetPlaceID: "p_notify_applicant_done",
SLADeadlineMS: 172_800_000, // 48 hours in milliseconds
}
// Compiles to:
// p_goal_an-approve_90pct_within_48h_achieved (sink — goal met)
// p_goal_an-approve_90pct_within_48h_violated (sink — SLA breached)
// The BPM engine wires: TargetPlaceID → t_sla_ → achieved/violated
// based on timestamp difference when the target place is first marked.
Constraint → inhibitor place (blocks transitions when active)
constraint := &ea.Constraint{
ID: "an-identity_verification_mandatory",
Name: "Identity Verification Mandatory",
// Process cannot proceed to underwriting unless identity is confirmed
}
// Compiles to:
// p_constraint_an-identity_verification_mandatory (inhibitor place)
// When this place is EMPTY the inhibitor arc blocks all underwriting transitions.
// A token is placed here only after identity validation succeeds.
// This is how a compliance rule becomes a structural execution guarantee.
Principle → FEEL guard expression
Unlike Drivers, Goals, and Constraints, a Principle has no
Petri fragment. It compiles to a FEEL guard expression
that is stored in pn.ArcGuards for any arc that the compiler
associates with the principle.
principle := &ea.Principle{
ID: "an-max_loan_guideline",
Name: "Maximum Loan Cap Principle",
Statement: "No loan exceeds 500 000 currency units",
FEELGuard: "loanAmount <= 500000",
}
// At compile time, any transition whose handler references this principle
// is annotated with the FEEL guard. The engine evaluates it before firing.
4. Strategy layer: CourseOfAction and ValueStream as plan nets
The Strategy layer bridges the gap between the why (Motivation) and the what (Business). It answers: "Given our goals and constraints, what ordered set of capabilities must we exercise?"
CourseOfAction → linear plan net
coa := &ea.CourseOfAction{
ID: "an-accelerate_digital_lending",
Name: "Accelerate Digital Lending",
// Three-step plan: IFML portal → real-time ML scoring → BPMN STP
CapabilityIDs: []string{
"an-loan_origination", // step 1
"an-credit_assessment", // step 2
"an-compliance", // step 3
},
}
// Compiles to:
// p_coa_start → t_coa_cap0 → p_coa_0 → t_coa_cap1 → p_coa_1 → t_coa_cap2 → p_coa_end
// Each transition handler is the capability ID. The BPM engine
// dispatches the capability to its realising BusinessService.
frag := coa.ToPetriFragment()
ValueStream → staged pipeline
vs := &ea.ValueStream{
ID: "an-loan_origination_vs",
Name: "Loan Origination Value Stream",
Stages: []ea.ValueStreamStage{
{ID: "vs-1", Name: "Application Receipt", CapabilityID: "an-loan_origination"},
{ID: "vs-2", Name: "Credit Assessment", CapabilityID: "an-credit_assessment"},
{ID: "vs-3", Name: "Fraud Detection", CapabilityID: "an-compliance"},
{ID: "vs-4", Name: "Decision & Disbursement", CapabilityID: "an-loan_origination"},
},
}
// Compiles to a 4-stage pipeline net:
// p_vs_stage0 → t_vs_cap0 → p_vs_stage1 → … → p_vs_end
// Stage completion places fire EIP MessageEndpoint outbound events.
A ValueStream stage completion place is the natural anchor for connecting
to an EIP MessageEndpoint. When the "Credit Assessment" stage
place is marked, the integration layer can fire a message to the credit
bureau API without any manual wiring.
5. Business layer: BusinessObject URIs, BusinessService as EIP anchor
The Business layer is the heart of the ArchiMate model. It describes the
domain concepts (BusinessObject), the people who act
(BusinessRole), the capabilities the enterprise has
(BusinessCapability), the services it offers
(BusinessService), and the processes and events that
orchestrate work.
BusinessObject → pkg/items.ItemDefinition.ImportRef
A BusinessObject is a structural concept — it defines the
schema of a domain entity without holding runtime state. The connection to
live execution happens through pkg/items.ItemDefinition.ImportRef:
the process data schema references the business concept by URI.
// Define the business concept
loanApp := &ea.BusinessObject{
ID: "an-loan_application",
Name: "Loan Application",
Properties: map[string]ea.PropertyDef{
"applicantName": {TypeRef: "xs:string", Required: true},
"loanAmount": {TypeRef: "xs:decimal", Required: true},
"submittedAt": {TypeRef: "xs:dateTime"},
},
}
// loanApp.URI() → "ea://an-loan_application"
// Define the process data item referencing the business concept
loanAppDef := &items.ItemDefinition{
ID: "def-loan-application",
Name: "Loan Application Data",
ImportRef: loanApp.URI(), // "ea://an-loan_application"
}
// Now any process DataObject or Message carrying this ItemDefinition is
// typed to the "Loan Application" business concept.
// The ea.Registry can resolve "ea://an-loan_application" back to the
// BusinessObject for schema validation at runtime.
BusinessService → integration.MessageEndpoint.ServiceRef
A BusinessService is the named capability the enterprise
exposes. In the EIP integration layer, MessageEndpoint.ServiceRef
stores the BusinessService.ID. This is the binding point that
connects the business vocabulary to the integration infrastructure:
// Business layer: declare the service
fraudSvc := &ea.BusinessService{
ID: "an-fraud_detection_svc",
Name: "Fraud Detection Service",
CapabilityIDs: []string{"an-compliance"},
}
// Integration layer: the endpoint that serves the business service
ep := &integration.MessageEndpoint{
ID: "ep-fraud-inbound",
Name: "Fraud Detection Inbound",
ChannelID: "ch-fraud-requests",
Direction: integration.EndpointInbound,
ServiceRef: fraudSvc.ID, // "an-fraud_detection_svc"
}
// Now: reg.EndpointsForService("an-fraud_detection_svc") returns [ep-fraud-inbound]
// This call is used by the service mesh to route inbound messages to the
// correct BPMN process (via the business service → capability → process mapping).
BusinessEvent → channel publication trigger
// Business events correspond to messages on pub-sub channels
evtRiskAssessed := &ea.BusinessEvent{
ID: "an-evt_risk_assessed",
Name: "Risk Assessment Completed",
}
// Mapped to: ch-risk-assessment-results (pub-sub channel)
// When a BPMN task completes and the risk assessment result is produced,
// the engine publishes a message to this channel.
// All subscribers (fraud detection pipeline, notification service, audit logger)
// receive it simultaneously via ChannelPubSub semantics.
6. Application layer: ApplicationComponent, ApplicationInterface, and IFML models
The Application layer is where the software that realises business services
lives. In Priostack, each ApplicationComponent is a
deployable unit that exposes and consumes services through
ApplicationInterface objects. The key design decision
(called "Option B" in pkg/ea/application.go) is that one
component can expose multiple interfaces, and each interface independently
backs either an IFML UI surface or a REST/gRPC endpoint.
// The Loan Application Portal component
portal := &ea.ApplicationComponent{
ID: "an-loan_portal",
Name: "Loan Application Portal",
// Links this component to the EIP integration layer
EIPEndpointRef: "ep-portal-inbound",
Interfaces: []ea.ApplicationInterface{
{
ID: "ai-portal-ui",
Name: "Application Form UI",
ComponentID: "an-loan_portal",
Direction: ea.AppInterfaceProvided,
// This interface is realised by an IFML model (the form and
// navigation flows for submitting a loan application)
IFMLModelRef: "ifml-loan-submission",
ServiceRef: "an-loan_submission_svc",
},
{
ID: "ai-portal-api",
Name: "Submission REST API",
ComponentID: "an-loan_portal",
Direction: ea.AppInterfaceProvided,
EndpointRef: "https://api.priostack.com/v1/loans",
ServiceRef: "an-loan_submission_svc",
},
},
}
// ToPetriFragment assembles the component by merging all interface fragments:
// - Provided interface ai-portal-ui → entry FIFO place (token type "ui:ifml-loan-submission")
// - Provided interface ai-portal-api → entry FIFO place (token type "app:interface")
frag := portal.ToPetriFragment()
// frag.EntryPlaces = ["p_ai_ai-portal-ui_buf", "p_ai_ai-portal-api_buf"]
The EIPEndpointRef field creates the binding to the EIP
integration layer. When the portal's entry FIFO place receives a token
(a loan submission message), the engine looks up the EIP endpoint and
routes the message through the registered pipeline.
7. The IFML bridge: from ViewContainer to BPMN process fire
IFML (Interaction Flow Modeling Language) is the OMG standard for
describing UI behaviour. In Priostack, an IFML model lives inside an
ApplicationInterface.IFMLModelRef and is compiled to an
executable Petri net by pkg/ifml.BuildIFMLNet.
The IFML model for loan submission
model := &ifml.IFMLModel{
ID: "ifml-loan-submission",
Name: "Loan Submission UI",
ComponentID: "an-loan_portal", // links back to ea.ApplicationComponent
Containers: []ifml.ViewContainer{
{
ID: "vc-home",
Name: "Home Screen",
Kind: ifml.Window,
IsDefault: true, // initial token goes here
Elements: []ifml.ViewElement{
{ID: "ve-summary", Name: "Product Summary", Kind: ifml.ViewDetail},
},
Actions: []ifml.Action{
{
ID: "act-start-application",
Name: "Start Application",
// No backend call here — just a navigation
},
},
},
{
ID: "vc-application-form",
Name: "Application Form",
Kind: ifml.Panel,
Elements: []ifml.ViewElement{
{
ID: "ve-loan-form",
Name: "Loan Application Form",
Kind: ifml.ViewForm,
DataObjectRef: "an-loan_form_data", // ea.DataObject.ID
},
},
Actions: []ifml.Action{
{
ID: "act-submit",
Name: "Submit Application",
// This Action fires the BPMN loan approval process
BackendRef: ifml.BPMNRef("loan_approval_bpmn"),
DataObjectRef: "an-loan_form_data",
},
},
},
{
ID: "vc-confirmation",
Name: "Confirmation Screen",
Kind: ifml.Window,
},
},
Flows: []ifml.NavigationFlow{
{
ID: "nf-home-to-form",
SourceID: "vc-home",
ActionRef: "act-start-application",
TargetID: "vc-application-form",
},
{
ID: "nf-form-to-confirm",
SourceID: "vc-application-form",
ActionRef: "act-submit",
TargetID: "vc-confirmation",
// FEEL guard: only navigate to confirmation if submission succeeded
Condition: "submissionStatus == \"accepted\"",
},
},
DataFlows: []ifml.DataFlow{
{
ID: "df-form-to-submit",
SourceViewID: "vc-application-form",
TargetActionID: "vc-application-form_act-submit",
DataObjectRef: "an-loan_form_data",
},
},
}
What BuildIFMLNet produces
pn := ifml.BuildIFMLNet(model)
// Result is a *core.PetriNet with:
//
// Places:
// p_vc_vc-home (colored, token type "ui:vc-home", initial=1)
// p_vc_vc-application-form (colored, token type "ui:vc-application-form")
// p_vc_vc-confirmation (colored, token type "ui:vc-confirmation")
//
// Transitions:
// t_act_vc-home_act-start-application handler="noop"
// t_act_vc-application-form_act-submit handler="bpmn:loan_approval_bpmn"
//
// Normal arcs:
// p_vc_vc-home → t_act_..._act-start-application → p_vc_vc-application-form
// p_vc_vc-application-form → t_act_..._act-submit → p_vc_vc-confirmation
// (arc guarded by: submissionStatus == "accepted")
//
// Read arc (DataFlow):
// p_vc_vc-application-form ──read──► t_act_..._act-submit
// (the Submit transition is only enabled when the form container is active
// AND form data is present — without consuming the "current screen" token)
t_act_vc-application-form_act-submit, it reads the handler
string "bpmn:loan_approval_bpmn", calls
ifml.ParseBackendRef to split it into
protocol="bpmn" and id="loan_approval_bpmn",
and dispatches a new BPMN process instance for that process definition ID.
The UI net and the process net run concurrently; the UI token moves to
p_vc_vc-confirmation only after the BPMN dispatcher confirms
that an instance was successfully created.
BackendRef protocol table
| BackendRef format | Dispatch destination | Example |
|---|---|---|
bpmn:<id> | Start a BPMN 2.0 process instance | bpmn:loan_approval_bpmn |
cmmn:<id> | Open a CMMN case instance | cmmn:fraud_investigation_case |
dmn:<id> | Evaluate a DMN decision table, return result inline | dmn:credit_policy |
direct:<h> | Invoke a registered handler function directly | direct:notify_user |
| (empty) | No-op transition (navigation only, no back-end call) | — |
8. Technology layer: TechComponent and TechService as infrastructure fragments
The Technology layer describes infrastructure in the same structural
language as the other layers. TechComponent,
TechService, TechInterface, and
TechProcess each compile to Petri net fragments that model
how messages enter and leave the infrastructure.
// External credit bureau API — technology component
creditBureau := &ea.TechnologyComponent{
ID: "an-credit_bureau_api",
Name: "Credit Bureau API",
Description: "External credit scoring REST endpoint",
}
// Compiles to: entry FIFO place p_tc_an-credit_bureau_api_in
// service execution transition t_tc_an-credit_bureau_api
// exit place p_tc_an-credit_bureau_api_out
// The credit check technology service
creditCheckSvc := &ea.TechnologyService{
ID: "an-tsvc_credit_check",
Name: "Credit Check Service",
ComponentID: "an-credit_bureau_api",
}
// TechService.ToPetriFragment():
// p_tsvc_in → t_tsvc_exec → p_tsvc_out
// t_tsvc_exec handler = "tech:an-tsvc_credit_check"
// The NGOR engine dispatches this handler to your registered Go function.
The Technology layer is the natural place to declare
TechInterface objects that correspond to
integration.MessageEndpoint declarations. The inbound
technology interface becomes the entry FIFO place; the outbound interface
becomes the exit place. The wiring is:
9. Migration layer: Plateau and WorkPackage as timed execution roadmaps
The Migration layer is unique in ArchiMate: it models the transition between architecture states. In most EA tools, the Migration layer is purely documentary. In Priostack, it is executable.
Plateau — roadmap anchor (no Petri fragment)
// Current state: paper-based, batch overnight credit scoring
currentPlateau := &ea.Plateau{
ID: "an-plateau_current",
Name: "Current State — As-Is (2024)",
StartDate: "2024-01-01",
EndDate: "2026-12-31",
ElementIDs: []string{"an-audit_log_db"}, // manual database only
}
// Target state: fully digital BPMN STP
targetPlateau := &ea.Plateau{
ID: "an-plateau_target_2027",
Name: "Target State — To-Be (2027)",
StartDate: "2027-01-01",
ElementIDs: []string{
"an-loan_portal", "an-loan_submission_svc",
"an-credit_bureau_api", "an-notification_gateway",
},
}
WorkPackage → timed transition with done-place
// Work package: automate BPMN straight-through processing
bpmnWP := &ea.WorkPackage{
ID: "wp-bpmn-stp",
Name: "Automate BPMN Straight-Through Processing",
PlateauID: "an-plateau_target_2027",
DurationMS: 7_776_000_000, // 90 days expected effort
}
// ToPetriFragment():
// p_wp_wp-bpmn-stp_in → t_wp_wp-bpmn-stp_execute (timed, 90-day delay) → p_wp_wp-bpmn-stp_done
// When the done-place is marked, the Deliverable for this work package
// fires and the target plateau element set becomes active.
frag := bpmnWP.ToPetriFragment()
// frag.EntryPlaces = ["p_wp_wp-bpmn-stp_in"]
// frag.ExitPlaces = ["p_wp_wp-bpmn-stp_done"]
WorkPackage.ToPetriFragment() output can be connected
directly to a BPMN process that manages the transformation project itself.
A portfolio management process can model each work package as a task with a
realistic service time distribution; the simulation tells you the probability
of hitting the target plateau date before you commit to it.
10. Vertical integration: the complete spine from Motivation to Technology
The ArchiMate specification defines realisation relationships between layers: the Business layer realises Motivation goals; the Application layer realises Business services; the Technology layer realises Application components. In Priostack, these realisation relationships are expressed as ID references between types, and the engine traces them at compilation time to build the complete execution net.
11. End-to-end walkthrough: loan origination in the ArchiMate model
With the full stack declared, here is what happens from the moment an applicant opens the loan portal to the moment a decision is produced.
// ── Startup: load the ArchiMate model and build the registries ────────────────
eaReg := ea.NewRegistry()
// Register motivation layer
eaReg.RegisterDriver(&ea.Driver{ID: "an-regulatory_pressure", ...})
eaReg.RegisterGoal(&ea.Goal{
ID: "an-approve_90pct_within_48h",
TargetPlaceID: "p_notify_applicant_done",
SLADeadlineMS: 172_800_000,
})
eaReg.RegisterConstraint(&ea.Constraint{ID: "an-identity_verification_mandatory", ...})
// Register business layer
eaReg.RegisterObject(&ea.BusinessObject{ID: "an-loan_application", ...})
eaReg.RegisterService(&ea.BusinessService{ID: "an-fraud_detection_svc", ...})
// Register application layer
eaReg.RegisterAppComponent(&ea.ApplicationComponent{
ID: "an-loan_portal",
EIPEndpointRef: "ep-portal-inbound",
Interfaces: []ea.ApplicationInterface{{
IFMLModelRef: "ifml-loan-submission",
ServiceRef: "an-loan_submission_svc",
Direction: ea.AppInterfaceProvided,
}},
})
// Build IFML execution net (compiles UI to Petri net)
ifmlModel := loadIFMLModel("ifml-loan-submission")
uiNet := ifml.BuildIFMLNet(ifmlModel)
// uiNet is ready to be submitted to the NGOR engine
// Build EIP registry
eipReg := integration.NewRegistry()
eipReg.RegisterChannel(&integration.MessageChannel{
ID: "ch-loan-submissions",
Kind: integration.ChannelPointToPoint,
})
eipReg.RegisterEndpoint(&integration.MessageEndpoint{
ID: "ep-portal-inbound",
ChannelID: "ch-loan-submissions",
Direction: integration.EndpointInbound,
ServiceRef: "an-loan_submission_svc", // ties back to BusinessService
})
// Load BPMN, DMN, CMMN process definitions
processDef, _ := bpm.ParseBPMNXML(readModel("loan_approval.bpmn"))
creditPolicy, _ := bpm.ParseDMNXML(readModel("credit_policy.dmn"))
fraudCase, _ := bpm.ParseCMMNXML(readModel("fraud_investigation.cmmn"))
// ── Runtime: applicant submits the form ───────────────────────────────────────
// 1. UI net fires t_act_vc-application-form_act-submit
// handler = "bpmn:loan_approval_bpmn"
// 2. Engine resolves: protocol=bpmn, id=loan_approval_bpmn
proto, id := ifml.ParseBackendRef("bpmn:loan_approval_bpmn")
// proto = "bpmn", id = "loan_approval_bpmn"
// 3. BPM engine starts a new process instance
instanceKey := engine.StartProcess(processDef.ID, map[string]interface{}{
"applicantName": "Emma Richter",
"loanAmount": 45000,
"submittedAt": time.Now(),
})
// 4. BPMN engine evaluates DMN credit policy (task: evaluate_credit_policy)
// BackendRef: "dmn:credit_policy"
result, _ := engine.EvalDMN(creditPolicy, map[string]interface{}{
"credit_score": 710,
"income": 65000,
"loanAmount": 45000,
})
// result: {creditDecision: "Approved", riskBand: "Low"}
// 5. BPMN gateway routes: Low risk → auto-approve path
// task: approve_loan fires → task: notify_applicant fires
// 6. On completion: EIP pipeline scores the trajectory
// (see blog-eip-pipelines for the full pipeline declaration)
// anomalyScore = 0.04 → below 0.5 threshold → registers in corpus
// 7. Goal "Approve 90% within 48h" marks p_goal_an-approve_90pct_within_48h_achieved
// (elapsed time = 800ms for this straight-through path)
12. Data tracing: ea.DataObject → pkg/items.DataItem → GeomTrace
ArchiMate's DataObject in the Application layer represents
a data entity managed by software. It is the structural counterpart of
pkg/items.DataItem, which is the live runtime instance with
state lifecycle and geometric tracing.
The geometric trace on a DataItem is the same cell-ID sequence
described in the geometric memory article.
Every time the BPM engine advances a process step, it calls
ExecuteWithGeomState, gets a new cell ID, and calls
item.Transition(newState, activityID, cellID). The full
process history is embedded in the data item — not in a separate log table,
not in an external audit system. The ArchiMate model that defined the
DataObject is the same model that defines the schema of the
trace; the two are linked by URI.
Why this matters for compliance
In highly regulated domains — banking, insurance, healthcare — every data
state transition must be auditable. The conventional approach stores audit
events in a separate database table, written by application code that can
fail silently. In Priostack, the audit trail is structural: it is produced
by the engine at every step, carried in the data item itself, and linked
back to the ArchiMate business concept via the ImportRef URI.
There is no separate audit writing path that can be bypassed.
The ea.Constraint and ea.Principle elements
from the Motivation layer are enforced at the execution level as inhibitor
places and FEEL guards respectively. An attempt to bypass the
identity verification constraint literally cannot fire the underwriting
transition — not because application code checks for it, but because the
Petri net structure prevents it.
Conclusion
Priostack's architecture closes the gap between enterprise architecture models and running processes. The key design decisions that make this possible are:
-
One type per ArchiMate concept, with a
ToPetriFragment()method. The EA model is not just documentation; it is the specification from which execution nets are compiled. -
Strict one-way dependency graph.
pkg/eaimports nothing frompkg/bpm,pkg/integration, orpkg/ifml. The binding between layers is expressed as string ID references, not type dependencies. This makes the EA model independently testable and versionable. -
IFML as the bridge between UI and BPMN.
pkg/ifml.BuildIFMLNetcompiles a UI model into a Petri net whose transitions fire BPMN, CMMN, or DMN processes via theBackendRefprotocol. The UI model and the process model evolve independently; the BackendRef string is the only coupling. -
EIP integration as the operational bus for all layer-crossing messages.
Every cross-layer communication — Business service to Application
component, Application component to Technology service, Technology
service to audit store — is a message on an EIP channel. The
integration.Registryis the single place where all these connections are declared and inspectable. -
GeomTrace as the structural audit trail.
Every
DataItemcarries the geometric history of its execution, linked back to the ArchiMate business concept that defined it. Compliance audit, anomaly detection, and corpus building all read from the same source of truth.
To see the complete stack in action, start with the agentic credit tutorial, which runs all six ArchiMate layers — from the loan application BPMN process to the geometric memory anomaly score. Then read the companion articles: Geometric Memory and Process Trajectories for the mathematical underpinning, and EIP Pipelines and Geometric Memory for the integration infrastructure that connects them at scale.
examples/e2e/models/ea_model.archimate in the
qubit-core repository is a valid
Archi
4.x project file. Open it to see the full layer diagram, relationship
map, and viewpoints for the loan origination domain — the same model
the engine executes.