Skip to content

Architecture state

A repository holds the same architecture several times over: how it is today, how it is meant to end up, and the stable plateaus in between. Architecture state is how a model, a diagram or an individual element says which of those it describes.

Without it the graph merges them. A target-state component and its baseline counterpart become one resource making contradictory claims, and a query for "what runs today" returns things nobody has built yet.

The vocabulary is three individuals from the core ontology, and the property is arch:architectureState:

Value arch:architectureState Meaning
baseline arch:Baseline how the architecture exists today — implemented, operational
target arch:Target how it should exist once planned changes are realised
transitional arch:Transitional a stable plateau on the way from one to the other

The spelling variants the ontology records as skos:altLabel are accepted too: as-is, current and current-state for baseline; to-be, future and future-state for target; transition, intermediate and intermediate-state for transitional. Case and the choice of -, _ or a space are ignored, so As Is and as-is are one value.

Not the same thing as status:

The two are easy to confuse and answer different questions.

Field Question Subject
status: has this diagram been released? the diagram, as a document
architectureState: which reality does it describe? the architecture

A target-state diagram can be perfectly published — finished, reviewed, and describing a future that does not exist yet. Neither field implies anything about the other, which is why they are separate fields rather than one vocabulary. Writing draft under architectureState: fails the run and says where it belongs.

status: is ADR 0004 and reaches the graph as adms:status in the provenance graph. Architecture state lands in the semantic graph.

Which route each notation and level has

There are two ways to state it, and the difference matters more than where you write it:

  • The checked route — the architectureState: field, or '!la-architecture-state in a .puml. You supply a token, its value must be one of three, a typo fails the run, and no flag is needed.
  • The generic route — writing the triple yourself as an annotation: links:, '!la-link, BPMN extensionElements, or an ArchiMate property. You supply the predicate IRI and the object IRI, any IRI is accepted without complaint, and it requires --emit-extension-data.

The checked route reaches only the model and the view, and only where a diagram index exists. Every other cell below is the generic route.

Notation Model View Element
PlantUML index — checked index, or in-file '!la-architecture-state — checked generic: index elements:, or in-file '!la-link
BPMN index — checked index — checked generic: index elements:, or in-file extensionElements
Backstage index — checked index — checked generic: index elements:
LeanIX index — checked index — checked generic: index elements:
ArchiMate ✗ no route generic: property + object-properties: generic: property + object-properties:
also relationships
Structurizr ✗ ✗ ✗

What each route costs is set out under the two routes below.

Two gaps are worth stating plainly rather than leaving to be discovered:

  • ArchiMate has no model-level route. It has no diagram index, and the converter promotes properties on elements, relationships and views but not on the model. A model-wide claim has to be made in the aggregation repository instead.
  • Structurizr has no route at all, in-file or index.

The two routes

The checked route: architectureState:

A first-class field whose values are a closed set. Not gated behind --emit-extension-data: which reality a diagram describes is a property of the diagram, like its status, not data borrowed from a modelling tool's extension point.

In the diagram index, at model level and per view:

model:
  id: order-domain
  architectureState: baseline        # the model IS the baseline architecture
views:
  - id: order-flow-as-built
    file: order-flow.bpmn
    status: publish
  - id: order-flow-planned
    file: order-flow-v2.bpmn
    status: publish
    architectureState: target        # this diagram describes the target

PlantUML sources can also declare it in the file, which BPMN cannot — a .bpmn has nowhere to put a statement about the diagram as a whole, because extensionElements nests inside the element it annotates:

'!la-architecture-state target
@startuml
class OrderService
@enduml

An unrecognised value fails the run, naming the entry:

[ERROR] Conversion failed: Unknown architectureState 'Targt' for 'planned.puml' in
/repo/models/diagram-index.yaml. Accepted: baseline, target, transitional. A state says which
reality the diagram describes, so an unrecognised one is refused rather than published as a link to
a term nothing defines. Note this is not the publication status: 'draft' and 'publish' belong under
'status:'.

Failing closed is the whole point of the field existing, and the contrast with the generic route below is the reason it is a field rather than one more link.

