SBDL Compiler Design

2.0.0 (SBDL Compiler), 26.6 (SBDL Language) [#e316992]

The SBDL compiler: reads distributed SBDL, builds and verifies one model, and projects it into many output forms. Flat sibling modules rather than a package, so that sbdl.py stays directly runnable.

The compiler’s layers, modules and the software around it

Design Goals

A quality the design is built to achieve.

Goal Rationale Principles Evidence
Every element and every diagnostic is traceable to the file and line that caused it — dp_stage_gate, dp_source_reference —
Identical input produces byte-identical output Generated artefacts are committed, published and diffed in CI; churn hides real changes dp_sorted_output, dp_stable_arithmetic t_native_renderer
Runs unmodified on CPython and PyPy with no compiled extensions on the core path Large models are routinely compiled under pypy3 dp_external_rasteriser, dp_stable_arithmetic t_native_renderer
The entry script runs directly from a checkout, from an installation or as a frozen binary — dp_flat_modules —
New output modes, directives and rendering backends are added without changing the compilation pipeline — dp_outputs_namespace, dp_single_model, dp_mode_registry, dp_writer_contract, dp_injection_over_import t_renderer_backend
A command line that once worked keeps working Mode names live in user Makefiles, BATCH directives and deployment scripts dp_mode_registry, dp_renderer_backend t_mode_aliases
Compile, filter and render time grows roughly linearly with model size Production models hold thousands of elements; quadratic passes made some modes unusable dp_incoming_index t_incoming_index
The core path and the SVG diagram path need nothing beyond the Python standard library Removing the Java and Graphviz dependency was the reason for the native renderer dp_renderer_backend, dp_external_rasteriser —
The language server never stalls the editor while a compile is running — dp_off_the_event_loop t_lsp_smoke
A second implementation of the language can be qualified against this one — dp_semantic_comparison, dp_corpus_checks_itself t_compliance_self
The shipped, minified compiler behaves identically to the source — dp_shared_namespace, dp_test_the_build t_distribution

Architecture

A band of modules holding one position in the import order.

Foundation

Leaf of the import graph: imports no sibling.

Foundation

sbdl_core.py

Configuration, printing, progress, lazy imports and run-state reset.

Component Responsibility Defined at
cmp_config Configuration store: registered defaults, -C overrides, SBDL_* environment snapshot, provenance by comparison with defaults sbdl_core.py:45
cmp_reset reset() and the hook registry through which any module registers global state to clear between compilations sbdl_core.py:432
cmp_lazy_import Optional dependencies imported on first use; offers installation only when stdin can answer sbdl_core.py:500
cmp_printing f_print: decides whether to print before formatting; errors and warnings to stderr, output never interleaved with stdout sbdl_core.py:603
cmp_progress Progress bars and terminal title on stderr, inert unless enabled and stderr is a terminal sbdl_core.py:664

Model

The language: parser, metamodel, element graph and every reader. Depends on lyr_foundation.

Model

sbdl_model.py

Parser, semantics, element hierarchy, AST and the input layer. One module because the metamodel is internally cyclic and the parser and readers are mutually coupled.

Component Responsibility Defined at
cmp_parser SBDL_Parser: statement scanning, key-value parsing, tokens, attributes and directive expansion sbdl_model.py:38
cmp_directives Compiler directives: definitions, imports, embedding context, cross-references, Prolog assertions and batch jobs sbdl_model.py:169
cmp_semantics SBDL_Semantics: the type tables (properties and permitted relations per type) and the registry of custom types sbdl_model.py:1710
cmp_statements SBDL_Statement hierarchy: declarations, using, scope, depends and relation operators, as parsed sbdl_model.py:2447
cmp_elements SBDL_Element hierarchy: one class per metamodel type, each verifying its own properties and links sbdl_model.py:2625
cmp_ast SBDL_AST: turns statements into the element set, applies filters, verifies, and answers relation queries sbdl_model.py:3714
cmp_readers Input readers: native and embedded SBDL, JSON, YAML, CSV matrix and SQL, all producing parser elements sbdl_model.py:4949
cmp_ast_cache Pickled AST cache for single-file inputs, validated before reuse sbdl_model.py:5481

Principles: dp_single_model, dp_immutable_elements.

Writers

Projections of a verified model into other forms; consumers of the model only. Depends on lyr_model.

Writers

sbdl_outputs.py

The output namespace: text, tabular, SQL, template and PlantUML writers, batch dispatch and trace verification. Also imports mod_openfmea, mod_sysmlv2.

Component Responsibility Defined at
cmp_plantuml_writers PlantUML diagram writers: the plantuml rendering backend sbdl_outputs.py:38
cmp_text_writers compile, query, matrix:csv, tree:json, tree:yaml and type-info writers sbdl_outputs.py:1040
cmp_sql_backend Normalised SQLite writer, behind a backend seam reserved for remote databases sbdl_outputs.py:1237
cmp_template_fill template:fill: the model as a Jinja2 context, plus Office document templating sbdl_outputs.py:1535
cmp_mode_loader Loads --custom-mode modules and their MODES dictionaries sbdl_outputs.py:1668
cmp_batch Batch dispatch: runs the jobs declared by BATCH directives against copies of the AST sbdl_outputs.py:1703
cmp_model_machine SBDL_Model_Machine: replays trace elements against the functions and state machines of the model sbdl_outputs.py:1830

Principles: dp_outputs_namespace, dp_writer_contract.

sbdl_openfmea.py

OpenFMEA import and export: the cause, mode and effect table and its portfolio form.

sbdl_sysmlv2.py

Translation of the model into SysML v2 textual notation.

sbdl_native_svg.py

Diagram-agnostic SVG basis: theme, text metrics, layouts, routing, labels and canvas.

Component Responsibility Defined at
cmp_theme Theme tokens and style packs: every visual decision is a registered configuration key sbdl_native_svg.py:13
cmp_layouts Containment packing, layered (Sugiyama-lite), tree and force-directed layouts sbdl_native_svg.py:531
cmp_routing Orthogonal and curved edge routing around obstacles, with a spatial grid for scale sbdl_native_svg.py:1104
cmp_canvas Canvas: frame, header tab, footer and final document fitting sbdl_native_svg.py:1783

Principles: dp_measure_equals_draw, dp_external_rasteriser.

sbdl_native_sysml.py

The native rendering backend: SysML-style diagrams drawn directly as SVG. Also imports mod_native_svg, mod_outputs.

Component Responsibility Defined at
cmp_structure_diagrams Aspect, requirement, element and use case diagrams sbdl_native_sysml.py:456
cmp_behaviour_diagrams Sequence (function), activity (function-process) and state machine diagrams sbdl_native_sysml.py:673
cmp_analysis_diagrams FMEA failure-chain and type-affinity diagrams, which have no PlantUML counterpart sbdl_native_sysml.py:3255

Principles: dp_machine_readable_svg.

Services

Long-running or remote ways of reaching a compiled model. Depends on lyr_model.

Services

sbdl_lsp.py

Language server: diagnostics, symbols, hover, completion and the model explorer snapshot.

Component Responsibility Defined at
cmp_completion Completion as a pure function of the line prefix, testable without an editor sbdl_lsp.py:260
cmp_model_snapshot The model served to the explorer: the widest open model that contains the document sbdl_lsp.py:396
cmp_lsp_server The pygls server and its handlers, built as closures inside lsp_start sbdl_lsp.py:509
cmp_doc_worker One worker per open document, compiling off the event loop and coalescing requests sbdl_lsp.py:605

sbdl_mcp.py

Read-only Model Context Protocol server over a compiled model.

Principles: dp_injection_over_import.

sbdl_remote.py

Standalone RPC client for the remote REST service, shipped separately from the compiler.

Entry

The command line: the only module that knows every other. Depends on lyr_writers, lyr_services.

Entry

sbdl.py

Argument handling, the mode table and the single compilation run.

Component Responsibility Defined at
cmp_mode_table operating_modes: the common modes, extended by the selected rendering backend sbdl.py:39
cmp_main main: one compilation run, staged and gated by check_step sbdl.py:114
cmp_arguments Argument parsing and pre-execution handling: configuration, -C, progress and flags that exit early sbdl.py:277

Principles: dp_never_import_entry.

Assurance

Evidence that the compiler does what it claims. Depends on lyr_writers.

Assurance

sbdl_compliance.py

Compliance corpus and runner that qualify an external compiler against this one. Shipped: the corpus is inline data, so it runs from an installation with no repository.

Principles: dp_semantic_comparison, dp_corpus_checks_itself.

sbdl_tests.py

The unit and integration suite, driven largely through the real command line. Not shipped: it needs the test fixtures. Holds the one sanctioned upward reference to the entry.

Principles: dp_test_through_cli.

Tooling

Build, release and editor tooling around the compiler.

Tooling

helpers/

Source rewriters run on the distribution copies: explicit imports, f-string compatibility, comprehension shadowing.

release_public.sh

Publishes one commit per release to the public repository, filtered by a manifest.

Principles: dp_snapshot_releases.

build_dist.sh

Distribution build: copy, rewrite star imports, minify, repair, package.

Principles: dp_test_the_build.

Design Principles

A design decision that holds across the compiler.

Architecture

The compiler is a set of flat sibling modules, not a package. Keeps sbdl.py directly runnable however it is launched; the entry puts its own directory on sys.path first. Consequence: A bare copy of sbdl.py no longer works alone; every sibling must travel with it.
Applies to lyr_entry; serves goal_runnable

Imports form a directed acyclic graph: core, then model, then writers and services, then the entry. Each layer can be read, tested and replaced knowing only the layers beneath it. Consequence: The native renderer reaches outputs through a plain module import, the one tolerated cycle, resolved at call time.
Applies to sbdl_compiler

No module imports the entry; the test suite alone reaches it, through one guarded helper. When the entry runs as __main__, importing it re-executes it as a second module and rebuilds the configuration snapshot.
Applies to mod_entry

Modules reconstitute one shared namespace with star imports; the build rewrites them into explicit imports. Keeps the split invisible to code moved out of the original single file, while letting the minifier rename locals in the shipped copy. Consequence: Underscore names do not cross a star import and must be imported explicitly.
Applies to lyr_foundation; serves goal_correct_build; evidenced by t_distribution

Global state that must not survive a compilation registers a reset hook with the core. The language server and the test suite compile many models in one process; the core stays a leaf while any module can register state.
Applies to cmp_reset

The entry imports output modes from the outputs module and nowhere else. Adding a writer then touches only the mode table, never the entry imports. Consequence: A writer carved into its own module must be re-exported by the outputs module or the mode table fails at run time.
Applies to mod_outputs; serves goal_extensible

Semantics

Every input form is read into the same element graph, verified once, and only then projected. Writers never parse and never verify, so every output agrees on what the model is.
Applies to mod_model; serves goal_extensible

Each compilation stage ends at a gate that counts errors and aborts before the next stage. A later stage never runs on a model an earlier stage rejected, unless the user asks for that with --skip-errors.
Applies to cmp_main; serves goal_traceable

Diagnostics cite an element by source_reference, never by reference. reference is a display value a model may override; source_reference is the parser location and cannot be overridden. Consequence: The language server recovers squiggle positions from diagnostic text, so a wrong reference pins it to line 0.
Applies to cmp_elements; serves goal_traceable

Relation queries take a table of incoming relations, built once by whoever holds the element set. An element stores only the relations it declares; finding the reverse half by scanning makes every query linear and every pass quadratic.
Applies to cmp_ast; serves goal_scalable; evidenced by t_incoming_index

related is an ordinary relation, exposed through its own view and excluded from links. Relation verification type-checks each link against its target, which a related link could never satisfy.
Applies to cmp_elements

A group organises the model and is not part of it: it may end a connectivity path but never bridge one. Adding an element to a review package must not change the answer to a question about the system. Consequence: Connectivity semantics are implemented twice, in the AST walk and in the SQL query, and must change together.
Applies to cmp_ast; evidenced by t_filter_semantics

A filter reduces the model; a diagram root leaves the model whole and moves only where a diagram starts. Diagram writers reach outwards while drawing, so filtering to one element culls what is needed to draw it.
Applies to cmp_ast; evidenced by t_diagram_root

Elements are defined once and never modified; membership and relation may be declared from either side. Definitions are distributed across files the author may not own, so the model is assembled, never edited.
Applies to mod_model

Extensibility

Every output mode is one row in a mode table: name, writer, output kind, description and older spellings. Help, discovery, batch validation and the MCP tools all read the same table, so a new mode appears everywhere at once. Consequence: Deprecated spellings are kept as aliases and omitted from help, which is deprecation by omission.
Applies to cmp_mode_table; serves goal_extensible, goal_stable_cli; evidenced by t_mode_aliases

A writer takes the AST, the output path, a file opener, the arguments and a print function, and returns an error count. One signature lets the entry, batch, the MCP server and custom modes all drive any writer the same way. Consequence: A writer reads its own mode name from the arguments, never from a literal of its own.
Applies to mod_outputs; serves goal_extensible; evidenced by t_renderer_backend

A mode that reads input is registered twice: in the mode table, and with the reader for its format. Readers and writers vary independently; most reading modes share one writer. Consequence: A reading mode registered only once parses its input as SBDL and produces wrong output rather than an error.
Applies to cmp_mode_table; evidenced by t_mode_aliases

Diagram modes come from a selected rendering backend, so one mode name dispatches to a different writer per backend. Lets the native renderer replace PlantUML behind unchanged command lines, and an unknown backend fails rather than drawing nothing.
Applies to cmp_mode_table; serves goal_stable_cli, goal_dependency_light; evidenced by t_renderer_backend

A service that needs the writers receives the mode table as an argument instead of importing it. Keeps services such as the MCP server below the entry in the import graph and free of mode-specific code.
Applies to mod_mcp; serves goal_extensible; evidenced by t_mcp_server

Outputs project the model; they never restate it or invent what it does not say. A diagram that asserts something absent from the model is worse than one that leaves it out, as with an inferred initial state.
Applies to lyr_writers

Rendering

Anything measured and then drawn is computed by one function used for both. Separate copies drift: labels were sized at one position and painted at another, and clipped.
Applies to mod_native_svg

A style pack changes paint and spacing only, never shape, notation or layout. Every machine-readable hook in the SVG stays identical across styles, which the editor and the tests rely on.
Applies to cmp_theme

Every drawn element carries data-sbdl attributes naming the model element it shows. Tests count hooks instead of geometry, so they survive layout changes, and the editor makes diagrams clickable.
Applies to mod_native_sysml; evidenced by t_native_renderer

PNG output pipes SVG through an external command rather than a Python binding. Bindings are C extensions that break PyPy; a missing rasteriser fails loudly instead of writing SVG into a file named png.
Applies to mod_native_svg; serves goal_portable, goal_dependency_light

Quality

Sets are never iterated on an output path without sorting. String set order varies per process under hash randomisation, so it silently became property order in several writers.
Applies to sbdl_compiler; serves goal_reproducible

Layouts use only correctly rounded operations and a summation that is identical on every interpreter. A layout is a feedback loop: one bit of difference in a sum steers every later iteration.
Applies to cmp_layouts; serves goal_reproducible, goal_portable; evidenced by t_native_renderer

Tests drive the real command line or protocol wherever the wiring is part of the behaviour. Flag wiring, configuration loading and mode registration are exactly what an in-process call skips.
Applies to mod_tests

The suite runs against the minified distribution before a release, not only against the source. Some defects exist only in the minified form, where a renamed name meets an interpreter optimisation.
Applies to mod_build; serves goal_correct_build; evidenced by t_distribution

Compliance compares meaning, not text: both outputs are recompiled by the reference and the canonical forms compared. compile is idempotent, so formatting differences dissolve and only changes of meaning remain.
Applies to mod_compliance; serves goal_qualifiable; evidenced by t_compliance_self

Every compliance case states its expected outcome, and a case the reference disagrees with blames the corpus. A deliberate change of behaviour then surfaces as a corpus disagreement instead of silent drift.
Applies to mod_compliance; serves goal_qualifiable; evidenced by t_compliance_self

Operations

Standard output carries only the requested output; everything for humans goes to standard error. The default output is stdout, and the language and MCP servers speak their protocols over it.
Applies to cmp_printing; evidenced by t_mcp_server

The compiler never waits for an answer that nobody can give. An install prompt inside CI or a captured child process blocks forever and invisibly.
Applies to cmp_lazy_import

Compiling and building model snapshots happen on worker threads, never on the language server event loop. A request waiting on a compile delays every request behind it, including shutdown.
Applies to cmp_doc_worker; serves goal_responsive_editor; evidenced by t_lsp_smoke

The public repository receives one dated commit per release, built from a manifest of the private one. Working history and timestamps stay private; a new file stays private until listed.
Applies to mod_public_release

Boundaries

Protocols

A wire or file format through which other programs drive or consume the compiler.

Protocol Description Owned by
if_cli The command line: sources, a mode, filters, configuration and an output path mod_entry
if_sbdl_text SBDL itself, native or embedded in other files, read and written by compile mod_model
if_tree_formats JSON tree, YAML tree and CSV matrix, written and read back cmp_readers
if_sql_schema The normalised SQLite schema: elements, properties, relations with derived reverse halves, custom types cmp_sql_backend
if_openfmea OpenFMEA documents, written and read mod_openfmea
if_sysmlv2 SysML v2 textual notation, written mod_sysmlv2
if_svg Native SVG diagrams with data-sbdl hooks and a stated ground colour mod_native_sysml
if_lsp Language Server Protocol over stdio, plus the sbdl/model request and sbdl/modelUpdated notification mod_lsp, ext_editor
if_mcp Model Context Protocol over local HTTP or stdio: five read-only tools mod_mcp, ext_ai_client
if_rpc REST RPC to a remote compilation service mod_remote

Extension Points

A seam through which the compiler is extended without editing it.

Extension point Description Owned by
if_custom_mode A module exposing a MODES dictionary of writers, loaded with --custom-mode; its modes replace built-in ones of the same name cmp_mode_loader
if_custom_directive A file of custom compiler directives, loaded with --custom-directive cmp_directives
if_customtype customtype declarations, with optional embedded Python verifiers: the language profile mechanism cmp_semantics
if_template_context The model as a dictionary inside Jinja2: identifiers to properties and relation lists cmp_template_fill
if_ast_hooks Pre- and post-verification hooks called with the AST, configured as lists of functions cmp_main

External Software

Software outside the compiler that it calls, or that calls it.

Software Description Dependency Relates to
ext_plantuml PlantUML, invoked as a subprocess by the plantuml rendering backend optional cmp_plantuml_writers
ext_rasteriser An SVG rasteriser such as rsvg-convert, used only when a native diagram is written as PNG optional cmp_canvas
ext_pygls pygls, the language server framework under the lsp mode optional cmp_lsp_server
ext_jinja2 Jinja2, the template engine under template:fill optional cmp_template_fill
ext_prolog SWI-Prolog through pyswip, for the Prolog assertion directives optional cmp_directives
ext_editor The VS Code extension: a language client plus explorer, previews and tables that shell out to the compiler consumer mod_lsp
ext_ai_client An MCP client such as Claude Code or Claude Desktop consumer mod_mcp
ext_minifier python-minifier, run by the distribution build build mod_build

Behaviour

Use Cases

Use cases

Use case Actor Description Function Goal
uc_compile Modeller Compile distributed sources and produce an artefact fn_compile_run goal_traceable
uc_edit Modeller Write SBDL in an editor with live diagnostics, completion and a model explorer fn_lsp_document goal_responsive_editor
uc_ask AI assistant Ask questions about a model and look at its diagrams fn_mcp_call —
uc_build Build system Generate a project’s documents and diagrams from one compilation fn_batch goal_reproducible
uc_verify_runtime Test engineer Check captured runtime logs against the behaviour the model defines fn_trace_verify —
uc_qualify Tool implementer Qualify another SBDL compiler against the reference fn_compliance goal_qualifiable
uc_release Maintainer Build, test and publish a release fn_release goal_correct_build

Functions

fn_compile_run

One compilation: configuration, reading, parsing, model construction, filtering, verification and the mode. Defined at sbdl.py:117, owned by mod_entry.

Input: Source files, a mode and options. Output: The mode’s artefact, and the total error count as exit status. Invariant: Every stage ends at check_step.

fn_compile_run

Step What happens Where Defined at
ev_pre_exec Load configuration, apply -C and environment overrides, and handle flags that exit early cmp_arguments sbdl.py:428
ev_select_reader Choose the reader from the mode; any other mode reads by content, detecting databases among the inputs cmp_main sbdl.py:204
ev_read_inputs Read every input into parser elements carrying file, line indexes and host context cmp_readers sbdl.py:226
 ev_extract_embedded Take native files whole and lift sbdl-prefixed statements out of host files cmp_readers sbdl_model.py:4899
 ev_sniff_context Record the host construct each statement sits in, such as the enclosing function, for context directives cmp_directives sbdl_model.py:4633
ev_build_ast Build the AST from parser elements, or load it from the cache cmp_ast sbdl.py:230
 ev_split_statements Scan text into statements, keeping the line index of each cmp_parser sbdl_model.py:1591
 ev_expand_directives Expand compiler directives in place: definitions, imports, version checks, batch jobs cmp_directives sbdl_model.py:939
ev_construct_elements Turn statements into the element set cmp_ast sbdl.py:237
 ev_apply_scope Apply using defaults, scope prefixes, nesting and relation operators cmp_ast sbdl_model.py:3860
 ev_resolve_depends Read each depends target once, failing on a missing file cmp_readers sbdl_model.py:3788
 ev_register_types Register custom types in the semantic tables, documenting each by its description cmp_semantics sbdl_model.py:3867
 ev_resolve_crossrefs Substitute cross-references to other elements’ properties cmp_directives sbdl_model.py:3954
ev_register_filters Register the -f filters on the AST; from:sql has already applied them as SQL cmp_main sbdl.py:241
ev_verify Verify every element: its own properties, then each relation’s existence and permitted type (if verification enabled) cmp_elements sbdl.py:245
otherwise ev_skip_verification Report verification as skipped and continue cmp_main sbdl.py:255
ev_dispatch_mode Look the mode up in the operations table and call its writer with the AST cmp_mode_table sbdl.py:261
ev_report Report timings and return the error count cmp_main sbdl.py:266

fn_lsp_document

The life of one open document in the language server. Defined at compiler_design.sbdl:472, owned by mod_lsp.

Input: Document notifications from the editor. Output: Diagnostics, symbols and model snapshots.

fn_lsp_document

Step What happens Where Defined at
ev_lsp_open A document is opened, changed or saved; its worker is asked to compile cmp_lsp_server sbdl_lsp.py:761
ev_lsp_compile The worker compiles the document and its depends, coalescing requests that arrive meanwhile cmp_doc_worker sbdl_lsp.py:689
ev_lsp_diagnostics Compiler messages become diagnostics positioned from their source reference cmp_lsp_server sbdl_lsp.py:715
ev_lsp_model_updated The client is told the model changed cmp_lsp_server sbdl_lsp.py:720
ev_lsp_snapshot The explorer’s model request is answered on a thread from the cached element set cmp_model_snapshot sbdl_lsp.py:897
ev_lsp_close The document closes; its elements, file set and snapshot are dropped cmp_lsp_server sbdl_lsp.py:786

fn_mcp_call

One MCP tool call against the model compiled at start-up. Defined at sbdl_mcp.py:35, owned by mod_mcp.

Input: A JSON-RPC request. Output: Text or image content.

fn_mcp_call

Step What happens Where Defined at
ev_mcp_receive Read a request from POST /mcp or a stdin line, refusing a non-local origin mod_mcp sbdl_mcp.py:204
ev_mcp_dispatch Route the method to its handler; notifications get no reply mod_mcp sbdl_mcp.py:174
ev_mcp_run_writer Run an injected writer on the loaded AST into a temporary directory (if the tool renders or exports) mod_outputs sbdl_mcp.py:68
ev_mcp_reply Return the result as content, or as a tool error the model can read mod_mcp sbdl_mcp.py:154

fn_batch

Run the jobs declared by BATCH directives against the one compiled model. Defined at sbdl_outputs.py:1709, owned by cmp_batch.

Output: One artefact per job.

fn_batch

Step What happens Where Defined at
ev_batch_collect Batch directives met while parsing record their command lines cmp_directives sbdl_model.py:860
ev_batch_job For each command: validate the mode, copy the AST, run in the foreground or as a background job (if commands remain) cmp_batch sbdl_outputs.py:1746
ev_batch_wait Wait for background jobs, counting completions rather than dispatches cmp_batch sbdl_outputs.py:1728

fn_trace_verify

Replay trace elements against the statically defined behaviour. Defined at sbdl_outputs.py:2017, owned by cmp_model_machine.

Input: A model and the trace elements found in logs. Output: A verdict per step, as prose or JSON.

fn_trace_verify

Step What happens Where Defined at
ev_trace_walk Take each trace in definition order, which is log order (if traces remain) cmp_model_machine sbdl_outputs.py:2030
 ev_trace_function A function trace sets the active function and its expected event sequence cmp_model_machine sbdl_outputs.py:1935
 ev_trace_event An event trace must be the next expected event; it may fire transitions that move the state cmp_model_machine sbdl_outputs.py:1994
 ev_trace_assert State, aspect and transition traces assert where the machine already is cmp_model_machine sbdl_outputs.py:1969
ev_trace_verdict Report every divergence with the log file and line it came from cmp_model_machine sbdl_outputs.py:1863

fn_compliance

Qualify a candidate compiler against the reference. Defined at compiler_design.sbdl:498, owned by mod_compliance.

Input: A candidate command line. Output: A per-profile verdict with its scope of claim.

fn_compliance

Step What happens Where Defined at
ev_baseline_gate Compile one minimal valid model first (if the candidate compiles the baseline) mod_compliance compiler_design.sbdl:506
otherwise ev_cannot_qualify Report that nothing can be qualified, rather than a pass over zero cases mod_compliance compiler_design.sbdl:512
ev_probe_modes Probe each mode with a trivial input; an unsupported mode skips its cases instead of failing them mod_compliance compiler_design.sbdl:513
ev_run_case Run each case on both compilers and compare canonical forms (if cases remain) mod_compliance compiler_design.sbdl:514
ev_compliance_report Report exercised cases only, never the corpus size mod_compliance compiler_design.sbdl:519

fn_release

Build, test and publish a release. Defined at compiler_design.sbdl:521, owned by mod_build.

Output: A distribution and one public commit.

fn_release

Step What happens Where Defined at
ev_dist_copy Copy the modules and inject the version mod_build build_dist.sh:32
ev_dist_rewrite Rewrite each star import into the exact explicit equivalent mod_build_helpers build_dist.sh:45
ev_dist_minify Minify, renaming locals and keeping the global names that form the library API mod_build build_dist.sh:48
ev_dist_repair Repair what the minifier breaks: f-string forms for older interpreters, comprehension variables shadowing closures mod_build_helpers build_dist.sh:56
ev_dist_check_lists Fail when a copied module is missing from the installed module list mod_build build_dist.sh:68
ev_dist_test Run the suite against the minified build in a scratch directory mod_tests compiler_design.sbdl:528
ev_public_export Export the committed tree through the manifest and scan it for private content mod_public_release compiler_design.sbdl:529
ev_public_commit Commit as one release with pinned author and date, and tag it; never push mod_public_release compiler_design.sbdl:530

fn_native_render

How every native diagram mode draws. Defined at compiler_design.sbdl:534, owned by mod_native_sysml.

Input: The AST and the resolved diagram roots. Output: SVG, or PNG through an external rasteriser.

fn_native_render

Step What happens Where Defined at
ev_render_collect Project the model into nodes and edges for this kind of diagram mod_native_sysml compiler_design.sbdl:542
ev_render_measure Measure every box from text metrics, captions and reserved overhangs cmp_layouts sbdl_native_svg.py:682
ev_render_layout Place nodes with the layout the notation calls for: packed, layered, tree, timeline or force cmp_layouts sbdl_native_svg.py:529
ev_render_route Route edges around obstacles, fanning endpoints that share a side cmp_routing sbdl_native_svg.py:1375
ev_render_labels Place edge labels at the least overlap, sliding along the edge before nudging off it cmp_routing sbdl_native_svg.py:1518
ev_render_paint Paint in a fixed order: boxes, then edges, then labels, each tagged with its model element cmp_canvas sbdl_native_svg.py:1807
ev_render_emit Fit the canvas and write the document (if output is not named png) cmp_canvas sbdl_native_sysml.py:401
otherwise ev_render_rasterise Pipe the SVG through the configured rasteriser, failing loudly when it is absent cmp_canvas sbdl_native_sysml.py:414

Other Events

Event What happens Where Defined at
ev_stage_failed A stage gate counted errors and --skip-errors is not set (if errors greater than zero) cmp_main sbdl.py:140

State Machines

State machines

State Description Within Where
st_run A compilation run in progress — cmp_main
st_configuring Arguments and configuration being applied st_run cmp_arguments
st_reading Inputs being read st_run cmp_readers
st_parsing Statements being parsed into the AST st_run cmp_parser
st_constructing The element set being constructed st_run cmp_ast
st_verifying The element set being verified st_run cmp_elements
st_writing The mode writing its output st_run mod_outputs
st_complete Run finished; exit status is the error count — cmp_main
st_aborted Run stopped at a stage gate — cmp_main
st_doc_closed Nothing held for the document — mod_lsp
st_doc_open The document is open — mod_lsp
st_doc_compiling A compile is running st_doc_open cmp_doc_worker
st_doc_current Diagnostics and model reflect the latest text st_doc_open cmp_lsp_server
Transition From To On Description
tr_read st_configuring st_reading ev_read_inputs Reading starts
tr_parse st_reading st_parsing ev_build_ast Parsing starts
tr_construct st_parsing st_constructing ev_construct_elements Construction starts
tr_verify st_constructing st_verifying ev_verify Verification starts
tr_verify_skipped st_constructing st_verifying ev_skip_verification Verification is skipped
tr_write st_verifying st_writing ev_dispatch_mode The mode runs
tr_finish st_writing st_complete ev_report The run completes
tr_abort st_run st_aborted ev_stage_failed Any stage fails
tr_doc_open st_doc_closed st_doc_compiling ev_lsp_open Open
tr_doc_compiled st_doc_compiling st_doc_current ev_lsp_diagnostics Compiled
tr_doc_changed st_doc_current st_doc_compiling ev_lsp_compile Edited again
tr_doc_close st_doc_open st_doc_closed ev_lsp_close Closed

Design Hazards

A way the design is known to be broken by a plausible change.

Design hazards as failure chains

Hazard Failure mode Effect Control Detection
A writer iterates a set of strings on an output path Output differs between runs of identical input Committed and published artefacts change without a model change, hiding real changes in review Every set on an output path is sorted Render twice and compare, then again with the hash seed fixed: stable only with the seed means a set is being iterated
A submodule imports the entry by name The configuration-default snapshot is rebuilt mid-process Configuration bleeds between compilations and between tests Submodules import only core and model; upward references are deferred to call time —
A reading mode is added to the mode table but not to the reader table Input in another format is parsed as SBDL Wrong output with no error Both registrations are documented together beside the mode table Every reading mode round-trips through its own reader
A writer gathers relations without the incoming-relations table A pass rescans every element for every element Modes take minutes on production-sized models The outermost scope holding the element set builds the table and passes it down Indexed walks are compared with scanning ones and checked for rescans
The minifier gives a comprehension variable the name of a closure cell its function passes through A NameError raised only by the minified build A released compiler fails where the source passed every test A build step renames such comprehension variables to fresh names The language server smoke test, run against the minified build
An optional dependency is missing where stdin cannot answer A child process blocks on a prompt nobody sees A build or compliance run hangs with no indication why Prompts are offered only when stdin is a terminal, and compliance children run with stdin closed —

Evidence

Test What it shows Goals Principles Defined at
t_filter_semantics FilterSemanticTests: every filter’s result set written out, including SQL-layer fidelity — dp_group_is_not_model sbdl_tests.py:415
t_distribution DistributionTests and ComprehensionShadowTests: the import rewrite is exact and the minifier is never blocked goal_correct_build dp_shared_namespace, dp_test_the_build sbdl_tests.py:797
t_lsp_smoke LSPSmokeTests: a real server over stdio, and a model request that does not stall it goal_responsive_editor dp_off_the_event_loop sbdl_tests.py:901
t_incoming_index IncomingRelationsTests and CMEGraphIndexTests: indexed walks equal scanning ones and do not rescan goal_scalable dp_incoming_index sbdl_tests.py:1172
t_renderer_backend RendererBackendTests: each backend covers the shared diagram names, writers keep the contract, -C selects a backend goal_extensible dp_renderer_backend, dp_writer_contract sbdl_tests.py:1280
t_mcp_server MCPServerTests: the MCP server driven over stdio as a client would — dp_injection_over_import, dp_stdout_is_output sbdl_tests.py:1549
t_diagram_root DiagramRootTests: a root keeps what a filter loses — dp_filter_versus_root sbdl_tests.py:2084
t_mode_aliases ModeNameAliasTests: deprecated spellings render identically and never appear in help; every reader round-trips goal_stable_cli dp_mode_registry, dp_two_registries sbdl_tests.py:2184
t_native_renderer NativeRendererTests: counts by data-sbdl hooks, parity with PlantUML, well-formed XML, identical layout on every interpreter goal_reproducible, goal_portable dp_machine_readable_svg, dp_stable_arithmetic sbdl_tests.py:2437
t_compliance_self The compliance self-check: the reference against itself, where any failure is a runner or corpus bug goal_qualifiable dp_semantic_comparison, dp_corpus_checks_itself compiler_design.sbdl:546