Two related problems in relationshipLabel (internal/render/mermaid/mermaid.go), both
found while investigating #26 on a real 13-entity model.
1. Long role values collide as edge labels
The schema documents role as "What role the related entity plays ... A role name like
Owner should be defined in the glossary" — i.e. a short noun phrase. Nothing enforces
that. modelith lint only inspects backticked PascalCase tokens inside a role
(entityRefs), so a freeform prose role passes clean:
- entity: AcceptancePlan
cardinality: "1:0..1"
role: "the run's contract, present at capability scale"
The renderer passes it verbatim into the Mermaid edge label. Mermaid's dagre ER layout
reserves no space for edge labels, so on a model with several such roles the labels overlap
each other and the entity boxes, and drift onto lines they don't belong to. Replacing every
label with a single word cleared the overlap entirely — confirming the label text, not the
graph shape, is the cause.
Modelith has a better home for prose: relationship.note. But nothing steers an author
there, and the failure mode only shows up after rendering.
Options: lint warning when a role exceeds ~N words or contains sentence punctuation
(pointing at note); and/or wrap or truncate the label in the Mermaid renderer while
keeping the full text in the Markdown table.
2. Ownership is silently dropped when a role is present
func relationshipLabel(rel model.Relationship) string {
switch {
case rel.Role != "":
return sanitize(rel.Role)
case rel.Ownership != "":
return rel.Ownership
default:
return rel.Cardinality
}
}
Crow's-foot notation cannot express composition, so "owned" on the edge is the only place
that signal appears in the diagram. But the role branch wins, so:
- an owned relationship with a role renders the role, and looks identical to a
referenced one;
- an owned relationship without a role renders
"owned".
On the model I looked at, four relationships were ownership: owned; two showed owned and
two did not, purely because the latter also had a role. The diagram reads as though the
composition structure is inconsistent when the source is not.
Worth considering: combine them (owned — <role>), or drop the ownership fallback and
express composition through styling instead. Either way the current behaviour is information
loss that depends on an unrelated field being set.
Two related problems in
relationshipLabel(internal/render/mermaid/mermaid.go), bothfound while investigating #26 on a real 13-entity model.
1. Long
rolevalues collide as edge labelsThe schema documents
roleas "What role the related entity plays ... A role name likeOwnershould be defined in the glossary" — i.e. a short noun phrase. Nothing enforcesthat.
modelith lintonly inspects backticked PascalCase tokens inside a role(
entityRefs), so a freeform prose role passes clean:The renderer passes it verbatim into the Mermaid edge label. Mermaid's dagre ER layout
reserves no space for edge labels, so on a model with several such roles the labels overlap
each other and the entity boxes, and drift onto lines they don't belong to. Replacing every
label with a single word cleared the overlap entirely — confirming the label text, not the
graph shape, is the cause.
Modelith has a better home for prose:
relationship.note. But nothing steers an authorthere, and the failure mode only shows up after rendering.
Options: lint warning when a
roleexceeds ~N words or contains sentence punctuation(pointing at
note); and/or wrap or truncate the label in the Mermaid renderer whilekeeping the full text in the Markdown table.
2. Ownership is silently dropped when a role is present
Crow's-foot notation cannot express composition, so
"owned"on the edge is the only placethat signal appears in the diagram. But the
rolebranch wins, so:referenced one;
"owned".On the model I looked at, four relationships were
ownership: owned; two showedownedandtwo did not, purely because the latter also had a role. The diagram reads as though the
composition structure is inconsistent when the source is not.
Worth considering: combine them (
owned — <role>), or drop the ownership fallback andexpress composition through styling instead. Either way the current behaviour is information
loss that depends on an unrelated field being set.