Import sap-architecture skill

This commit is contained in:
2026-07-24 20:47:16 +00:00
commit f3699e6f43
121 changed files with 127110 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
# SAP Reference Corpus Findings
Research snapshot: 2026-04-28.
Sources:
- `SAP/btp-solution-diagrams` at commit `c9860da`
- `SAP/architecture-center` at commit `e76ce36`
- SAP Community announcement: <https://community.sap.com/t5/technology-blogs-by-sap/announcement-new-release-of-content-and-central-entry-point-for-sap-btp/bc-p/14011436>
## Corpus Size
The current public corpus contains 138 editable `.drawio` diagrams:
| Source | `.drawio` files | Role |
|---|---:|---|
| `SAP/btp-solution-diagrams/assets/editable-diagram-examples` | 11 | canonical BTP Solution Diagram examples |
| `SAP/architecture-center/docs/ref-arch/**/drawio` | 127 | Architecture Center reference architecture diagrams |
The raw upstream draw.io corpus is about 24 MB. This plugin bundles a curated 71-template subset: all 11 canonical BTP examples, 52 Architecture Center templates chosen for broad SAP BTP coverage, and 8 curated external SAP-compatible reference examples.
## What the Live Corpus Shows
Common page sizes:
| Page size | Count | Use |
|---|---:|---|
| `1169 x 827` | 46 | canonical landscape canvas; safest default |
| `1100 x 850` | 22 | Architecture Center landscape variant |
| `1654 x 1169` | 17 | large A3-style landscape |
| `850 x 1100` | 15 | portrait variant |
| `827 x 1169` | 13 | canonical portrait variant |
Top observed colors outside embedded SVG icon payloads:
| Hex | Count | Meaning / note |
|---|---:|---|
| `#475E75` | 2167 | non-SAP area border / neutral stroke |
| `#1D2D3E` | 2139 | title / primary text |
| `#FFFFFF` | 1865 | card fill / background |
| `#0070F2` | 1627 | SAP / BTP area border |
| `#188918` | 782 | positive / authentication flow |
| `#F5F6F7` | 576 | non-SAP area fill |
| `#EBF8FF` | 525 | SAP / BTP area fill |
| `#00185A` | 503 | dark SAP blue variant used in Architecture Center diagrams |
| `#5D36FF` | 467 | indigo / authorization flow |
| `#266F3A` | 402 | dark positive green variant |
| `#CC00DC` | 323 | pink / trust flow |
Observed font families:
| Font | Count | Guidance |
|---|---:|---|
| `Helvetica` | 3494 | default for generated diagrams |
| `Arial` | 1978 | appears in SAP files, often inside rich text labels |
| `72 Brand` | 124 | appears in some newer Architecture Center files; do not introduce unless inherited from a template |
Observed stroke widths:
| Stroke width | Count | Guidance |
|---|---:|---|
| `1.5` | 5902 | dominant border / connector weight |
| `2` | 627 | secondary connector / emphasis |
| `1` | 456 | pills, small cards, light dividers |
| `3` | 86 | heavy emphasis |
| `4` | 10 | firewall / very heavy boundary |
## Implementation Decisions
- Keep `1169 x 827` as the default canvas because it is both the canonical BTP examples' size and the most common live corpus size.
- Keep `Helvetica` as the generated-diagram default. `Arial` and `72 Brand` are accepted as inherited upstream-template variants but should not be newly introduced by the skill.
- Expand the validator palette with observed SAP variants such as `#00185A`, `#0057D2`, `#2395FF`, `#D1EFFF`, and common neutral variants so the validator does not fight real Architecture Center files.
- Validate duplicate IDs per draw.io page, not globally across the entire `.mxfile`; multi-page upstream files can reuse `0` / `1` root IDs safely.
- Bundle representative templates rather than every raw upstream diagram. The full corpus can still be used for research by cloning the SAP repos and passing them to `score_corpus.py --references`.
## Operational Loop
For a generated candidate:
1. Run `select_reference.py` on the user's request and pick from the top 3 candidates.
2. Copy the selected template and preserve geometry, canvas, container rhythm, legend style, and line/pill density.
3. Relabel and replace only the content required by the user's scenario.
4. Run `autofix.py --write`.
5. Run `validate.py`.
6. Run `score_corpus.py --min-score 90`.
7. If the score is below 90, use `compare.py` against the selected template and restore the dimensions that drifted.
The point of the loop is not to make every generated diagram identical. It is to keep the structural fingerprint close enough that a new diagram reads as part of the SAP Architecture Center system rather than as a generic draw.io sketch.
+118
View File
@@ -0,0 +1,118 @@
# Do and Don't — consolidated SAP rules
Every entry below is a verbatim quote from the official SAP BTP Solution Diagram Guidelines, with the source file in the footer of each item.
## Areas / containers
**DO** — alternate fill / no-fill when nesting:
> "When nesting different areas inside each other, you should alternate between using a fill and not using a fill to provide sufficient contrast between the areas. **The parent layer is usually the BTP layer.**" — `diagr_comp/areas.md`
**DON'T** — change the style of stacked layers:
> "Areas can be shown as stacked to display multiple grouped layers or items. **The style should not be changed in order to keep diagrams consistent.**" — `diagr_comp/areas.md`
**DO** — use the fixed corner radius:
> "**A fixed corner radius of 16 pixels is recommended.**" — `diagr_comp/areas.md`
## Color usage
**DO** — use one consistent palette family (Horizon):
> "Horizon is the default visual style for SAP Products … This also applies to diagrams." — `foundation.md`
**DON'T** — paint everything in accent colors:
> "Secondary colors can be applied to accentuate important elements. They make a vivid contribution to the overall UI and **should be used sparingly.**" — `foundation.md`
**DON'T** — overpower with primary/non-SAP either:
> "It is not recommended to use the colors too heavily, they can overpower the diagram." — `diagr_comp/areas.md`
## Connectors / arrows
**DO** — use the fixed semantic mapping:
> "Trust Flows are usually pink / Authentication flows are usually green / Authorization flows are usually indigo / Firewalls and Network barriers are thick grey lines" — `lines_connectors.md`
**DO** — pick the line style that matches the data-flow semantics:
> "Solid lines for direct, synchronous request-response data flows / Dashed lines for indirect, asynchronous data flows / Dotted lines for optional data flows / Thick lines for firewalls only" — `foundation.md`
**DON'T** — invent your own arrow style:
> "Avoid creating your own arrows; use the ones available in the library instead as they adhere to the correct styling guidelines." — `solution_diagr_intro/big_picture.md`
**DON'T** — use thick lines for anything other than firewalls:
> "Thick lines for firewalls only" — `foundation.md`
## Icons
**DO** — use the grey-circle service icons:
> "**For diagram visualization it is mandatory to use the version with grey background circle.**" — `diagr_comp/icons.md`
**DO** — use generic icons for non-SAP elements (devices, databases):
> "This set of icons with soft gradients is used for all elements that are either generic such as devices or databases. … **The primary color used is neutral grey.**" — `diagr_comp/icons.md`
## Product names
**DO** — pair SAP product names with the SAP logo:
> "**SAP product names must be paired with the SAP logo.**" — `diagr_comp/product_names.md`
**DON'T** — over-do the SAP logo:
> "**It is not recommended to use too many SAP logos in the same diagram. Use text only elements instead.**" — `diagr_comp/product_names.md`
The skill applies this rule by placing exactly **one** SAP logo per diagram (top-right of the BTP zone). Service cards inside the BTP zone don't get individual logos — the one zone-level logo carries them.
## Text / typography
**DO** — keep text sizes consistent when scaling:
> "When scaling elements up or down, take care to ensure text sizes remain consistent." — `solution_diagr_intro/big_picture.md`
**DO** — use the four-style hierarchy:
> "**To create hierarchies four text styles were derived from Fiori Horizon.**" — `diagr_comp/text.md`
## Spacing
**DO** — use the SAP-logo-height rule:
> "**Spacing around objects should be even and roughly the height of the SAP Logo.**" — `foundation.md`
## Legend
**DO** — include a legend in L1 / L2:
> "**Including a legend in each diagram is crucial to clarify these meanings.**" — `foundation.md`
**DON'T (L0 only)** — force a legend onto a marketing-level diagram:
> "In such diagrams, connectors maintain neutrality and the content is streamlined to essentials, **eliminating the necessity for a legend, but a short description is recommended.**" — `solution_diagr_intro/big_picture.md`
## PowerPoint vs draw.io
**DO** — switch to draw.io if PowerPoint constrains the layout:
> "**Slide dimensions are unalterable**, so if you find the available space inadequate for your diagram, **avoid downscaling all the elements to accommodate it**. … **If your diagram is too large for PowerPoint, consider switching to draw.io.**" — `solution_diagr_intro/big_picture.md`
This skill always emits draw.io.
## What this skill enforces automatically
`validate.py` catches:
- Off-palette hex (warns)
- **Dark / branded page background** (`pageBackgroundColor` not in {white, transparent}) — error
- **Off-vocabulary pill verbs** — pills labelled `PROMPT`, `ROUTE`, `CONTEXT`, `DELEGATE`, `INVOKE`, `FETCH`, `EXECUTE`, etc. trigger warnings. Use canonical SAP verbs: `TRUST`, `Authenticate`, `Authorization`, `A2A`, `MCP`, `ORD`, `HTTPS`, `OData/REST`, `REST/Token`, `SAML2/OIDC`, `OIDC`, `SCIM`, `Identity Lifecycle`, `Group`, `Role`, `Role Collection`, `Source`, `Target`, `Destination`.
- **Multi-logo over-use** — more than 6 SAP logos in one diagram triggers a warning per `product_names.md`.
- `absoluteArcSize=1` missing when `arcSize` is set (warns; autofix repairs)
- `strokeWidth` outside `{1, 1.5, 2, 3, 4}` (warns)
- `strokeWidth>=3` flagged for review (firewall-only rule)
- Edge label without `labelBackgroundColor=default` (warns)
- Bent `orthogonalEdgeStyle` edge (centers not aligned on any axis) — error
- Label text wider than its shape — error
- Sibling shape overlap (not contained, not transparent, not pill) — error
- Off-grid coordinates — warns; autofix repairs
- `fontFamily` ≠ Helvetica — warns; autofix repairs
- Duplicate ids, missing `mxGeometry`, XML comments — error
`compare.py` additionally penalises:
- Wrong page background (white SAP canvas vs candidate dark theme)
- Wrong zone *hierarchy* — e.g. nesting Joule inside the BTP zone when the SAP reference puts them side by side
- Wrong edge stroke palette — semantic mismatches (green where magenta is expected) that the global palette set hides
- Pills using novelty verbs instead of the canonical SAP vocabulary
What `validate.py` does **not** check (yet — manual review):
- "Use the grey-circle icon variant" — visual check, not extractable from XML
- "Don't use accent colors heavily" — proportional rule, hard to quantify
- "Spacing roughly = SAP logo height" — context-dependent
- "Legend present" — checked only via warning if `level=L1|L2` and no `legend` element exists
+123
View File
@@ -0,0 +1,123 @@
# draw.io / mxGraph authoring gotchas
Encoding and alignment rules that apply whenever this skill **writes or edits
mxCell XML directly** — i.e. during surgical relabels (step 4), when adding
cards/edges next to template cells, and in `render_semantic.py`-derived output.
Violations are silent at write time and only visible when the user opens the
file: blank icons, "duplicate id" rejections, or connectors cutting through
artwork. `validate.py` mechanically checks §§12 and the structural parts of §7.
Scaffolded SAP templates already satisfy all of this — these rules matter for
the cells **you** add or change.
## 1. Embedded-image data URIs must OMIT `;base64`
draw.io style strings are `;`-delimited key=value lists. A standard data URI
(`data:image/svg+xml;base64,PHN2...`) contains a `;` — draw.io truncates the
`image=` value at that semicolon and starts parsing `base64,PHN2...` as a new
style key. Result: every icon renders blank, with no error.
- **Correct (draw.io style):** `image=data:image/svg+xml,PHN2Zy8+;`
(payload IS still base64-encoded; only the `;base64` marker is dropped —
draw.io's own convention, and what the bundled SAP libraries ship.)
- **Incorrect:** `image=data:image/svg+xml;base64,PHN2Zy8+;`
- Plain SVG/HTML is the opposite: an `<image href>` **requires** the standard
`;base64` form. If you generate both a `.drawio` and an SVG preview from the
same data, the two encodings must differ.
`extract_icon.py` / `extract_asset.py` emit the correct form — this rule bites
only when embedding a third-party logo or UI5 icon-font SVG by hand.
## 2. Root-cell skeleton and reserved ids
Every diagram page must begin with a **parentless root cell**, then a **layer
cell parented to it**, before any content:
```xml
<mxCell id="0" />
<mxCell id="1" parent="0" />
```
`0`/`1` are mxGraph's defaults, but the SAP corpus frequently uses namespaced
equivalents (`<prefix>-0`, `<prefix>-1`) — the *structure* is what matters, and
`validate.py` checks it. Two failure modes for hand-authored pages:
- Omitting the two root cells entirely → draw.io rejects the file.
- A content cell reusing the page's root/layer id (easy when deriving ids from
numeric counters, colliding with literal `0`/`1`) → "duplicate id", whole
file rejected. Namespace generated ids (`n-<id>`, `edge-3`, `pill-2`).
Ids must be unique within a page; each `<diagram>` page has its own id space.
## 3. Z-order is document order
Later cells render on top. Emit **edges before vertices** so connectors sit
behind nodes/icons (SAP's files do this; they never rely on opaque icon
backings). draw.io resolves an edge's `source`/`target` by id even when those
cells are declared later — forward references are fine. When inserting new
cards into a template, insert them **after** the edges that touch them.
## 4. Connectors must attach to facing connection points
Without fixed connection points, draw.io anchors edges center-to-center and a
line can cut straight through nodes that sit between endpoints. Give every
added edge directional exit/entry on the border side facing the counterpart:
```
exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;
```
(source's right edge → target's left edge, for a left-to-right flow; use
Y 0/1 with X 0.5 for vertical). Combine with `edgeStyle=orthogonalEdgeStyle;
rounded=0;orthogonalLoop=1;jettySize=auto;` so the router runs segments through
the gaps between columns. Z-order alone is never the fix for edges crossing
icons. This complements the center-alignment rule in `shapes-and-edges.md`:
aligned centers make the edge *straight*; facing anchors make it *dock* on the
correct sides.
## 5. Explicit waypoints
To force a route (e.g. through a routing channel between zones), put bend
points inside the edge geometry — intermediate points only; endpoints come
from the cells:
```xml
<mxGeometry relative="1" as="geometry">
<Array as="points"><mxPoint x="520" y="140"/><mxPoint x="520" y="260"/></Array>
</mxGeometry>
```
Keep waypoint coordinates on the 10-px grid like everything else.
## 6. Image aspect ratio & inscription
`imageAspect=1` preserves proportions (`0` stretches to the cell box — wide
wordmark logos become distorted). The SAP corpus itself uses `imageAspect=0`
on cells whose geometry was hand-sized to the artwork, so this is **not** a
validator check — it's a rule for logos *you* embed, where the cell box rarely
matches the source aspect exactly. In SVG the equivalent is
`preserveAspectRatio="xMidYMid meet"`. Square logos placed on a circular tile
must be inscribed: icon side ≤ tile diameter / √2, or the corners poke past
the circle (e.g. a 52-px tile fits at most a ~36-px square icon).
## 7. Structure & page setup
- Skeleton: `<mxfile><diagram id="..." name="..."><mxGraphModel ...><root>` +
the two reserved cells, then content. Emit uncompressed XML — never the
base64-deflate `<diagram>` payload form.
- Every vertex needs `vertex="1"` + `<mxGeometry x y width height as="geometry"/>`;
every edge `edge="1"` + resolvable `source`/`target` (or explicit
`sourcePoint`/`targetPoint` for floating edges); every cell (except `0`) a
valid `parent`.
- Children of a container (`container=1` or any parented vertex) use
coordinates **relative to the parent**, not the canvas. When re-parenting an
icon into a card (the "tucked inside a card" pattern), convert its x/y to
card-local values.
- Escape XML in labels/attrs: `&` `<` `>``&amp;` `&lt;` `&gt;`; `html=1`
when the label carries HTML.
## 8. Edge routing extras seen in the SAP corpus
- `entityRelationEdgeStyle` — perpendicular jetty stubs; SAP uses it for
*indirect* flows where orthogonal elbows would read as a direct chain.
- `targetPerimeterSpacing=15` — leaves a visual gap before the target border so
arrowheads don't kiss the stroke.
- `jumpStyle=none` — edge crossings drawn flat, no hop arcs. Don't enable
jumps; SAP's published files never use them.
+75
View File
@@ -0,0 +1,75 @@
# External SAP diagram test corpus
The bundled 71 templates remain the default because they are curated, compact, and versioned with this plugin. For deeper quality work, use external SAP repositories as opt-in test corpora under `.cache/`.
## Recommended external corpus
### `SAP/sap-btp-reference-architectures`
- Source: https://github.com/SAP/sap-btp-reference-architectures
- License: Apache-2.0.
- Why it matters: this repository contains 32 editable `.drawio` SAP BTP reference architecture files across Work Zone, Build Process Automation, Task Center, Private Link, multi-region resiliency, Datasphere, OpenAI/RAG, Federated ML, IAM, API-managed integration, B2B, B2G, A2A, and Master Data Integration.
- Local finding from 2026-05-01: 27 of 32 files score below 90 against the bundled corpus, and 18 score below 80. That makes it a useful stress suite for template coverage and geometry drift, not just a duplicate corpus.
- Baseline leave-one-out run from 2026-05-01: 7 passed, 7 near-miss, 18 ceiling-limited. Run this after the bundled suite to find template gaps that the main corpus does not expose.
Clone it under `.cache/`:
```bash
mkdir -p .cache/external
git clone --depth 1 https://github.com/SAP/sap-btp-reference-architectures.git \
.cache/external/sap-btp-reference-architectures
```
Run a dry-run first:
```bash
python3 plugins/sap-architecture/skills/sap-architecture/scripts/eval_corpus.py dry-run \
--references .cache/external/sap-btp-reference-architectures \
--limit 8 \
--generator ollama \
--model qwen3.6:35b-a3b-nvfp4 \
--exclude-target-template \
--apply-model-plan \
--max-attempts 3 \
--retry-margin 8 \
--min-score 90
```
Run the external overnight suite after the bundled suite:
```bash
caffeinate -dimsu -- \
python3 plugins/sap-architecture/skills/sap-architecture/scripts/eval_corpus.py run \
--references .cache/external/sap-btp-reference-architectures \
--generator ollama \
--model qwen3.6:35b-a3b-nvfp4 \
--exclude-target-template \
--apply-model-plan \
--max-attempts 3 \
--retry-margin 8 \
--min-score 90 \
--timeout-seconds 1200 \
--continue-on-error \
2>&1 | tee .cache/sap-architecture-eval/external-sap-btp-reference-architectures.log
```
## Sources not recommended for committed test fixtures
### SAP Discovery Center
SAP Discovery Center has useful BTP reference architecture descriptions and downloadable diagrams, but its terms are narrower than Apache-2.0. Treat it as a source of scenario ideas or private/internal tests only unless the specific artifact has a compatible license.
### Lucidchart marketplace and draw.io built-in SAP shapes
These are useful for asset coverage checks and visual expectations, but they are not a convenient `.drawio` target corpus. Use them to verify that official BTP service icons, area shapes, number markers, and connector conventions remain represented in `assets/asset-index.json`.
### `SAP-samples/teched2023-XP286v`
This is useful historical training material for the BTP solution diagram workflow, but it does not currently provide extra `.drawio` target files. Do not use it as a scoring corpus.
## How to interpret external results
- High corpus score and low target score means the generated diagram is still SAP-styled but the selected bundled template is structurally unlike the external target.
- `ceiling-limited` external cases are candidates for adding new templates or geometry-aware generation.
- `near-miss` external cases are candidates for selector metadata, label replacement, or a small number of additional model attempts.
- Do not commit generated `.cache/` outputs. Promote only reviewed examples or new legally compatible references.
+50
View File
@@ -0,0 +1,50 @@
# Diagram generation quality checklist
This checklist distills the research used to improve generated SAP BTP diagrams.
## General architecture diagram quality
- A diagram should stand alone: title, scope, notation, and acronyms must be understandable without a long narration.
Source: https://c4model.com/diagrams/notation
- Avoid ambiguous boxes and lines: element purpose, technology/protocol, and relationship intent should be visible.
Source: https://c4model.com/introduction
- Every meaningful relationship should be directional and labelled with a specific intent or protocol where possible.
Source: https://c4model.com/diagrams/notation
- Keep abstraction level consistent; mixing overview and implementation details makes diagrams hard to read.
Source: https://c4model.com/introduction
## SAP-specific quality
- Use the SAP BTP starter kit, official templates, and shape libraries instead of starting from blank XML.
Source: https://architecture.learning.sap.com/docs/community/diagrams
- Keep icon sizes, text formatting, and line styles consistent; do not invent custom arrows.
Source: https://architecture.learning.sap.com/docs/community/diagrams
- Use the BTP service icon version with the grey background circle.
Source: https://sap.github.io/btp-solution-diagrams/docs/btp_guideline/diagr_comp/icons/
- Preserve SAP area colors and 16 px corner radius; use accent colors sparingly.
Source: https://sap.github.io/btp-solution-diagrams/docs/btp_guideline/diagr_comp/areas/
- Use connector semantics consistently: trust is usually pink, authentication green, authorization indigo, and firewalls/network barriers thick grey.
Source: https://sap.github.io/btp-solution-diagrams/docs/btp_guideline/diagr_comp/lines_connectors/
- Do not downscale whole diagrams to fit; SAP's text sizes and line styles are tuned for the target medium.
Source: https://sap.github.io/btp-solution-diagrams/docs/solution_diagr_intro/big_picture/
## Implementation consequences
- `select_reference.py` prefers explicit reference families such as `RA0001`, preserves explicit L0/L1/L2 level hints, and reads curated `template-metadata.json` aliases/tags so generic labels like `Page-1` do not dominate selection.
- Generic Agentic AI + Joule prompts should anchor on `ac_RA0029_AgenticAI_root.drawio`; use the Embodied AI template only for explicit embodied/robotic/physical-agent scenarios.
- `eval_corpus.py create` provides a direct description-to-diagram path for smoke tests and examples.
- Preserve SAP Architecture Center reference-canvas structure, including white background, SAP footer/reference id/QR where present, network dividers, and inline pill notation. Do not add a dark dashboard background or a bottom legend band to templates that do not already have one.
- `eval_corpus.py run --exclude-target-template` now reports the nearest visual fallback templates computed from SAP fingerprints. These hints keep leave-one-out evaluation focused on visual fidelity when the exact target template is intentionally unavailable. Use `--no-style-neighbor-hints` for a pure semantic selector test.
- Overnight runs classify failures into `near-miss` and `ceiling-limited`. A ceiling-limited case means the chosen alternate SAP template is structurally too far from the target; add a closer sibling template or improve geometry-aware generation instead of spending more model attempts.
- Use the default `--retry-margin 8` for long local runs. With `--min-score 90`, it retries only cases that already score 82+ and stops early on low-ceiling cases.
- Use `references/external-test-corpus.md` for the second-stage external SAP run. The older `SAP/sap-btp-reference-architectures` diagrams are useful stress cases because they cover legacy and methodology-driven layouts that are not all visually close to the bundled templates.
- The Ollama prompt now asks for protocols/flow semantics, target-audience consistency, and conservative template label replacements.
- Model label edits do not rewrite reserved legend/notation labels such as `Access`, `Authentication`, `Authorization`, `Trust`, or `Deployment`.
- Unguarded model replacements are limited to title/service labels or near-typo corrections, reducing semantic drift.
- Scoring normalizes known SAP upstream typos such as `Adminstrator`, `Provisoning`, and `Plaforms`, so corrected output is not penalized.
- Per-attempt `target-compare.json` and `best-corpus-compare.json` files explain why a candidate did or did not match the target.
- Ollama runs use `/api/generate` with a JSON schema by default, temperature `0`, and CLI fallback if the local API is unavailable. This follows Ollama's structured-output guidance and keeps long runs machine-consumable.
- Retry attempts now receive compact score feedback from the previous attempt: validator counts, weak fingerprint dimensions, target diffs, and rejected label replacements. This makes second/third attempts useful for near-miss cases while leaving low-ceiling template gaps for human/template review.
- Use `--from-run <run-dir> --case-class near-miss` for focused retry runs. Re-running the full corpus after a stable plateau wastes time on ceiling-limited cases whose alternate template is structurally too far from the target.
- Use `--case-id <substring>` for manual smoke tests against one architecture family, for example `--case-id ra0024` for Joule/IAM or `--case-id agenticai` for Agentic AI.
- See `references/improvement-options.md` for the researched option ranking and why direct XML generation, generic autolayout, and fine-tuning are not the best next moves for SAP-style fidelity.
+144
View File
@@ -0,0 +1,144 @@
# Improvement options for higher SAP diagram fidelity
Research snapshot: 2026-05-01.
The goal is not generic diagram generation. The goal is editable `.drawio` output that looks close to SAP Architecture Center and SAP BTP Solution Diagram examples. That changes the ranking: preserving SAP-authored geometry, icons, colors, and notation is more important than asking a model to invent a new layout.
## High-value options implemented
### 1. Template-first generation
Status: implemented earlier and kept as the primary workflow.
Why it fits: SAP explicitly provides reusable examples/templates and starter-kit libraries so authors do not start from scratch. The local corpus results show the same thing empirically: a template-derived candidate can score near the source template, while from-scratch candidates lose canvas rhythm, icon counts, line topology, and typography.
Implementation consequence: `select_reference.py` picks a SAP-authored template, `eval_corpus.py` copies that template, and model output is allowed to make conservative label edits only. This keeps geometry, colors, icon data URIs, edge styles, and area shapes intact.
Sources:
- https://sap.github.io/btp-solution-diagrams/docs/solution_diagr_intro/intro/
- https://architecture.learning.sap.com/news/2026/04/22/introducing-the-refreshed-sap-architecture-center
### 2. Structured generation plan instead of free-form model text
Status: implemented in `eval_corpus.py`.
Why it fits: Ollama supports a JSON schema in the `format` field for `/api/generate`, and its docs recommend low temperature for deterministic structured output. The harness now uses the HTTP API with a schema for `title`, `subtitle`, `services`, `flow_steps`, `style_risks`, and `template_replacements`, falling back to the CLI only if the API is unavailable.
Expected impact: fewer parse failures, less markdown/control-token cleanup, and more consistent plan fields across long overnight runs. It does not solve geometry by itself, but it makes model output reliable enough for the deterministic template adapter.
Sources:
- https://docs.ollama.com/capabilities/structured-outputs
- https://docs.ollama.com/api/generate
### 3. Score-feedback retries
Status: implemented in `eval_corpus.py`.
Why it fits: DiagrammerGPT-style systems separate diagram planning from rendering and use iterative feedback to refine the plan. For this plugin, the renderer is deterministic template copying plus guarded label edits, so the useful feedback is the validator result, target score, weak fingerprint dimensions, target diffs, and rejected label replacements.
Expected impact: near-miss cases get a real second/third attempt instead of another independent generation. Ceiling-limited cases still stop early when the selected alternate template is too far from the target, because label feedback cannot fix a missing layout family.
Sources:
- https://diagrammergpt.github.io/
- https://arxiv.org/abs/2510.25761
## High-value options already available but opt-in
### 4. Larger SAP reference corpus
Status: documented in `external-test-corpus.md`.
Why it fits: SAP Architecture Center is a living platform and now includes current Agentic AI/Joule content. The optional `SAP/sap-btp-reference-architectures` corpus adds older BTP reference patterns that are useful stress cases. External corpora should stay under `.cache/` unless a license-compatible fixture is intentionally promoted.
Expected impact: better selector coverage and clearer evidence about which families need curated templates. It is especially useful for finding ceiling-limited cases where a new SAP-authored template is worth bundling.
Sources:
- https://architecture.learning.sap.com/news/2026/04/22/introducing-the-refreshed-sap-architecture-center
- https://github.com/SAP/sap-btp-reference-architectures
### 5. SAP Architecture Center validation rules
Status: use as semantic review input, not yet an automatic validator.
Why it fits: SAP publishes architecture validation rules, including AI/Joule/MCP-specific constraints. These rules evaluate semantic correctness, while the current local score evaluates visual/style fidelity. They should be added as a second pass after visual fidelity stabilizes.
Expected impact: catches diagrams that look SAP-like but violate SAP architectural guidance, for example MCP paths that bypass Joule or identity-provider flows that bypass SAP Cloud Identity Services.
Source:
- https://architecture.learning.sap.com/docs/validation-rules
## Medium-value options for later
### 6. Screenshot or pixel-level similarity
Status: not implemented.
Why it helps: the current fingerprint score catches structural/style differences in XML, but a rendered screenshot would catch overlaps, visual density, footer/QR placement, and label clipping that XML heuristics can miss.
Why not now: reliable rendering needs draw.io desktop, a containerized diagrams.net export path, or browser automation. It is valuable as a second-stage QA gate, but it adds machine dependencies and runtime cost. Keep this for curated examples and release checks, not every overnight run.
### 7. Graph/node/path alignment metrics
Status: partially approximated by `compare.py`.
Why it helps: research on diagram evaluation models diagrams as graphs and scores node/path alignment. This maps well to architecture diagrams where services are nodes and labeled flows are edges.
Why not now: the `.drawio` corpus does not yet expose a normalized semantic graph for every template. Implementing this properly needs extraction of zones, service cards, icons, and edge endpoints into a canonical graph before scoring.
Source:
- https://arxiv.org/abs/2510.25761
### 8. Embedding-based template retrieval
Status: not implemented.
Why it helps: semantic embeddings could improve template selection when the prompt and SAP reference use different wording.
Why not now: the current failures are mostly visual ceiling/coverage failures rather than pure retrieval failures. BM25-style tags plus visual-neighbor fallback are simpler and explainable. Revisit embeddings when selector candidates are semantically wrong but a good template exists in the corpus.
### 9. Curated domain scenarios from SAP web pages
Status: manual research only.
Why it helps: pages such as SAP AI Golden Path and Agentic AI/Joule reference pages provide current terminology and canonical component grouping.
Why not now: page text should improve descriptions and semantic correctness, but it does not automatically improve visual style unless paired with an existing `.drawio` reference or a new curated template.
Sources:
- https://architecture.learning.sap.com/docs/aigp
- https://architecture.learning.sap.com/docs/golden-path/ai-golden-path/build-and-deliver/build-ai-agents
## Low-value options for this use case
### 10. Direct LLM-generated draw.io XML
Status: avoid.
Why it is low value: draw.io XML contains shape styles, edge metadata, geometry, ids, nested cells, and embedded image data. Direct XML generation tends to produce syntactically fragile or visually off-style diagrams. diagrams.net documents that shapes, connectors, styles, and metadata live in XML, which makes this feasible for deterministic tools but brittle for long free-form model output.
Better alternative: keep XML deterministic. Let the model produce a short structured plan, then apply guarded transformations to a SAP-authored template.
Source:
- https://www.drawio.com/doc/faq/diagram-source-edit
### 11. Generic graph autolayout
Status: avoid for SAP-fidelity generation.
Why it is low value: graph layout engines can make readable diagrams, but they do not know SAP Architecture Center composition, footer rhythm, area nesting, connector semantics, service-card proportions, or grey-circle icon conventions. They are useful only after a semantic graph extractor exists and when no close SAP template exists.
### 12. Fine-tuning or LoRA on SAP diagrams
Status: avoid for now.
Why it is low value: the Apache-2.0 diagram corpus is useful but small, and the target output is editable XML with strict assets. Fine-tuning would be expensive to evaluate and could still invent invalid XML or unusable geometry. Retrieval plus templates plus validation gives better control and is easier to inspect.
## Recommended improvement order
1. Run the bundled leave-one-out suite with structured Ollama output and feedback retries.
2. Rerun only near-misses with `--from-run <run-dir> --case-class near-miss`; this is the only group where extra model attempts are currently likely to help.
3. Review ceiling-limited cases second; add legally compatible SAP templates or improve visual-neighbor selection instead of spending more Ollama attempts.
4. Convert recurring label/selector failures into metadata, prompt rules, or curated template aliases.
5. Run the external SAP corpus only after bundled results stabilize.
6. Add semantic validation rules for SAP AI/Joule/MCP once visual fidelity is consistently high.
7. Add screenshot QA for curated examples and release checks.
+103
View File
@@ -0,0 +1,103 @@
# Canvas layout recipe
The canonical SAP BTP examples use a **1169 × 827** landscape canvas, and this remains the safest default for new L2 diagrams. Architecture Center also contains larger landscape and portrait variants; when you start from one of those templates, preserve its canvas size instead of forcing it back to 1169 × 827.
## Coordinate grid
All placements below are snapped to the **10-px grid**. If you need to nudge something off-grid to make connector centers align, prefer moving by 10 at a time and keep the numbers integer.
```
┌──────────────────────────────────────────────────────────────────────────┐
│ Title (24pt bold #002A86, left-anchored) y=30..60 │
│ Subtitle (14pt #475E75) y=70..95 │
├─────────────┬────────────────────────────────────┬───────────────────────┤
│ User zone │ SAP BTP zone │ On-Premise zone │
│ x≈40..250 │ x≈270..880 │ x≈910..1140 │
│ w=210 │ w=610 │ w=230 │
│ stroke │ stroke #0070F2 fill #EBF8FF │ stroke #475E75 │
│ #475E75 │ │ fill #F5F6F7 │
│ fill white │ │ │
│ │ │ │
│ │ │ │
│ (y≈130..700 working area) │
└──────────────────────────────────────────────────────────────────────────┘
network bar
solid 4 px
at x=890..895
```
The network bar is a **single solid 4-px vertical line** between BTP and On-Prem (`strokeColor=#475E75;strokeWidth=4;endArrow=none`) — not a dashed rectangle. Next to it, a rotated text label `"Network"` (`rotation=-90;fontSize=12;fontStyle=1`) on white background.
## Zone-specific rules
### User / MCP Client zone (left column)
- `x=40, y=120, width=210, height≈580`
- Inline label `"MCP Client"` top-left, 16 pt bold `#475E75`
- Contains: optional user avatar (icon 64×80) + stacked client cards (VS Code, Claude Desktop, Copilot Studio, …) at 180×50 each, 20-px vertical gap
### SAP BTP zone (center column)
- `x=270, y=120, width=610, height≈580`
- Inline label `"SAP BTP"` top-left, 16 pt bold `#00185A`
- SAP logo (`image=img/lib/sap/SAP_Logo.svg`) top-right of the zone at `x=zone.right-90, y=zone.top+15, w=60, h=23` (or top-left at `x=zone.left+10, y=zone.top+10`)
- Inside: an inner white `Subaccount` frame at `x=300, y=170, width=560, height≈450`, stroke `#475E75`, fill `#FFFFFF`. Inside the Subaccount, stack the focus app card + bound services.
- **Bound services** always go in a separate white frame inside the BTP zone, stacked vertically as light-blue tiles (`#EBF8FF` fill, `#0070F2` stroke). Use the bundled service icons for visual grammar.
### On-Premise zone (right column)
- `x=910, y=120, width=230, height≈580`
- Inline label `"On-Premise"` top-left, 16 pt bold `#475E75`
- Typical content: `Cloud Connector` card + one or more backend system cards (S/4HANA, BW/4HANA, ECC)
## Pills on edges
Pills sit at the **midpoint of each edge**, floating above both zones. They share `parent="1"` with the zones (not a zone as parent) — this is why the validator exempts them from sibling-overlap checks.
Short imperative labels:
- `SIGN-IN` (green) — user auth
- `TRUST` (magenta, uppercase) — trust anchor
- `MCP TOOL CALL` (teal) — MCP JSON-RPC over HTTPS
- `mTLS · PP` (green) — Cloud Connector mutual TLS with Principal Propagation
- `OAUTH · JWT` (green) — XSUAA OAuth bearer
One pill per semantic step. Don't stack two pills on the same edge; break the edge into two steps if needed.
## Title band
```xml
<mxCell id="title-main" value="ARC-1 on SAP BTP Cloud Foundry"
style="text;html=1;fontFamily=Helvetica;fontSize=24;fontStyle=1;fontColor=#002A86;align=left;verticalAlign=middle;"
vertex="1" parent="1">
<mxGeometry x="40" y="30" width="1080" height="40" as="geometry"/>
</mxCell>
<mxCell id="title-sub" value="MCP client → XSUAA OAuth → ARC-1 → Cloud Connector → on-prem SAP"
style="text;html=1;fontFamily=Helvetica;fontSize=14;fontColor=#475E75;align=left;verticalAlign=middle;"
vertex="1" parent="1">
<mxGeometry x="40" y="70" width="1080" height="30" as="geometry"/>
</mxCell>
```
Keep the title under ~60 chars and the subtitle under ~100. Longer strings need wrapping which throws the coordinate math off.
## Legend
**Do not draw a legend inside the canvas.** The SAP ref-arch convention is:
- Edge pills are self-explanatory via color + label
- The flow narration below the embedded PNG (in Markdown / Confluence) spells out what each color means
When a selected SAP Architecture Center template already uses inline pills and no separate legend block, preserve that design. This matters for templates such as `ac_RA0029_AgenticAI_root.drawio`, where adding a large bottom legend forces the diagram away from the SAP reference layout and usually lowers the corpus score. If the user asks for a legend in that case, keep the inline pill labels and provide the legend explanation in the flow narration outside the canvas.
If the user explicitly asks for an inside-canvas legend, put it at `y≈730`, full-width, a single neutral frame with two rows (lines + blocks).
## Aspect ratio & margins
The 1169 × 827 canvas has a ~1.41 aspect ratio (A4 landscape). Leave:
- **40-px margin** on left and right (content lives at 40..1140)
- **120-px top margin** for title + subtitle
- **~100-px bottom margin** for the legend / whitespace
Zones fill the middle band evenly. Three zones → widths roughly `210 | 610 | 230` adding to 1050 with three 20-px gutters.
+72
View File
@@ -0,0 +1,72 @@
# SAP BTP Solution Diagram levels
The SAP BTP Solution Diagram Guidelines document **three levels — L0, L1, L2**. L3 is mentioned once in passing (`L0 — L2/L3 presentations`) but is **not specified** anywhere in the official guideline. Treat L3 as unofficial; default to **L2** when the user doesn't specify.
Source for everything below: `guideline/docs/solution_diagr_intro/big_picture.md`.
## The three documented levels
| Level | Audience | Shows | Hides | Typical shapes |
|-------|----------|-------|-------|----------------|
| **L0 — Marketing / overview** | Business roles, sales, business architects, enterprise architects, IT managers, IT analysts, CTOs. *("simply require an overview … rudimentary technical knowledge")* | One concept per box. Logos, neutral arrows, outcome wording. **No legend required**, but a short description is recommended. | Anything technical. | 36 hero cards, simplified flows. |
| **L1 — Conceptual** | Enterprise / solution architects, SAP consultants, product managers, presales, use case owners, DC mission owners. *("strong technical acumen and interest")* | Named SAP services, trust zones, coarse data flow. | Protocol names, hostnames, auth details. | Service cards grouped by zone (BTP vs on-prem), plain arrows. |
| **L2 — Logical / technical** *(default)* | SAP solution architects, cloud architects, product managers, business + dev roles, consultants, technical presales. *("extensive technical understanding, requiring detailed information")* | Services, accounts, roles, protocols, trust/auth pills, **legend mandatory**. | Hostnames, subnets, cert names. | Full 34 zone landscape with semantic pills on edges. |
Verbatim audience quotes from `big_picture.md`:
> "**L0 diagrams target individuals who simply require an overview.** They typically possess just rudimentary technical knowledge and interest."
>
> "**L1 diagrams target Individuals who possess a strong technical acumen and interest.** They often participate in technical decision-making processes."
>
> "**L2 diagrams target individuals with an extensive technical understanding, requiring detailed information to inform their decision-making process.**"
## L0 specifics
> "The granularity of diagrams should be adjusted according to the expertise of the intended audience. For example, the broadest level of detail, Level 0, caters mainly to individuals with basic technical skills, such as those in business roles."
>
> "A representative example would be a high-level solution diagram featuring BTP Services and simplified flows, without complex technical details. **In such diagrams, connectors maintain neutrality** and the content is streamlined to essentials, **eliminating the necessity for a legend, but a short description is recommended.**"
`big_picture.md`
L0 implications for the skill:
- Connector colors → all neutral grey (`#475E75`); no semantic auth/trust/authz colors.
- No edge pills.
- ≤ 6 service cards on canvas.
- Skip the legend block.
- Add a short description text element below the canvas instead.
## L1 specifics
- Group services by area (BTP, On-Prem, Third Party). Solid arrows for direct flow.
- Named SAP services with the grey-circle service icon.
- Optional: numbered step indicators (1 → 2 → 3) along the main flow.
- Legend optional but recommended.
## L2 specifics (the default for this skill)
- All four zones (User, BTP, On-Prem, Third-Party) where applicable.
- Numbered semantic pills on edges (TRUST, SIGN-IN, OAUTH · JWT, mTLS · PP, MCP TOOL CALL, …).
- Legend **mandatory** in principle — explains pill colors and line styles. If the selected SAP reference template has no separate legend block but already uses labelled inline pills, preserve that template structure and put the legend explanation in the generated flow narration instead of adding a new bottom band.
- Inline service icons (grey-circle variant only — see `diagr_comp/icons.md`).
> "Including a legend in each diagram is crucial to clarify these meanings."
`foundation.md`
## What about L3?
L3 is **not documented**. If a user explicitly asks for L3 (typical signals: hostnames, CIDRs, cert names, CIDR blocks, NAT gateway IPs, "production deployment", "rollout" details), proceed but produce an L2 with extra annotations rather than a different visual style. Tell the user the diagram is "L2 with physical annotations" — don't claim it follows an SAP-defined L3 spec.
## Canvas & tab naming
- Use `pageWidth="1169" pageHeight="827"` for new diagrams unless the selected SAP reference template uses a different size. The 2026 corpus includes larger landscape and portrait variants; preserving the chosen template's canvas scores better than normalising every diagram to one size.
- `grid="1" gridSize="10"` — show the grid while authoring, snap everything to 10 px.
- `<diagram name="…">` tab stem matches the output filename, suffixed with the level: `Product_Name_L2`, `ARC1_BTP_Deployment_L2`.
- `page="1"`, `pageScale="1"`, `math="0"`, `shadow="0"`, `background="none"` (default white).
## Flow narration
Numbered flow steps (1 → 2 → 3 …) are drawn as **small coloured circular pills on the diagram** (see `shapes-and-edges.md`). The full prose ("Step 1: User signs in to SAP Cloud Identity Services…") lives **below the embedded image** in the host document (Markdown / Confluence), **not** in a text block inside the canvas. This mirrors `architecture.learning.sap.com` — the canvas stays clean, the page carries the narrative.
When the output is a standalone `.drawio` (no host document), the skill prints the flow narration to stdout at the end of the run so the user can paste it into their docs.
+230
View File
@@ -0,0 +1,230 @@
# The realistic SAP-diagram workflow
This skill is an **authoring assistant**, not a one-shot generator. After
weeks of iteration on the LLM-only loop, historical leave-one-out
evaluation on an earlier 63-template bundle plateaued quickly. Most
remaining failures were *ceiling-limited*: the closest available SAP
template was geometrically too different from the target, and no amount
of label edits could close the gap. The current 71-template bundle
improves coverage, but the core lesson remains: use the closest SAP
template and edit it deliberately.
The honest conclusion: **producing a polished, SAP-Architecture-Center-
quality diagram requires manual editing for ~⅔ of scenarios.** That is
not a defect of the skill; it matches how SAP architects actually work.
The skill exists to make that manual loop as fast and disciplined as
possible.
## Why pure LLM generation hits a ceiling
| Stage | What's automatable | What requires human judgment |
|---|---|---|
| Template selection | yes — `select_reference.py` ranks 71 templates by metadata + visible labels | yes when the prompt is ambiguous or the right template isn't bundled |
| Label rewrites | yes — Ollama's safe label edits | semantic correctness ("does this XSUAA actually call that destination?") |
| Adding/removing services | partially — `extract_icon.py` drops the right icon at coordinates | layout decisions: which zone, where in the zone, what neighbours |
| Connector geometry | partially — autofix snaps to grid | alignment to anchor points, edge routing around other shapes |
| Visual polish | no | the last 20% of pixel-perfection |
The `compare.py` fingerprint score measures **structural style** (palette,
fonts, zone count, pill count, label tokens). It does not measure
**visual correctness** (Joule beside BTP vs nested inside BTP, network
divider drawn as a thick grey vertical line, footer band matching SAP's
template). For that you need to look at the rendered diagram.
## The fast manual loop (15-30 minutes per diagram)
```
1. plan (~2 min) describe scenario, level, zones, flow
2. scaffold (~10 sec) scaffold_diagram.py "<request>" --out file.drawio
3. inspect (~1 min) open template_browser/index.html if uncertain about choice
4. edit (~10-20 min) open file.drawio in draw.io desktop, surgically relabel
5. validate (~5 sec) autofix.py --write && validate.py
6. compare (~5 sec) render_compare.py reference.drawio file.drawio --open
7. iterate repeat 4-6 until visual review looks right
```
Each step has tooling support so the only attention-heavy part is step 4.
## Tools available for each step
### Step 1 — plan
Write the description in 5-10 lines: level (L0/L1/L2), zones (BTP,
On-Prem, Joule, Third-Party, Network divider, Cloud Solutions), services
in each zone, numbered flow with pill colors, accent app.
### Step 2 — scaffold (mandatory first action)
```bash
python3 scripts/scaffold_diagram.py \
"<the user's full diagram request>" \
--out docs/architecture/my-diagram.drawio
```
The script ranks the 71 bundled SAP templates against the request,
copies the best match to the destination, and prints the alternates.
Use `--template <filename>` to pin a specific template, `--dry-run` to
inspect candidates without copying, `--diagram-name "<title>"` to rename
the diagram page after copy.
### Step 3 — browse templates visually (optional)
```bash
python3 scripts/template_browser.py
open .cache/template-browser/index.html
```
Pre-renders all 71 templates into a clickable thumbnail grid with
filter, domain badges, and the `scaffold_diagram.py --template` command
for each. Useful when the selector is unsure or the prompt is vague.
### Step 4 — edit in draw.io desktop
Open the scaffolded file in draw.io desktop. Make these edits:
- **Title and subtitle** — match your scenario.
- **Service-card labels** — replace template's example service names with
yours. Use exact SAP product names ("SAP S/4HANA Cloud", not
"S/4HANA").
- **Icons** — swap or add via `scripts/extract_icon.py "Destination Service"
--x 600 --y 300 --w 80 --h 96 --id svc-dest`.
- **Connectors** — adjust source/target if you swapped services. Keep
the SAP-mandated colors: trust=#CC00DC pink, auth=#188918 green,
authorization=#5D36FF indigo, structural=#475E75 slate.
- **Pills** — relabel from the canonical SAP vocabulary
(TRUST/Authenticate/Authorization/A2A/MCP/ORD/HTTPS/OData/REST/...).
Avoid novelty verbs like PROMPT/ROUTE/CONTEXT/DELEGATE.
**Do NOT touch:** canvas size, zone hierarchy, network divider, SAP
logos, footer band, identity flow placement. Those carry the SAP visual
identity; preserving them is what keeps the score above 90.
### Step 5 — autofix + validate
```bash
python3 scripts/autofix.py --write docs/architecture/my-diagram.drawio
python3 scripts/validate.py docs/architecture/my-diagram.drawio
```
Autofix repairs the mechanical issues (grid snap, hex case, missing
`absoluteArcSize=1`, wrong `strokeWidth`, non-Helvetica fonts, XML
comments). Validate catches the rest (bent arrows, label overflow,
sibling overlap, edge labels missing `labelBackgroundColor`,
*off-vocabulary pill verbs, dark page backgrounds, multi-logo
over-use*).
### Step 6 — render and side-by-side compare
```bash
python3 scripts/render_compare.py \
assets/reference-examples/ac_RA0029_AgenticAI_root.drawio \
docs/architecture/my-diagram.drawio \
--out-dir .cache/review/agentic-ai/ \
--open
```
Outputs `review.html` with reference + candidate rendered side by side,
score breakdown, and **actionable suggestions mapped to the lowest-
scoring fingerprint dimensions**. Open it in the browser. The visual
review surfaces what the structural fingerprint can't.
### Step 7 — corpus score
```bash
python3 scripts/score_corpus.py --min-score 90 docs/architecture/my-diagram.drawio
```
Final gate: the candidate must score ≥ 90 against at least one bundled
SAP reference. If lower, look at the `render_compare.py` review HTML
and address the suggestions.
## When manual editing is *not* needed
A few scenarios pass the loop on the first scaffold, no editing
required:
| Scenario | Template that wins | Why |
|---|---|---|
| Generic Agentic AI on BTP | `ac_RA0029_AgenticAI_root.drawio` | Joule + BTP + Cloud Solutions structure already present |
| Task Center central inbox | `btp_SAP_Task_Center_L2.drawio` | Canonical layout |
| OData via App Router + Private Link | `ac_RA0014_OData_AppRouter_PrivateLink.drawio` | Specific RA, narrow scenario |
| SAP IAS authentication L2 | `btp_SAP_Cloud_Identity_Services_Authentication_L2.drawio` | Direct match |
For these, scaffold + run the validators is usually enough. Run
```bash
python3 scripts/eval_corpus.py inventory --references assets/reference-examples
```
to see the full bundled list.
## When manual editing *is* needed (and how much)
- **ceiling-limited families** — RA0027 SIEM/SOAR/ETD, RA0028
SuccessFactors module integration, RA0013 BDC AI Core, RA0023 DevOps,
RA0029 Embodied AI Agents. Expect 15-30 min of manual editing per
diagram unless you're willing to bundle additional templates from
upstream SAP repos.
- **near-miss scenarios** — eval runs may mark cases as near-miss
(typically high-80s score). Often a 5-minute label tweak in draw.io
desktop pushes these above 90.
- **prompts the selector can't resolve** — when the prompt mentions
multiple equally-relevant scenarios (e.g. "Joule with Federated ML
via Cloud Connector"), the human picks the right template by browsing
`template_browser/index.html` and forces it with `--template`.
## How to expand template coverage (one-time effort)
The single highest-leverage way to improve the hardest cases is to
**bundle more SAP templates that fill ceiling-limited families**.
Two upstream sources, both Apache-2.0:
1. <https://github.com/SAP/sap-btp-reference-architectures> — 32
editable .drawio files; many cover scenarios the bundled templates miss
(specifically: industry-specific integrations, advanced data flows).
2. <https://github.com/SAP/architecture-center> — already curated; we
have 52 of these. The remainder are mostly variants of bundled ones.
The mechanical step:
```bash
git clone --depth 1 https://github.com/SAP/sap-btp-reference-architectures.git \
.cache/external/sap-btp-reference-architectures
# Score the external corpus to identify high-value additions
python3 scripts/eval_corpus.py inventory \
--references .cache/external/sap-btp-reference-architectures
```
For each scenario where our loop is ceiling-limited, look in the
external corpus for a closer-match template, then copy it into
`assets/reference-examples/` and add metadata to
`assets/reference-examples/template-metadata.json`.
## What NOT to do
- **Don't run `eval_corpus.py run` overnight expecting more passes.**
The plateau is real. Code/template changes are what move the needle,
not LLM retries.
- **Don't try to write `.drawio` XML by hand or have an LLM emit it
from scratch.** The XML is dense, draw.io has many subtle requirements
(UserObject ids, layered mxGeometry, etc.), and hand-written diagrams
consistently fall to ~50/100 fingerprint score.
- **Don't add features that the SAP reference doesn't have.** Adding a
bottom legend block to a template that doesn't have one *lowers* the
fingerprint score because it adds shapes/colors/cells the reference
lacks.
## Realistic time budget per diagram
| Diagram complexity | Time | Source |
|---|---|---|
| Easy: same-family template available, minor relabel | 5-10 min | scaffold + 2-3 label edits + validate |
| Medium: same-family template, many service swaps | 15-25 min | scaffold + 5-10 label edits + icon swaps + validate + iterate |
| Hard: ceiling-limited family, structural rework | 30-45 min | scaffold + manual zone restructure in draw.io + iterate |
| Very hard: scenario not represented in corpus | 60+ min | bundle a new template first, then proceed |
Compare to authoring from scratch with the official SAP starter kit:
typically 60-120 minutes for a polished L2 diagram. The skill cuts that
roughly in half by removing the boilerplate and gating quality.
+182
View File
@@ -0,0 +1,182 @@
# How this skill stays close to the SAP standard
A claim like "this plugin produces SAP-Architecture-Center-style diagrams" is only believable if there's an empirical way to measure it. This file documents the comparison harness, the fidelity numbers, and the workflow that produces high-fidelity output.
## The fingerprinting harness — `scripts/compare.py`
`compare.py` extracts a structural + style fingerprint from any `.drawio` file and computes a similarity score against another `.drawio` file. The fingerprint covers:
| Dimension | What's checked |
|-----------|----------------|
| **Canvas** | `pageWidth × pageHeight` — should match the selected SAP template; `1169 × 827` is the default for new L2 diagrams |
| **Page background** | `pageBackgroundColor` / `background` attribute — SAP diagrams use white/transparent. A non-white candidate scores 0 on this metric. |
| **Counts** | total cells, vertices, edges, inline-SVG icons, legacy `mxgraph.sap.icon` stencil count, pills (`arcSize=50`) |
| **Zone hierarchy** | nesting depth of zone cells — catches structural mistakes like nesting a focus zone inside another one when the SAP reference puts them side by side (Joule-inside-BTP bug) |
| **Palette** | the set of hex colors in the file (Jaccard similarity) |
| **Edge palette** | the set of `strokeColor` values *actually used on edges* — catches semantic color swaps (green↔magenta) that the global palette set hides |
| **Pill vocabulary** | how many pills use canonical SAP verbs (TRUST/Authenticate/A2A/MCP/ORD/HTTPS/OData/REST/SAML2/OIDC/...) vs novelty verbs (PROMPT/ROUTE/CONTEXT/...) |
| **Fonts** | `fontFamily` values used (subset = full credit) |
| **Stroke widths** | the set of `strokeWidth` values |
| **Polish** | presence of `absoluteArcSize=1`, `labelBackgroundColor=default`, grid-snap rate |
| **Labels** | visible label count and label-token overlap, so wrong-target templates no longer score as perfect |
The score is a weighted blend of these dimensions; 100 means the two files have an identical fingerprint, 0 means nothing in common.
```bash
python3 scripts/compare.py reference.drawio candidate.drawio
python3 scripts/compare.py --score reference.drawio candidate.drawio # one-line score
python3 scripts/compare.py --json reference.drawio candidate.drawio # machine-readable
```
Calibration:
| Pair | Expected score |
|------|----------------|
| File compared to itself | 100 |
| Different SAP-published L2 diagrams (e.g. IAS Authentication vs Task Center) | 8085 |
| L0 of a scenario vs L2 of the same scenario | 6070 |
| Hand-crafted candidate built from scratch | 5055 |
| Candidate built by **copying a reference + relabeling** (the recommended workflow) | 95100 when the target scenario stays close |
The big gap between "from-scratch" (≈50) and "from-template" (≈100) is the empirical justification for the SKILL.md rule: **never draw from scratch — always start from a reference template.**
## The full quality loop
```
description ┐
┌──────────────────────────────────────────────────────────┐
│ Step 1 — scaffold from a SAP reference template │
│ scaffold_diagram.py "<request>" --out <file>.drawio │
│ Ranks 71 bundled SAP templates and copies the best one │
│ (uses metadata aliases/tags + visible draw.io labels │
│ + the "primary": true flag for canonical umbrella refs)│
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ Step 2 — surgical relabel for the new scenario │
│ Title, zone labels, service-card values; preserve │
│ canvas size, zone hierarchy, edges, pills, legend, │
│ network divider, SAP logos, footer │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ Step 3 — autofix.py --write │
│ Snap grid, normalise hex case, fix arcSize, strokeWidth│
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ Step 4 — validate.py │
│ Errors: bent arrows, label overflow, sibling overlap, │
│ missing geometry, duplicate ids, │
│ dark/branded page background │
│ Warnings: off-palette, off-grid, missing label-bg, │
│ off-vocabulary pill verbs, multi-logo over-use │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│ Step 5 — score_corpus.py across all bundled references │
│ Best score should be ≥ 90 if template drift is low │
│ If < 90, compare.py shows where the structure drifted │
│ (canvas, page bg, zone depth, edge palette, pill vocab)│
└──────────────────────────────────────────────────────────┘
final .drawio + flow narration
```
For `eval_corpus.py run --exclude-target-template`, the exact target is removed from the selector pool. The harness therefore adds an explicit primary visual-neighbor hint computed with `compare.py` fingerprints. This is not used for normal production generation; it makes the leave-one-out research loop test the closest available SAP layout instead of an arbitrary semantic neighbor.
The harness also records the selected-template target baseline for every case. This is the score of the alternate template before any model label plan is applied. In overnight leave-one-out runs, low baseline scores are a ceiling signal: label edits can improve content overlap, but they cannot invent the target's canvas rhythm, vertex count, zone proportions, edge topology, or service-icon density. Reports classify these as:
- `near-miss`: failed, but within `--retry-margin` of `--min-score`; retrying, adding metadata, or improving label replacement may help.
- `ceiling-limited`: failed below the retry floor; add a closer SAP sibling template or implement geometry-aware generation before spending more model time.
- `model-failure` / `validator-failure`: fix the generation or validation error first.
The default `--retry-margin 8` means a `--min-score 90` run stops retrying cases below 82. This reflects the observed overnight loop: most large gaps were template-coverage gaps, not stochastic model failures.
## Worked example — `examples/iam-arc1-mcp-l2.drawio`
The bundled `examples/iam-arc1-mcp-l2.drawio` was produced by:
1. Picking `btp_SAP_Cloud_Identity_Services_Authentication_L2.drawio` as the closest reference template (it's the canonical IAM-on-BTP diagram).
2. Surgically swapping ~5 labels for an ARC-1 MCP scenario:
- title: `Authentication with SAP Cloud Identity Services``ARC-1 MCP Server - Authentication on SAP BTP`
- subtitle: `Recommended authentication flows…``Claude Desktop / Copilot Studio MCP clients calling ARC-1 over XSUAA OAuth, reaching on-prem SAP via Cloud Connector with Principal Propagation`
- card label: `SuccessFactors``ARC-1 MCP Server`
- zone label: `SAP BTP Applications -IAM based on SAP Cloud Identity Services``SAP BTP Applications - ARC-1 MCP based on SAP Cloud Identity Services`
- card label: `Mobile/Desktop``Claude Desktop / Copilot Studio`
3. Running `autofix.py --write` (resulted in 436 mechanical fixes — geometry snap, hex case, arc size, font normalisation, comment strip).
4. Running `validate.py` — exit 0.
5. Running `compare.py` against the original reference — **scored 96.6/100** with the target-aware label-token scorer.
6. Running `score_corpus.py --min-score 90` across the bundled templates — best score **96.6/100**.
This proves the workflow: with a few hand-edits, you preserve SAP's visual structure while the scorer still notices intentional scenario-label changes.
## Why the validator + autofix matter
Without these gates, a hand-crafted candidate scored **~52** even when it followed the rules in `references/`. The biggest contributors to the gap:
- Bent `orthogonalEdgeStyle` arrows (centers not aligned)
- Sparse zones with too few service cards (low vertex / icon count)
- Off-palette hex from improvising "close-enough" colors
- Missing `labelBackgroundColor=default` on edge labels
- **Dark / branded page background** (now a hard validator error)
- **Off-vocabulary pill verbs** like `PROMPT`, `ROUTE`, `CONTEXT`, `DELEGATE` — replaced with `TRUST`, `Authenticate`, `A2A`, `MCP`, `ORD`, `HTTPS`, `OData/REST`, `SAML2/OIDC`
- **Wrong zone hierarchy** (e.g. nesting Joule inside the BTP zone when SAP places it as a sibling) — now penalised by the `zone_depth` metric in `compare.py`
`validate.py` catches all of these before the diagram is shown to the user. `autofix.py` repairs the mechanical ones automatically.
## Limitations
The fingerprint compares **structure, style, and visible label overlap** — not full semantic correctness. Two diagrams with similar fingerprints can still encode different architectures. The score validates "looks SAP-styled and uses similar target labels" but doesn't validate "the architecture actually works".
Also, the validator can't check:
- **One-SAP-logo rule** — multiple logos count as warnings only when they appear inline in the XML
- **Semantic correctness of arrows** — green / pink / indigo edges are colored correctly, but whether *that specific edge* should be authentication, trust, or authorization is a judgment call left to the author
- **Legend completeness** — presence of a legend block is checked; whether it accurately covers all colors in the diagram is not
For those, manual review against `references/do-and-dont.md` remains necessary.
## Corpus scoring
`score_corpus.py` wraps `compare.py` and ranks the candidate against every bundled `.drawio` reference:
```bash
python3 scripts/score_corpus.py --top 5 --min-score 90 my-diagram.drawio
```
Use this as the final fidelity gate. A good template-derived diagram should have:
| Signal | Target |
|---|---|
| Best target/corpus score | `>= 90` |
| Chosen-template pairwise score | `>= 90`, ideally `95-100` |
| Validator errors | `0` |
| Off-palette / line-style drift | explainable or fixed |
For research runs against SAP's full public corpus, clone the upstream repositories and pass them as reference directories:
```bash
python3 scripts/score_corpus.py \
--references /path/to/SAP/btp-solution-diagrams \
--references /path/to/SAP/architecture-center \
my-diagram.drawio
```
See `corpus-findings.md` for the 2026 snapshot that motivated the current 71-template bundle.
## How to add new reference templates
1. Drop a `.drawio` file in `assets/reference-examples/` (any name)
2. Confirm it's Apache-2.0 / MIT / your own work
3. Add an entry to `assets/NOTICE.md` if the source is third-party
4. Re-score your test diagrams against the new template — `score_corpus.py --top 10`
The skill picks the highest-scoring reference automatically when the user describes a scenario, so adding more references improves quality monotonically.
+152
View File
@@ -0,0 +1,152 @@
# Nudge workflow — iterative LLM ↔ scripts loop
Audience: Cursor's Agent (Claude Sonnet / GPT) or Claude Code working on a single diagram with a human in the loop.
The goal of this workflow is **not** to one-shot a perfect diagram. It is to converge on one through small, reviewable edits — guided by the candidate PNG, the SAP target PNG, and a scored breakdown that names what to fix next.
## The 3-tool loop
```
┌───────────────────┐
│ user nudge or │
│ initial prompt │
└─────────┬─────────┘
┌───────────────────────────┐
│ LLM picks ONE small edit │
│ via the Edit / Write tool │
└─────────────┬─────────────┘
┌───────────────────────────┐
│ scripts/autofix.py --write│ ← mechanical clean-up
└─────────────┬─────────────┘
┌───────────────────────────┐
│ scripts/iterate.py │ ← renders PNG, scores,
│ <candidate> │ prints next-step list
│ [--target <ref>] │
└─────────────┬─────────────┘
┌───────────────────────────┐
│ LLM reads: │
│ candidate.png │ ← uses its vision tool
│ reference.png │
│ suggestions list │
└─────────────┬─────────────┘
score ≥ 90 ────┼──── score < 90
│ │ │
▼ │ ▼
PASS — done │ pick next ONE edit
│ (loop)
await user nudge
("move Joule to the left",
"add MCP Gateway in BTP",
"use teal pills for MCP")
```
## Key rules for the LLM
1. **One edit per iteration.** Resist the urge to fix five things at once. The score breakdown ranks dimensions by weighted impact — pick the top suggestion. Always re-run `iterate.py` after each edit so you can see the score delta.
2. **Always look at the PNGs.** The text breakdown will tell you "icons missing", but the PNG tells you *where* to put them. After every `iterate.py` run, open both `candidate.png` and `reference.png` with your vision/read tool. Reason about them visually, not only by hex value.
3. **Watch the delta.** `iterate.py` reports `↑+3.2` or `↓-1.5` since the previous run. If you went down, your last edit was wrong — undo it (your text editor's history or `git diff`) before trying something else. Don't pile bad edits on top of bad edits.
4. **Stop at PASS.** Once the score is ≥ 90 and the user has given no further nudge, stop. Don't keep editing in pursuit of 100 — you'll start replacing intentional differences (the candidate's scenario labels) with template defaults.
5. **When the user nudges in natural language**, treat it as a single edit step. "Make Joule purple" → find the Joule zone cell → change `fillColor` and `strokeColor` to `#F1ECFF` / `#5D36FF` → autofix → iterate. Don't conflate the nudge with other improvements you also see.
6. **Ask the user before destructive moves.** Examples that need confirmation: deleting a zone the user explicitly added, swapping the chosen template for a different one, regenerating the file from scratch. A nudge is small; if your only path to compliance is a rewrite, ask first.
## What `iterate.py` gives you
Every run prints a structured block. Read it carefully — every line is there to direct your next move:
```
─── SAP DIAGRAM ITERATION ───
candidate : docs/architecture/foo.drawio
target : ac_RA0029_AgenticAI_root.drawio (corpus fingerprint match)
score : 78.4 / 100 ↑+3.2 since last iteration
pass gate : 90.0 (BELOW — keep iterating)
📷 Read these images with your vision tool to plan the next edit:
candidate : .cache/sap-architecture-iter/foo/foo.candidate.png
reference : .cache/sap-architecture-iter/foo/ac_RA0029_AgenticAI_root.reference.png
side-by-side HTML : .cache/sap-architecture-iter/foo/review.html
⚠ Lowest-scoring dimensions (fix worst first):
zones 45.0% ████░░░░░░
zone_depth 50.0% █████░░░░░
icons 55.0% █████░░░░░
pill_vocab 60.0% ██████░░░░
...
✏ Next concrete edit (do ONE, then re-run iterate.py):
1. Add 4 zone container(s). Reference has 8 zones; you have 4. Use rounded
rect with arcSize=16, strokeWidth=1.5, and a top-left bold inline label.
2. Add 6 BTP service icon(s). Use scripts/extract_icon.py
"<service-name>" --x <X> --y <Y> --id <id> to get a ready mxCell.
3. Replace 2 novelty pill verb(s). Allowed: TRUST, Authenticate, ...
...
✓ Score improved +3.2. Keep going.
```
## Translating nudges into edits
| User nudge | What you should do |
|---|---|
| "Make Joule purple" | Find the Joule zone cell (`<mxCell value="Joule"...>` or similar). Set `fillColor=#F1ECFF;strokeColor=#5D36FF`. autofix → iterate. |
| "Add MCP Gateway in BTP" | Look at the reference PNG to see where MCP Gateway goes. Duplicate an existing card (e.g. Custom Agents), change its label to `MCP Gateway`, use `extract_icon.py "Integration Suite"` for the icon, and put it inside the BTP zone parent. autofix → iterate. |
| "Move System Trigger to bottom-left" | Find the System Trigger cell, edit its `<mxGeometry x="..." y="...">` so x is small and y is high. Keep on 10-px grid. autofix → iterate. |
| "Use teal pills for the MCP flow" | Find the MCP-flow pill cells (likely `arcSize=50` near the cards you want connected). Set `fillColor=#DAFDF5;strokeColor=#07838F` on each. autofix → iterate. |
| "It looks too crowded" | Compare zone counts vs reference. If you have more zones than ref, remove the least-essential one. If geometry density is too high, increase canvas pageWidth/pageHeight (rare). autofix → iterate. |
| "I don't like this template, try a different one" | This is the destructive case — ask the user to confirm. If yes: `scaffold_diagram.py --template <other>.drawio --out <same-destination> --force`. The file will be replaced. |
## Common loops
### Initial-creation loop (after fresh scaffold)
1. Run `scaffold_diagram.py "<request>" --out foo.drawio` — produces a SAP-anchored starting point at ~100% structural similarity to its source template.
2. Run `iterate.py foo.drawio` — first iteration; it picks the source template as target automatically and reports near-100 score because edits haven't started.
3. Make label edits to fit the user's scenario (rename `SuccessFactors``ARC-1`, etc.).
4. After every 1-3 small edits, run `autofix.py --write foo.drawio && iterate.py foo.drawio`.
5. Loop until either the user is satisfied or score is ≥ 90.
### User-nudge loop (later refinement)
1. User says: "Joule should be on the left, not in the middle."
2. Read `candidate.png` from the last iterate run to see current Joule placement.
3. Read `reference.png` to understand the canonical SAP layout.
4. Make ONE edit: change Joule zone's `<mxGeometry x="..."` to a smaller value.
5. Run `autofix.py && iterate.py`.
6. Confirm with the user that the placement now matches their intent — they may want it even further left, or a different zone moved instead.
### Recovery loop (you regressed)
1. Last `iterate.py` showed `↓-2.5` — your edit broke something.
2. Use `git diff foo.drawio` (or your editor's undo) to inspect the exact change that hurt the score.
3. If the change was off the user's nudge path, undo it and try a smaller, more targeted version.
4. If the change WAS on the user's nudge path but the structural cost is high, explain the tradeoff to the user and ask whether they want the visual change or the score.
## When to stop
The loop terminates when ANY of these are true:
- `iterate.py` reports `score >= 90` AND the user has given no follow-up nudge.
- The user explicitly says "good", "stop", "ship it".
- Five consecutive iterations move the score by less than ±0.5 points (you're at a plateau — better to ask the user what to nudge next than to keep guessing).
- The user starts asking for changes that aren't SAP-style (custom dark backgrounds, novelty pill verbs the validator rejects). In that case acknowledge the tradeoff once and proceed.
## What `iterate.py` does NOT do
- It does not edit the diagram for you. You (the LLM) make all edits.
- It does not run Ollama. The LLM in Cursor / Claude Code IS the model — `iterate.py` just feeds it visual + scored feedback.
- It does not roll back automatically. Use git or your editor's undo for that.
- It does not change the target template mid-loop unless you re-invoke with `--target`. If you scaffolded from template A and are 30 iterations in, switching to template B will reset the score baseline.
+192
View File
@@ -0,0 +1,192 @@
# SAP Horizon palette & typography
Every value in this file is sourced from the **official SAP BTP Solution Diagram Guidelines** at https://github.com/SAP/btp-solution-diagrams/tree/main/guideline. Quotes are verbatim. Hex values are normalised to uppercase (autofix.py will normalise any surviving lowercase).
## The atomic design system
Quoted from `guideline/docs/btp_guideline/atomic.md`:
> "Atoms are the smallest elements in this case the basic elements such as colors, line styles, icons, and text"
>
> "Molecules are elements that consist of atoms. A Molecule refers to any element that uses the basic colors and lines, for example, an arrow that is red and dashed."
>
> "Organisms are groups of Molecules. This could be grouped elements such as a typical shape with text and connectors, or even a whole diagram."
This skill emits at the organism level — composed zones with cards, connectors, and pills — but every value below is at the atom level so that nothing improvises.
## Color philosophy
> "Horizon is the default visual style for SAP Products. Its color balance helps to draw the user's attention to the essential information and functions. It also promotes a distinct and consistent look throughout all products. **This also applies to diagrams.**"
`foundation.md`
The skill never invents palette values. The `validate.py` check warns on any hex outside this file.
## Primary palette — the everyday colors
| Role | Border | Fill | Source |
|------|--------|------|--------|
| **SAP / BTP area** | `#0070F2` | `#EBF8FF` | `foundation.md` |
| **Non-SAP area** | `#475E75` | `#F5F6F7` | `foundation.md` |
| **Title text** | — | — | `#1D2D3E` (`foundation.md`) |
| **Body text** | — | — | `#556B82` (`foundation.md`) |
> "Blue is the standard, grey for non-sap elements and the Accent colors are for highlighting certain areas."
>
> "It is not recommended to use the colors too heavily, they can overpower the diagram."
`diagr_comp/areas.md`
## Semantic palette — status / meaning
> "Semantic colors can be used to represent a negative, critical, positive, neutral, or information status."
`foundation.md`
| Role | Border | Fill |
|------|--------|------|
| **Positive** (authentication, mTLS, success) | `#188918` | `#F5FAE5` |
| **Critical** (warnings, partial outage) | `#C35500` | `#FFF8D6` |
| **Negative** (errors, blocked) | `#D20A0A` | `#FFEAF4` |
## Accent palette — sparingly, for emphasis
> "Secondary colors can be applied to accentuate important elements. They make a vivid contribution to the overall UI and **should be used sparingly.**"
`foundation.md`
| Role | Border | Fill |
|------|--------|------|
| **Teal** (MCP, custom emphasis) | `#07838F` | `#DAFDF5` |
| **Indigo** (authorization flows, focus app) | `#5D36FF` | `#F1ECFF` |
| **Pink** (trust flows) | `#CC00DC` | `#FFF0FA` |
The semantic mapping for connectors is fixed (see `shapes-and-edges.md`):
> "To harmonize certain reoccurring flows a use of the following standards is recommended:
> - Trust Flows are usually pink
> - Authentication flows are usually green
> - Authorization flows are usually indigo
> - Firewalls and Network barriers are thick grey lines"
`lines_connectors.md`
## Observed Architecture Center variants
The 2026 corpus profile in `corpus-findings.md` found these additional SAP-authored variants in real `.drawio` files. Treat them as accepted inherited values, not as colors to introduce casually:
| Family | Observed variants |
|---|---|
| SAP blue | `#00185A`, `#002A86`, `#0057D2`, `#2395FF` |
| SAP light blue fills | `#D1EFFF`, `#CCDDFF`, `#EAF8FF`, `#EDF8FF`, `#ECF8FF` |
| Neutral greys | `#475E74`, `#475F75`, `#5B738B`, `#D5DADD`, `#EDEDED`, `#EDEFF0` |
| Positive green | `#266F3A` |
| Indigo | `#470BED`, `#7F00FF` |
Generated diagrams should still prefer the guideline palette above. The validator accepts these variants because SAP's own Architecture Center files use them.
## Color proportion — the area-color rule
> "It is not recommended to use the colors too heavily, they can overpower the diagram."
The published SAP examples observe roughly:
- **~70%** primary blue (SAP / BTP zones, service cards) and neutral grey (non-SAP)
- **~20%** white inner frames (subaccount, runtime container, focus app)
- **~10%** accent (one or two colored zones / pills max)
Don't paint two zones in different accent colors competing for attention. If two flows need to be highlighted, use one accent and keep the rest neutral.
## Alternating fill by nesting level
> "When nesting different areas inside each other, you should alternate between using a fill and not using a fill to provide sufficient contrast between the areas. **The parent layer is usually the BTP layer.**"
`diagr_comp/areas.md`
Resulting pattern (alternation, parent = BTP):
| Nest level | Fill |
|------------|------|
| L0 outer (BTP) | `#EBF8FF` |
| L1 inner | `#FFFFFF` (no fill) |
| L2 inner | `#EBF8FF` |
| L3 inner | `#FFFFFF` |
Stacked layers (e.g. multi-tenant subaccounts) keep the same style:
> "Areas can be shown as stacked to display multiple grouped layers or items. **The style should not be changed in order to keep diagrams consistent.**"
`diagr_comp/areas.md`
## Typography — Helvetica everywhere
The guideline document mentions Arial and Arial Black as font choices:
> "To add the system fonts Arial and ArialBlack to your local draw.io installation you can add the following to the configuration: `{ "customFonts": ["Arial", "Arial Black"] }`"
`solution_diagr_intro/intro.md`
The current public corpus mixes `Helvetica`, `Arial`, and a small amount of `72 Brand`. The skill emits **Helvetica** and `autofix.py` normalises generated content to Helvetica because it is the dominant value in both the canonical BTP examples and Architecture Center diagrams. If a copied SAP template already contains `Arial` or `72 Brand` in rich-text labels, preserve it unless you are rewriting that label.
### Hierarchy
> "**To create hierarchies four text styles were derived from Fiori Horizon.**"
`diagr_comp/text.md`
The doc commits the four styles only via a graphic (`text_styles.png`); concrete pt sizes derived from observation of the shipped templates:
| Role | Size (pt) | Weight (`fontStyle`) | Color |
|------|-----------|----------------------|-------|
| Diagram title | 24 | bold (`1`) | `#1D2D3E` |
| Subtitle | 14 | regular (`0`) | `#475E75` |
| Zone / container label | 16 | bold (`1`) | `#475E75` (non-SAP) or `#1D2D3E` / `#00185A` (BTP) |
| Feature-group heading inside a card | 18 | bold (`1`) | `#1D2D3E` |
| Sub-section label | 14 / 11 | bold (`1`) | accent or `#1D2D3E` |
| Service card title | 1214 | bold (`1`) | `#1D2D3E` |
| Service card caption / inline helper | 11 | regular (`0`) | `#556B82` |
| Pill label | 10 | bold (`1`) — uppercase for TRUST | pill text color |
| Edge label | 10 | regular (`0`) | `#475E75` or zone color |
Never use pure black. `#1D2D3E` reads as "black" but harmonises with the blue zone fills.
### Scaling rule
> "Texts defined in this document may need to be scaled up to fit the specifications of the target medium."
>
> "When scaling elements up or down, take care to ensure text sizes remain consistent."
`text.md` and `solution_diagr_intro/big_picture.md`
If the user asks for a poster-sized canvas, scale the **whole** diagram including text — don't tweak font sizes individually.
## Spacing — the SAP-logo heuristic
> "**Spacing around objects should be even and roughly the height of the SAP Logo.**"
`foundation.md`
The SAP logo (the standard 60 × 23 px draw.io shape) is roughly **23 px tall**, snapped to the 10-px grid that's **20 px** of breathing room. Use 20 px between sibling cards, 30 px between zones.
## Banned palettes
Not in the SAP Horizon family — the validator flags these as warnings:
- draw.io defaults: `#dae8fc`, `#d5e8d4`, `#f8cecc`, `#6c8ebf`, `#fff2cc`
- Material / Tailwind generic pastels
- Pure `#000000` for text (use `#1D2D3E` instead)
- Any hex not listed in `validate.py:SAP_PALETTE`
## Don't
> "It is not recommended to use too many SAP logos in the same diagram. Use text only elements instead."
`diagr_comp/product_names.md`
> "**SAP product names must be paired with the SAP logo.**" *(but only one logo per zone, not one per service card)*
`diagr_comp/product_names.md`
> "Avoid creating your own arrows; use the ones available in the library instead as they adhere to the correct styling guidelines."
`solution_diagr_intro/big_picture.md`
+175
View File
@@ -0,0 +1,175 @@
# Shape & edge conventions
All values match the SAP BTP Solution Diagram Guidelines and the actual `.drawio` files SAP ships in `SAP/btp-solution-diagrams` and `SAP/architecture-center`. Copy the style strings verbatim — never invent alternatives.
## Zone frame (outer landscape containers)
Every zone has an **inline top-left bold label** — never a separate header tab. Corner radius is fixed at 16 px:
> "**A fixed corner radius of 16 pixels is recommended.**"
`diagr_comp/areas.md`
```
rounded=1;whiteSpace=wrap;html=1;arcSize=16;absoluteArcSize=1;strokeWidth=1.5;
fontFamily=Helvetica;align=left;verticalAlign=top;spacingLeft=10;spacingTop=10;
fontSize=16;fontStyle=1;
```
`arcSize=16;absoluteArcSize=1` produces a fixed 16-px corner radius. Without `absoluteArcSize=1`, draw.io interprets `16` as a percentage and on a 700-px-wide zone you get a 112-px radius. **`autofix.py` adds `absoluteArcSize=1` automatically, but your source should have it from the start.**
## Service card (tile inside a zone)
```
rounded=1;whiteSpace=wrap;html=1;arcSize=16;absoluteArcSize=1;strokeWidth=1.5;
fontFamily=Helvetica;fontSize=12;align=center;verticalAlign=middle;
```
Card content is HTML in the `value` attribute — bold title 13 px then `<br/>` then muted caption 11 px wrapped in `<span style="font-size:11px;color:#556B82;font-weight:normal;">…</span>`. Typical size: **280 × 5084 px**.
### Icon + label pattern
For a BTP service tile with the official icon + a label underneath, use the pre-built mxCell from the bundled library (see `extract_icon.py`). The library cells already set:
- `shape=image;image=data:image/svg+xml,<base64>`
- `verticalLabelPosition=bottom;verticalAlign=top` — puts the label below the icon
- `labelPosition=center;align=center`
- `imageAspect=0;aspect=fixed`
Default size **64 × 80** (icon 64 px + ~16 px for the label). Set `fontSize=12` on the icon cell for the label — larger than the ref default 10 so short labels don't look stranded.
> "**For diagram visualization it is mandatory to use the version with grey background circle.**"
`diagr_comp/icons.md`
The bundled library is the grey-circle variant. Don't substitute plain SVGs.
## Action pill (edge pill — HTTPS, TRUST, Sign-in, mTLS, A2A, MCP, authorization)
```
rounded=1;whiteSpace=wrap;html=1;arcSize=50;absoluteArcSize=1;strokeWidth=1;
fontFamily=Helvetica;fontSize=10;align=center;verticalAlign=middle;
```
- **Size**: 6090 × 2024 px
- **Label**: `<b style="font-size:10px;">LABEL</b>` — short, imperative, UPPERCASE for trust relationships
- **Color per role** — see "Edge color semantics" below
Pills **float on top** of zone frames — they share `parent="1"` with the zones, not the zone as parent. The validator suppresses overlap warnings for them.
## Numbered flow step (L1/L2 flow narration)
Small coloured circle (`shape=ellipse;aspect=fixed`), ~28-35 px diameter, with a single-digit bold label. Color matches the semantic category (green = auth step, indigo = authz step, magenta/pink = trust step, neutral `#475E75` = plain flow step).
## Edge defaults
```
edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;
strokeColor=#475E75;strokeWidth=1.5;
endArrow=blockThin;endSize=6;endFill=1;
fontFamily=Helvetica;fontSize=10;
labelBackgroundColor=default;
```
**`labelBackgroundColor=default` is mandatory** for any edge that crosses a filled zone. Without it, edge label text bleeds into the `#EBF8FF` BTP fill and becomes unreadable — the single most common "looks unpolished" bug. The validator flags this.
> "Avoid creating your own arrows; use the ones available in the library instead as they adhere to the correct styling guidelines."
`solution_diagr_intro/big_picture.md`
The `endArrow=blockThin;endSize=6;endFill=1` style above matches the SAP-shipped library arrows.
Additional routing flags seen in SAP's published files — `entityRelationEdgeStyle` for indirect flows, `targetPerimeterSpacing=15`, `jumpStyle=none` — plus connection-point docking rules and waypoint syntax are in `drawio-gotchas.md` §§45, 8. Read that file before hand-authoring any new edge cell.
### Edge color semantics — **the SAP-mandated mapping**
> "To harmonize certain reoccurring flows a use of the following standards is recommended:
> - **Trust Flows are usually pink**
> - **Authentication flows are usually green**
> - **Authorization flows are usually indigo**
> - **Firewalls and Network barriers are thick grey lines**"
`lines_connectors.md`
| Color | Meaning | Stroke / Fill (when used as pill) |
|-------|---------|-----------------------------------|
| `#475E75` | Default internal flow | — |
| `#188918` | **Authentication** (positive semantic) | stroke `#188918`, fill `#F5FAE5`, text `#266F3A` |
| `#5D36FF` | **Authorization** (indigo accent) | stroke `#5D36FF`, fill `#F1ECFF` |
| `#470BED` | **Provisioning / identity lifecycle** (SCIM) — the *edge* indigo used in e.g. `ac_RA0010_BuildWorkZone`; keep `#5D36FF` for authorization pills/zone accents | stroke `#470BED`, fill `#F1ECFF` |
| `#CC00DC` dashed | **Trust relationship** (pink accent, no data) | stroke `#CC00DC`, fill `#FFF0FA` |
| `#07838F` | **Custom emphasis** (teal — e.g. MCP tool call) | stroke `#07838F`, fill `#DAFDF5` |
| `#000000` solid thick (`strokeWidth=3` or `4`) | Network / firewall barrier | — |
| `#002A86` | Call into SAP ABAP system (ADT) | — |
### Line-style semantics
> "Recommended styles for BTP Solution Diagrams are:
> - Solid lines for direct, synchronous request-response data flows
> - Dashed lines for indirect, asynchronous data flows
> - Dotted lines for optional data flows
> - Thick lines for firewalls only"
`foundation.md`
| Style | draw.io flags | Meaning |
|-------|---------------|---------|
| **Solid** | (default) | Direct, synchronous request-response |
| **Dashed** | `dashed=1;dashPattern=4 4` | Indirect, asynchronous |
| **Dotted** | `dashed=1;dashPattern=1 4` | Optional |
| **Thick** | `strokeWidth=3` or `4` | Firewall / network barrier (only — never for emphasis) |
### Trust lines
Use `dashed=1;dashPattern=4 4` for trust relationships:
```
edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;
strokeColor=#CC00DC;strokeWidth=1.5;
dashed=1;dashPattern=4 4;
endArrow=none;startArrow=none;
fontFamily=Helvetica;fontSize=10;
labelBackgroundColor=default;
```
Mutual trust → no arrowheads (`startArrow=none;endArrow=none`).
> "Bidirectional solid arrows may represent mutual trust."
`lines_connectors.md`
(Bidirectional arrows for trust **without** dashing are also acceptable per the doc, but the dashed variant is more visually distinct from data flows. The skill defaults to dashed.)
## Alignment rule — the highest-leverage polish trick
For an `orthogonalEdgeStyle` edge with `source=A; target=B` to render as a **straight line** (no bend), the **centers** of A and B must share an axis:
- `A.centerX == B.centerX` → vertical straight line
- `A.centerY == B.centerY` → horizontal straight line
Where `centerX = x + width/2`, `centerY = y + height/2`.
If the centers differ on both axes, the edge renders with a 90° kink. Either:
1. Snap one coordinate so the centers align (preferred), **or**
2. Add explicit docking anchors: `entryX=0.5;entryY=0;exitX=0.5;exitY=1;entryDx=0;entryDy=0;exitDx=0;exitDy=0`.
`validate.py` detects this class of bug and reports `edge N: source/target centers differ on both axes`.
## Spacing — the SAP-logo heuristic
> "**Spacing around objects should be even and roughly the height of the SAP Logo.**"
`foundation.md`
The SAP logo (the 60 × 23 px library shape) is ~23 px tall, snap-rounded → use **20 px** between sibling cards and **30 px** between zones.
## Gotchas
- **Widths like `239.99999999999997`** happen because draw.io UI rounds imprecisely — emit integers. `autofix.py` quantises them.
- **`absoluteArcSize=1` is non-negotiable** — without it `arcSize=16` on an 800-px zone makes a 128-px radius.
- **Pill `strokeWidth` is `1`, not `1.5`** — pills are small and 1.5 looks over-weighted.
- **Edge labels need `labelBackgroundColor=default`** even when the edge is outside a zone, for consistency.
- **Service-card labels are set on the icon cell**, not the wrapping rectangle. Naive generators put the label on the rectangle and the text gets clipped by the icon image.
- **Don't use thick lines for emphasis.** Thick = firewall only. The validator warns on `strokeWidth>=3` outside a firewall context.
- **Don't recolour library arrows** — use the ones from the library and only change the `strokeColor` to the semantic color (green/indigo/pink/teal/grey).