If a PlantUML file and the index both declare one, they must agree. Baseline and target are opposite claims about one diagram, so a disagreement is refused rather than settled by precedence — which is where this differs from a prefix declared twice. Preferring either silently would publish a future architecture as current, or the reverse.

The same predicate written through the extension-data mechanism. This is the only route that reaches an element, and for ArchiMate it is the only route at all.

Index, any of the three levels. Requires --emit-extension-data:

prefixes:
  arch: https://meta.linked.archi/core#
model:
  id: order-domain
  links:
    arch:architectureState: arch:Baseline          # the model
views:
  - id: planned
    file: planned.bpmn
    links:
      arch:architectureState: arch:Target          # the view
    elements:
      Process_Order:
        links:
          arch:architectureState: arch:Target      # one element

PlantUML, in the file:

'!la-prefix arch: https://meta.linked.archi/core#
'!la-view-link arch:architectureState arch:Target          # the view
'!la-link OrderService arch:architectureState arch:Target  # one element

BPMN, in the file. The subject is always the element that owns the extensionElements, so this reaches the process and its tasks but never the arch:View:

<definitions xmlns:arch="https://meta.linked.archi/core#"
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" …>
  <process id="Process_Order" name="Order Fulfilment">
    <extensionElements>
      <arch:architectureState rdf:resource="arch:Target"/>
    </extensionElements>

ArchiMate, as an element, relationship or view property, with the key declared under object-properties: in --type-mapping so the value resolves to an IRI rather than a string:

namespaces:
  arch: https://meta.linked.archi/core#
object-properties:
  - arch:architectureState

Without that declaration the property is emitted as the literal "arch:Target", which violates arch:architectureState's rdfs:range and loses the IRI join, so no query can follow it into the state vocabulary. See type mapping and ArchiMate.

What the generic route costs

It is gated. Without --emit-extension-data the entries are read and ignored. Nothing warns that a statement was dropped.

It is not validated. A generic predicate has no closed set to check against, so a misspelling resolves to a perfectly valid IRI that nothing defines, and nothing complains:

# authored as arch:architectureState: arch:Targt
<…/element/Process_Order> arch:architectureState <https://meta.linked.archi/core#Targt> .

A query filtering on arch:Target then silently skips that element — no error at conversion, no error at query time, just a row that is not there. The only case that does warn is an undeclared prefix, where the value cannot resolve at all and is kept as a literal.

So the discipline is on the author wherever the checked field does not reach: element scope in every notation, and every level in ArchiMate.

Two rules that govern how it is read

Nothing is inherited. This is where architecture state differs from status:, where a model-level value is only a default and the model is never the subject. arch:architectureState is defined on a Model as readily as on a view — the core ontology's own example uses a Model — so a model saying baseline is a claim about the model, not a default for its views:

model:
  id: order-domain
  architectureState: baseline        # the model is the baseline architecture
views:
  - id: as-built
    file: as-built.puml              # says nothing of its own, and inherits nothing
  - id: planned
    file: planned.puml
    architectureState: target        # this diagram describes the target

A view-level statement does not reach the elements in the view either. A diagram marked arch:Target has elements carrying nothing, so "which applications are in the target architecture" is answered by walking from the view into its contents, not by filtering elements directly.

Saying nothing asserts nothing. There is no default. A repository that has never distinguished baseline from target is not thereby claiming everything is baseline, which means an unstated resource is genuinely unstated and must not be read as baseline by a consumer.

What reaches the graph

One triple per subject, in the model's semantic graph:

<https://example.org/la/bpmn/order-domain/graph/semantic> {
    <…/bpmn/order-domain>                          arch:architectureState arch:Baseline .
    <…/bpmn/order-domain/view/order-flow-planned>  arch:architectureState arch:Target .
    <…/bpmn/order-domain/element/Process_Order>    arch:architectureState arch:Target .
}

Semantic rather than provenance, for two reasons that point the same way. It says which reality the diagram describes rather than how the file came to be, so it is not provenance in the sense the rest of the index metadata is. And the same predicate can arrive through the generic route, which lands in the semantic graph — one predicate appearing in two named graphs depending on which route wrote it would silently halve the results of any query scoped to a single graph.

See also