Skip to content

Releases

RELEASES

0.57.0 — 2026-10-28

  • New: a TestCase can verify architecture elements directly (REQ-TRS-TCELEM-001, #408). verifiesElement: names the PartDef, InterfaceDef, ActionDef or StateDef elements a test exercises (E102 unresolved, E129 wrong kind, W019 when a variant removes the element). A test with only verifiesElement: satisfies E013.
  • New: W104 reports an active, non-abstract PartDef, InterfaceDef, ActionDef or StateDef that no active TestCase names in verifiesElement: and that satisfies no requirement with an active verifying test. testExempt: <rationale> on the element suppresses it; draft elements are never checked.
  • Changed (behaviour): existing models gain W104 on every untested active architecture element. It is a warning; add verifiesElement: links or testExempt: rationales, or leave it, and gate CI with validate --deny W104 once the count is zero.
  • New: sequence diagrams show operation calls (#365, #407, REQ-TRS-SEQ-002). A SendAction/PerformAction that names an operation: is a message labelled with the operation's signature, followed by a dashed return (Real ! Fault when errors: are declared) for a synchronous operation with a return type. Existing diagrams are unchanged.
  • New: operation call arguments are checked against the parameter's kind and unit (E675, #398, #406).
  • Changed: the repository's own .cargo/config.toml caps RUST_TEST_THREADS at 4 and debuginfo at line tables so the full test suite no longer exhausts memory.

0.56.0 — 2026-10-22

  • New: syscribe design-report <part> [--json] (#371, #403, REQ-TRS-DREP-001) lays out one software part as the detailed-design (ASPICE SWE.3) work product: level and description, interface (its own operations and those of the ports it contains), behaviour (the ActionDefs realising its operations), data (features with type, unit and range), resources (ram, flash, nvm, stack, period, deadline, wcet, priority), code (implementedBy:), the requirements it satisfies, and the tests that verify it with their verdicts. An empty section says None.; an element that is not a software part is a usage error.

0.55.0 — 2026-10-22

  • New: stereotypes (metadata) are typed, queryable, styleable and checkable (#374–#379, #387, #389, #390). MetadataDef stereotypes carry tagged values, specialise one another and apply to any element; syscribe meta [--def <D>] [--group-by <field>] reports applications, [diagram.stereotypes.<Def>] styles diagrams (fill, stroke, frames, legend), [[gates.coverage]] sets a coverage threshold per stereotype, and the MCP server exposes the same surface.
  • New: architecture rules (#369, #388, #396). An ArchitectureRule element states a constraint over the software structure: forbid-dependency, independence, allow-only, layering (with layer: on parts and layers: on the rule) and max-depth. Findings are E660–E663/W662/W663; a waivers: entry with a rationale and an expiry date suppresses a finding for one element, and an expired or unused waiver is W664.
  • New: operations bound to behaviour (#364, #391). errors: on an operation (E670) and realizedBy: naming the ActionDef that implements it, whose signature must match (E671, E672).
  • New: operation call sites (#364, #398, #401). A SendAction/PerformAction names the operation it calls with operation: <owner>::<name>; an unknown operation is E673 and arguments that do not match its input parameters are E674. Types and units of the values are not yet checked.
  • New: data types with value constraints (#366, #393): range:, pattern: and default: on an AttributeDef.
  • New: sequence diagrams take a part as subject through the actions it performs (#365, #392).
  • New: resource budgets (#368, #394, #395). syscribe budgets [--json] rolls up memory use (ram, flash, nvm, stack against *Capacity and margin, E690/E691) and CPU load (period, deadline, wcet, priority; utilisation against the Liu–Layland bound for rate-monotonic or 1 for EDF, E692/E693).
  • New: deployment structure (#370, #397). deploymentKind (soc … thread) makes a part a node; nodes nest outermost first (E730, E731), a component sits on one node unless replicated: true (E732), and a node may not have a lower integrity level than what it hosts (E733).
  • New: software design levels (#371, #400). level: component | unit on a software part; a non-draft unit needs an implementedBy: (with a #symbol, W740), a satisfied requirement, an L1 test and a containing component (E740–E744).
  • New: the breakdown ADR requirement can be switched off (#399). [traceability] require_breakdown_adr = false in .syscribe.toml stops E310; a cited ADR is still checked (E311, W303) and a malformed entry is W632.

0.54.0 — 2026-10-13

  • Changed (behaviour): a command given an option it does not know now fails with a usage error (stderr names the option and lists the valid ones, exit 1) instead of ignoring it. About 40 commands used to ignore unknown options silently, among them audit, matrix, metrics, cyber-risk, feature-check, export-html, diff, claim, suspect, baseline, plantuml, magicgrid, safety-case and zones, so a mistyped audit --deny was never applied in CI. scripts still forwards its arguments to user scripts. A table-driven test covers about 48 commands, and the drift tests now require every accepted option to be documented on its help page.
  • Changed (behaviour): impact --kinds <unknown>, export-reqif --scope <unknown> and trade-study --config <unknown> are usage errors (exit 1); export-reqif used to write an empty document and trade-study an empty grid.
  • Fixed: export-reqif wrote mis-nested XHTML for a body that mixed bold and inline code (<xhtml:code>…<xhtml:strong></xhtml:code>), so import-reqif rejected the exporter's own output of the project model. The inline conversion is now nesting-safe, and the 412 requirements of model/ round-trip.
  • Fixed: suspect accept --all and --all-unbaselined reported links whose source is a row of a TARA or FMEA sheet as baselined, but the baseline was written to the sheet where the exploded row never reads it, so the same links were counted again on every run. These bulk commands now skip such links and list them, a single suspect accept of one is an error, and the sheet file is left unchanged.
  • Changed: feature accepts a FEAT-* id as well as a qualified or bare name; the cyber-risk --format error lists all seven formats; feature-check --summary (accepted but ignored until now) prints counts per code and severity instead of each finding; baseline create --date, magicgrid --output and plantuml -o are documented.
  • Fixed (docs): a review of the CLI reference, the 98 help pages, the specification, the guides and the demo and qualification documents against the 0.53.0 binary. Among the corrections: the CLI reference examples were regenerated from real output; the metrics, audit, set and safety-case sections were rewritten; the usage-error exit codes (connectivity, follow, impact and review exit 2 on a missing argument) are stated; the specification no longer says name: is the qualified-name segment, marks the checks it describes but the tool does not make (direction: values, typedBy: on a definition, unresolved multiplicity bound names, the 120-character name: limit, built-in ignore lists, gitignore syntax in .sysmlignore) as not enforced, documents import-reqif, and states the real W300, W303 and W039 conditions; the testLevel meanings agree everywhere (L1 unit, L2 property/fuzz, L3 formal proof, L4 emulator integration, L5 hardware-in-the-loop); satisfiedBy is documented as a computed index; the demo-model tables match the models; the tool-qualification page states that 122 of 478 test cases are evidenced by Rust tests and that the tracked TVR is a 0.43.0 snapshot; W050 is documented as catalogued but not currently emitted; mkdocs lists the seven design notes.

  • Fixed (docs): every frontmatter field the parser accepts is now documented in both the full specification and syscribe spec fields. 41 fields were missing from the CLI reference (the ResidualRisk, VulnerabilityReport, PlantDef, view and fault-rate fields among them) and 31 from the specification's Appendix A index (the plant, FMU, flowKind, attack-potential and common-cause fields among them). A new test, every_frontmatter_field_is_documented, reads the field names from the parser and fails when one has no entry in either document.

  • Changed: the LLM authoring prompt (--agent-instructions) gains a "Discovering what the tool can do" section (help, help <command>, spec <section>, template, MCP describe_type/explain_finding), a table of the executable-behaviour and evidence commands (simulate, inject, mutate, eval, constraints, requirement-coverage, exec-coverage, …), rows for the 17 commands it omitted, and a Part 9e map of executable models, plants, models:, context diagrams and feature placeholders. syscribe spec gains behaviour, evidence, diagrams and variability sections (the model-guide pages, embedded so they cannot drift), spec fields documents the plant, models:, role and flowKind fields, and the stale validation-code range in the spec index is gone. New tests agent_prompt_covers_every_command and agent_prompt_spec_sections_exist keep the prompt in step with the command list.
  • Fixed: selecting a feature selects its group parents (#228): a parameterBindings: entry on a parent no longer raises E203 when a descendant is selected, and such a parent is not reported as an orphan (W024), matching what configure already did.
  • Fixed: export-html no longer embeds the whole namespace tree in every page (#225). Each page lists the top-level packages, the siblings along the path to the element and its own children; the complete listing is written once as all-elements.html. The model/ site drops from about 175 MB to about 21 MB.
  • Fixed: W007 no longer fires for a type used only as a transition accept payload, or an action used only as a state's entryAction/doAction/exitAction or a transition effect (#224).
  • Fixed: a featureTree: id derived from a long name (Platform.HighPerformance) is cut to the 12-character FEAT segment limit instead of failing E006; a 1-character segment still needs an explicit id:, and the E006 message now says so (#227).

  • New: quantitative goal verdicts and the fault tree compared with the campaign (#343, REQ-TRS-GOALV-001, spec § Safety targets). metrics judges every goal with a quantified tree: the first-order PMHF/PFH when its events declare diagnosticCoverage (unchanged), else a rate-only PFH from the exact top-event probability over missionTime, or PFDavg = Σ Π λ·(1−DC)·TI^k/(k+1) when the goal's target: says mode: demand with a proofTestInterval. The limit is the goal's target.value, else [reliability.targets] in .syscribe.toml, else the built-in table, and the report names the source. A figure whose events fail with a probability above [reliability] plausibleProbability (default 0.1) over the mission is not credible; rateSource:/rateStatus: record a rate's provenance, a verdict on unverified rates says so, and list --rate-status finds them. metrics --sensitivity shows which events' rates move the verdict; audit and safety-case show the figure. inject --ft <FT> --consistency [--consistency-order N] [--max-runs M] reports every cut set with its executable verdict and every defeating set missing from the tree. New codes E985 (malformed target:), E986 (rateStatus), W988 (claimed rate above the bound), W989 ([reliability]); a rate-only or PFDavg figure gates (W033, metrics exit 2) only when the goal declares target: or .syscribe.toml sets the limit; otherwise its fail is advisory. On the grid-tie inverter SG-GTI-001's 1.4e-1 over 15 years is flagged not credible with FTE-GTI-005 its largest contributor, and the comparison finds sets the tree does not have (see the demo page).

  • New: richer invariants (#342, REQ-TRS-INV-001, spec §8.12.8). A composite scenario names a property with Where <name> is <expression> and gives its degraded form for a fault set with Except under <fault> [and <fault>…]: <expression>; a fault no clause names keeps the full property, and a set several clauses apply to needs a clause covering them all, else the run is an error, "no applicable degraded clause". Then within <d>: … must be reached by then and kept to the end, Then always … / from now on / never hold at every settled instant. simulate says when a scenario held only in a degraded clause, and inject, its report and its record mark such a set survived (degraded). The grid-tie invariants now state the safe state of SG-GTI-001 (gates off and both relays open) with its degraded forms; checking always found that the sensing common cause FTE-GTI-009 alone lets the inverter energise a dead grid for 1.1 s at start-up, recorded as the proposed decision RISK-GTI-011.
  • New: in-process plants (#340, REQ-TRS-PLANT-001, spec §8.8.6). A PlantDef declares parameters, inputs, outputs, states and der(x) = … / y := … equations in the expression language; a part becomes the plant with plant: (a PlantDef, or a library plant: Gain, FirstOrderLag, Integrator, Saturation, DelayLine, ImpedanceDivider). It runs at the composite's plantStep: with fixed-step RK4 or Euler, needs no FMI build feature or toolchain, and gives the same trace bit for bit on every platform. Faults act on plant parts: stuck/offset on outputs, silent, and the new parameter kind. The expression language gains exp, ln, sin, cos and tanh. New codes E938, E939. The grid-tie inverter's anti-islanding check now runs against a grid impedance plant.
  • New: campaign evidence and residual-risk decisions (#341, REQ-TRS-RISK-001, spec §12.14). inject --record [--run <id>] [--config <C>] keeps a fault-injection campaign in .syscribe/campaigns.json (composite hash, invariants, every set with its origin, verdict and failing invariant, sets not run, engine version); results campaigns [diff] lists and compares the records, and inject --report <file.json|file.md> writes one for an assessor with the decision and failure rates of each defeated set. A new ResidualRisk element (RISK-*: faultSet, status proposed | accepted | mitigated | rejected, goal, mitigatedBy, approvedBy, reviewDate, expires, campaignHash) records the decision on one defeated set. A defeat no decision names is W940 (gate it with --deny W940), a decision the campaign contradicts W941, a stale or expired decision W942/W943, a record of a composite that has changed W944; malformed decisions are E942/E943/E944. safety-case shows a solution node per campaign and audit the unexplained defeats. The grid-tie inverter records its US and India campaigns and proposes a decision on each defeated set.
  • New: deterministic diagram exports (#339, REQ-TRS-VIS-032). Text is measured with Liberation Sans advance widths compiled into syscribe instead of the installed fonts, so the same model exports the same bytes on every machine (boxes come out about a tenth wider than before: the installed-font path scaled glyphs by the font's line height instead of its em, so it measured Liberation Sans about 10 % narrow and the width margin only just made up for it). diagram export --all renders every diagram into <model>/generated (--format, --out-dir, one --config into generated/<CONF-id>), rewriting only what changed, writing PlantUML style includes relative to the file, and removing only renders it recorded in .syscribe-generated that no diagram produces any more; a render failure fails the run. --check writes nothing and exits 1 naming each file that differs, is missing or is left over. model_gti/generated/ holds the grid-tie renders and CI checks them.
  • New: diagram views (#338, REQ-TRS-VIS-031, spec §8.16.10). On a derived IBD, include: may be a mapping of kinds, domains, tags and features: the parts and edges it selects are drawn as usual, the parts that contain them stay as frames, and the rest is faded in every writer. style: <name> applies a [diagram.style.<name>] table of .syscribe.toml (context = "fade" | "hide", flows.<kind>, extends). layout: takes flow: left-to-right | top-to-bottom and layers: beside its pins. diagram export --config A --config B draws both products in one diagram, marking what only one has. A malformed view, style or hint is W421; a missing or cyclic extends is W419. model_gti gains GtiPowerView, GtiProtectionView and GtiSoftwareView.
  • Fixed: Mermaid output put a guard or label holding brackets ([then], [only CONF-A]) unquoted inside an edge's |…| or a port's circle, which Mermaid cannot parse; such labels are now quoted (#338).
  • New: system context and external actors (#337, REQ-TRS-VIS-030, spec §12.13). A part usage marked role: external is an actor outside the product: derived IBDs draw it «actor» (an environment part «environment», dashed) and derived BDDs mark its definition «actor». In a context composite, a part holding an actor, a port of a product part that nothing reaches is W996. External parts are never evidence, like environment parts. model_gti/Context/GtiContext puts the inverter beside the PV array, the grid, the owner's head-end, the installer tool and the rapid-shutdown initiator, with the diagrams GtiContextBdd and GtiContextIbd; the inverter gains boundary ports bound to the parts that serve them.
  • New: grouping and containment in derived IBDs (#336, REQ-TRS-VIS-029, spec §8.16.8.2). depth: draws parts inside parts with their ports and connections; a deployment package allocated to hardware is drawn inside it; a safety level (silLevel:, asilLevel:, a safety stereotype) outlines a part with its level and appliesWhen: badges it optional, through the node mark, with an SVG legend when anything is marked; groupBy: domain frames the parts by domain: (containment wins; the domain becomes a banner). A self-containing definition is opened once and depth: is capped at 16; with several hosts a deployment package goes into the nearest; PlantUML and DOT draw the marks and containment; under --config nothing is badged optional. An unknown or misplaced groupBy: is W420. The GTI GtiIbd shows the firmware inside the STM32 inside the control board.
  • New: flow kinds in diagrams (#335, REQ-TRS-VIS-028, spec §8.16.9). flowKind: on a PortDef, a port feature or a connections: entry (power, signal, command, data, protection, mechanical) styles the edge in SVG, sprotty, DOT, Mermaid and PlantUML; a [diagram] table in .syscribe.toml restyles a kind ([diagram.styles.<kind>]) and places ports by kind ([diagram.portSides]), with a port's own side: winning. An unknown kind or side, or a malformed [diagram] entry, is W419. A model that names no flow kind draws exactly as before. The GTI model's power stage IBD now shows its DC, AC, gate-command and sensing paths.
  • New: executable evidence (#333, #344, REQ-TRS-EXECEV-001, spec §12.12, docs/model-guide/executable-evidence.md). requirement-coverage runs the scenarios of every active TestCase whose subject is a machine, action or composite, in-process, and grades each requirement executable, executable-weak (a failing scenario, or below --min-states/--min-transitions/--min-guards/--min-score), descriptive-only, unverified or not-applicable (inspection, analysis, or a parent whose children all have executable evidence), with the scenarios, the coverage of the machines that carry it and mutation scores; a scenario counts only when its subject exercises what satisfies the requirement. exec-coverage shows the same evidence per software/hardware element: executable itself, modelled by, or not modelled, with its scenarios, correspondence findings and requirements by verdict. Gates --min-executable, --min-modelled and --require exit 2. Scenarios narrow their TestCase's verifies: with @verifies REQ-A,REQ-B tags or # verifies: step comments; a claim outside verifies: is W994, an unclaimed requirement when every scenario is tagged W995. mutate --record keeps scores in .syscribe/mutation.json (stale when the machine changes); --mutate computes them. MCP tools requirement_coverage and exec_coverage. model_gti/ tags its protection scenarios.
  • New: verification composites (#332, REQ-TRS-VCOMP-001, spec §12.11): an architecture PartDef that carries exhibitsStates: is used directly in a TestCase's subject composite and needs no models:, counting as its own counterpart for W991 and exercising its requirements for W992. role: environment on a part usage marks the test set-up (a grid source, a stimulus): no architecture counterpart, never evidence, its own models:/portMap: ignored (W993), listed with [environment] and left out of the aggregate in simulate --coverage, and listed apart in inject with environment-only fault sets marked. An unknown role: or one on a port is E992. In model_gti/, the grid source is an environment part and System::Software::Supervisor carries the supervisor machine (SupervisorPart removed).
  • New: typed ports (#331, REQ-TRS-PORTTYPE-001, spec §8.8.5): a port typedBy: a PortDef carries the events its ItemDef items name, with direction: per item and isConjugated: true reversing it. A machine that sends or accepts an event the type does not carry or carries the other way, or names a payload field the item lacks, is E932; a payload value or use of an accepted field of the wrong type or unit dimension is E935. Untyped ports are unchanged. With models:, ports of the same type and conjugation correspond without portMap:, and differently typed counterparts are E991. model_gti/Interfaces/ types the protection chain and the architecture ports alike, and four portMap:s are gone.
  • New: models: links an executable part to the architecture element it is a behavioural model of (#330, REQ-TRS-MODELS-001, spec §12.11, docs/model-guide/behaviour-models.md), with portMap: (a port name, a list, or null), abstracts: (port names, or requirement ids the model cannot evidence) and fidelity:, on a definition or on a part usage for one-to-many. New checks, dormant without models:: E990 target, E991 executable port correspondence and direction, W990 uncovered architecture port (checked on the union of modelling parts), W991 connection correspondence both ways (HW/SW boundary skipped), W992 a TestCase whose subject cannot evidence a requirement it verifies. The link shows in links, refs, follow (models/modeledBy), impact, trace, why and suspect-link detection. model_gti/ declares it on every behaviour part.
  • Fixed: a state-machine placeholder for a feature parameter with no value:/default: no longer raises a parse error at the { (#328, REQ-TRS-PROJ-009): the base model checks the expression with a stand-in of the parameter's type and reports the parameter once as W248 on its FeatureDef, naming the machines. validate --config and each Configuration of --all-configs check machines at their own bound values, without changing what suspect links and baselines hash.
  • Changed: a Configuration id needs no numeric suffix, like FEAT-* and BL-* ids (#327, REQ-TRS-ID-008): CONF-GTI-US-M3 validates without E200/W042, and so does a bare CONF-001; the numeric form CONF-GTI-US-001 still validates and an extra [ids.prefixes] prefix for Configuration follows the same grammar.
  • Changed: feature references (#325). Inline requires:/excludes: on a featureTree: entry resolve like crossTreeConstraints: values, so requires: [Protection.Afci] works; E212, E209, E222 and E241 name the form their field accepts and the closest match; a Configuration features: key that names no feature is E239 (it used to select nothing silently).
  • Fixed: W012 no longer fires for a mandatory: true feature, and suggests mandatory: true rather than the legacy groupKind: mandatory (#326, REQ-TRS-FM-007).
  • New: state machines can use feature parameters (#311): {{Feature.param}} placeholders in guards, assignments and durations, with --config on compile, mutate and inject.
  • New: FMEA rows can be gated by variant, and fault values can follow feature parameters (#313).
  • Changed: a test plan bound to configurations is a plan for those products only, and selection skips test cases that run in none of them (#314); the escaping-reference check also skips a plan bound to other products. A satisfies link to a requirement the variant does not have is not an escaping reference (#312).
  • Changed: mutate makes no swap-order mutant for transitions with provably disjoint guards (#315, part a). Grid-aware literal shifts (part b) remain open.
  • Changed: inject says that higher-order cut sets were left out rather than reporting an analysis overflow (#316).
  • Fixed: virtual time runs on a 1 ns grid, so split delays reach timers at any absolute time (#310).
  • New: analysis graphs in the Diagram IR (#223, phase 2) — diagramKind: Traceability | ZoneConduit | ThreatGraph derive the hazard-to-test graph (HazardousEvent ← SafetyGoal ← Requirement ← … ← TestCase with each goal's fault tree and arguments; nodes toned by the roll-up of their tests, ASIL/status/verdict shown, gaps as red badges naming W002/W003/W305/W300, no requirement, no goal), the IEC 62443 zone model (zones as compound nodes holding their parts and allocated security controls, SL target / achieved labels, red with an SL gap badge when short, conduits as edges labelled CD-… · SL achieved/required, weak conduits red, heavy and dashed) and the TARA chain (ThreatScenario → DamageScenario → Asset → CybersecurityGoal → SecurityControl, threats toned by risk under the configured [cyber] method, W802 on an unimplemented goal). New Zone node kind and impacts/affects/protectedBy/implementedBy/conduit/weakConduit edge kinds; the sprotty client, SVG, Mermaid, DOT (zones as clusters, rankdir from the layout, #rgb colours expanded for Graphviz) and PlantUML writers draw them. New hara trace [<subject>] --format dot|mermaid|plantuml|svg (with the ingested test verdicts), zones --format …, cyber-risk --format dot|mermaid|plantuml|svg (the heat md|html|json stay), diagram export for the three kinds, and the element detail panel of a hazardous event, goal, requirement that traces to a goal, zone, conduit, threat, damage scenario, asset, cybersecurity goal or control embeds the graph; the New diagram dialog offers all three. Wrong subjects are the existing W418; no new codes. Shared zone logic moved to syscribe_model::zones so the reports and the picture agree. Examples in model_auto/ (new assets, zones, conduits and security-control allocations) and model_sil/.
  • Fixed: connectivity stopped at a safety or security analysis element (#223) — a walk from a SafetyGoal, HazardousEvent, FaultTree/gate/event, AttackTree/gate, ThreatScenario, DamageScenario, CybersecurityGoal or SecurityControl now also follows hazardousEvents:, topEvent:, gate inputs:, event ref:, threatRef:, damageScenarios:, threatScenarios:, implementsGoals:, mitigatedBy: and the derived-from-goal links by default, and --kinds accepts those link names.
  • Fixed: zones --coverage showed — in every control column (#223) — it looked for a SecurityControl among a zone's members: (which must be parts, E955) and in a conduit's implementedBy:, never at the Allocation that binds a control to the architecture. A control now counts for a zone when it is allocated to one of its parts (members: or inZone:), the zone or a touching conduit; zones also counts inZone: parts as members.
  • Changed: safety diagrams polished (#223 follow-up) - fault-tree and attack-tree nodes are labelled with their stable id and the full name wraps beneath it (new word-wrapping in size.rs); a gate or event is a description box with its standard symbol hung on a stub (AND flat-bottomed D, OR shield, XOR with a second arc, NOT triangle with bubble, inhibit hexagon; basic-event circle, undeveloped-event diamond, house pentagon), tree edges are routed as a bus with an arrowhead into the gate (browser and SVG alike), GSN undeveloped diamonds sit inside the node box, SVG exports carry a tone legend, and DOT output is Graphviz-valid (six-digit colours, wrapped text, undeveloped diamond). Derived GSN diagrams now show real test verdicts from .syscribe/results.json and the derived attack tree uses the model's [cyber] configuration, as W035 does.
  • New: heat tables (#223) - syscribe_model::heat builds a grid (rows, columns, cells with element ids, tone, label) rendered as Markdown, JSON or a standalone self-contained HTML page: FMEA severity x occurrence with RPN colouring (fmea report --format md|html|json), the HARA S/E/C -> ASIL matrix with hazardous events and safety goals placed in cells (new hara matrix [--format ...]), and the TARA impact x feasibility risk matrix under the configured [cyber] method (cyber-risk --format md|html|json). export-html gains reports/heat.html (its page count now includes it) and syscribe-server serves /heat. Default fmea report / cyber-risk output is unchanged.
  • New: safety diagrams in the Diagram IR (#223, phase 1) — diagramKind: FaultTree | AttackTree | SafetyCase (alias GSN) derive a fault tree (IEC 61025 gate symbols, event shapes by eventKind, λ/probability labels, single points and cut-set members highlighted and the top-event probability on the root, from fault-tree analyze), an attack tree (coloured by rolled-up feasibility, easiest path emphasised, W035 badge) and a GSN argument (goal/strategy/solution/context/justification/assumption shapes, undeveloped diamonds, status/verdict overlays) from the model. New generic Node.mark overlay (status, value, tone, badges, emphasis) drawn by the sprotty client, SVG, Mermaid, DOT and PlantUML writers; new diagram export --format dot, safety-case --format text|json|dot|mermaid and fault-tree render <FT> --format mermaid|dot|svg|plantuml (plain render keeps its flowchart); the element detail panel of a FaultTree/AttackTree/SafetyGoal/Argument/ThreatScenario embeds the derived diagram with node click-through, /api/diagrams/model/<qname> serves it without a Diagram element, and the New diagram dialog offers the three kinds. Wrong subjects are the existing W418; no new codes. Examples in model_auto/ (FaultTreeEngine, AttackTreeTorqueReplay, SafetyCaseEngine, plus an attack tree and a GSN argument) and model_sil/.
  • New: fault-tree analysis (#211) — syscribe_model::fta (BDD-based; cut sets, exact top-event probability over missionTime, Fussell-Vesely/Birnbaum/RAW importance, per-event roles, beta-factor CCF via ccfGroup:/ccfBeta:) and fault-tree analyze <FT> [--json] [--max-order N] [--no-ccf].
  • New: fault-tree structural validation (#212) — E980 gate cycle/self-input, E981 gate arity (NOT/XOR/inhibit), E982 negative failureRate, E983 probability out of range, E984 ccfBeta out of range, W980 unreachable node, W981 node outside a FaultTree directory, W982 single-input AND/OR, W983/W984 CCF group problems, W987 unparsable missionTime.
  • Changed: metrics is driven by minimal cut sets (#211, #213) — gate logic now matters (AND vs OR), unreachable/house/negative-λ events are skipped, PMHF = λ_RF + λ_DPF (dual-point rate over missionTime) instead of adding the latent rate, missing DC/DCl count as 0 with W985 (and W986 for a missing missionTime), DC/DCl are clamped (no more LFM 2.0), SIL 1 is gated, a computed-but-untargeted goal shows no target, and metrics exits 2 when a goal fails.
  • New: security-analysis validation gaps (#219, #220, #221): E960 names the offending field when securityProperty:/derivedFromCybersecurityGoal: has the wrong shape (both now also accept a list); TARASheet rows get E961 (no id) / E962 (unknown key) and a new assetTable:; E963/E964 dangling Asset.assetOwner/relatedSafetyGoal; E965 attack-tree cycle, W966-W968 multiple roots / unscored step / duplicate input; W960-W965 incomplete risk inputs, orphan or asset-less DamageScenario, riskTreatment consistency; W969/W970 orphan SecurityControl/CybersecurityGoal; W971-W973 zone/conduit consistency; VulnerabilityReport W974-W979/E967 (CVE id, status vocabulary, resolution evidence, CVSS vector/severity, threat link) with new cvssVector/cvssSeverity/fixedIn fields.
  • Changed: conduits --json reports pass: null (not true) when achievedSL or a zone targetSL is unknown; co-analysis expands a HazardousEvent hazardRef to the SafetyGoals that list it; sbom emits CycloneDX vulnerabilities (VEX) from VulnerabilityReports, matched to components by pkg: purl or owning part, and affectedElements: accepts pkg: URLs.
  • Changed: SysML v2 ingest keeps the full dotted path of connect/bind/flow endpoints (Owner::a::b::c) instead of collapsing to the head part; W542 no longer applies to connect (#206). Endpoints of ingested .sysml elements are now checked by E127/W056.
  • New: E128 — unresolved via/to on send/accept actions and transition accepts; flow/succession endpoints on structural elements are checked like connections: endpoints (#207).
  • New: W068 — a redefining feature's multiplicity: is not contained in the redefined feature's (#208).
  • Changed: W057/W044 understand SI prefixes (kN, mm, MHz) and judge prefixed units by dimension (#209).
  • Changed: complete ISQ/SI/SIPrefixes/USCustomaryUnits/ScalarValues/Base name tables; an unknown bare name or membership import under a library wildcard (import ISQ::*) is now reported (#210).
  • Changed (behaviour): audit with ingested test results now fails when a safety goal is failing, adds a Verification results section, and W312 is in the default [audit] fail_on (a project that sets its own fail_on must add it) (#256).
  • Changed (behaviour): the suspect-link projection excludes workflow state (status while progressing, claimedBy, claimedAt, assignedTo); baselines captured before this need one suspect accept --all (#251).
  • Changed (behaviour): exploded TARA/FMEA rows inherit sheet-level responsibility/appliesWhen/tags; baselines sealed over such rows drift once (#229).
  • Changed (behaviour): audit no longer reports PASS for a model with a failing safety metric or an uncovered high-integrity goal: W033 and W805 on an ASIL C/D SafetyGoal now fail the verdict (exit 2) by default, alongside W306. Relax or extend this with an [audit] table in .syscribe.toml (fail_on = [...] for codes that fail at any level, [audit.fail_on_asil] mapping a code to the ASIL levels at which it fails; fail_on_asil = {} opts out). A malformed entry is W934 (#216).
  • New: audit gains Safety (hazards, goals by integrity level, FTA, FMEA, hardware metrics, FFI gaps) and Security (TARA artefacts, CAL distribution, vulnerabilities, IEC 62443 zones) sections in text and --json (#216).
  • Changed: safety-case always folds in the implicit derivedFromSafetyGoal Requirement chain (it was dropped whenever a goal had any Argument), walks derivedChildren transitively down to verifying TestCases, marks undeveloped nodes [UNDEVELOPED], prints a per-goal verdict and a completeness summary (also in --json, as status/undeveloped/completeness), and exits 1 for an unknown goal id. The traversal now lives in the public syscribe_model::safety_case module (build, SafetyCaseNode, NodeStatus, GoalVerdict, Completeness) so diagram derivers can reuse it (#217).
  • New: E881 Argument cycle; W861 solution Argument with no evidence; argumentType also accepts context, justification, assumption and undeveloped (#217).
  • New: W931 FMEA row without severity/occurrence/detection; W932 severity >= 9 without a recommendedAction regardless of RPN; FMEA rows may carry failureRate/diagnosticCoverage/latentDiagnosticCoverage and, via ftaRef, feed the hardware metrics/W033. fmea report drops the duplicate Name column, labels recommendedAction as Recommended Action, lists a duplicate-id row once, and exits 1 for an unknown --fmea-sheet; an unresolved FMEA ref is reported once (W904, no longer also E115) (#218).
  • New: ASIL decomposition validation (#214): E878 illegal ISO 26262-9 pair (D -> A+A, D -> B+A, ...), E879 bad decomposedFrom:; asilLevel: QM is accepted, the notation asilLevel: B(D) / QM(D) and a decomposedFrom: field are supported, E010 now lists the valid values, and E865/W860 apply at every integrity level (not only ASIL D / SIL 4).
  • New: HARA checks (#215): the ASIL is derived from S/E/C (ISO 26262-3 Table 4) and shown by show as derivedASIL; W811 goal ASIL lower than derived, W812 ASIL C/D or SIL 3/4 goal without safeState/ftti, W813 partial S/E/C set, W814 mixed ISO 26262 / IEC 61508 parameters, E880 invalid ftti unit.
  • New: configurable ISO/SAE 21434 risk and CAL (#222) — a [cyber] table in .syscribe.toml selects method = "simple" (default, unchanged) or "annex" (built-in example tables modelled on the standard's informative annexes; not normative, verify against your copy), overrides risk-matrix / CAL / risk→CAL cells, and scores attack potential (elapsedTime, expertise, knowledge, windowOfOpportunity, equipment on ThreatScenario/AttackStep, configurable thresholds); optional per-category impact ratings on DamageScenario (overall = max). cyber-risk, W031, W032 and attack-tree roll-up follow the configuration. New W640 (malformed [cyber] entry), W641, W642, E640, E641. With no [cyber] table nothing changes.

0.53.0 — 2026-10-09

  • New: MCP/REST create_element takes parent and writes <parent>/<id>.md for id-identified types and <dir>/_index.md for packages; move_element accepts an id as the last destination segment (#185).
  • New (opt-in): W065 — an id-identified element whose file stem differs from its id. Off by default; enable with [ids] check_file_names = true in .syscribe.toml, gate with --deny W065.
  • Fixed: feature editor keeps typed input across re-renders and drops stale fetches (#189); removeParameter refuses while a [repos] peer Configuration binds the parameter (#193); MCP guarded-write baseline is dropped after a post-refusal reload that read changed inputs (#196).

0.52.0 — 2026-10-09

SysMLv2 modelling gaps (GH #198–#205)

A probe that modelled a UAV, an elevator controller and a textual .sysml round trip found validation too lenient and ingest/export lossy. Fixed:

  • Fixed: imports: [ISQ::*] (or any library wildcard) on a package silenced every unresolved-reference check below it (#198).
  • New validation (errors): E115 unresolved behavior-field reference (sub-action/parameter typedBy, payload, includes, extends, subject, result, returnType), E116 succession/binding/flow endpoint that names nothing the element declares, E117 value outside a closed vocabulary (sub-action/control-node kind, loopKind, parameter direction) (#199). E118 malformed or reversed multiplicity, E119 bad visibility, E120 supertype: on a usage, E121 isVariant outside a variation, E122 enumeration without literals or specializing another, E123 usage typed by the wrong kind of definition (and conjugates: of a non-PortDef), E124 unknown enumeration literal, E125 interface/connection with fewer than two ends (#200). E126 unresolved imports:/aliases:/dependsOn:, E127 connection endpoint whose owning part does not exist (#201).
  • New validation (warnings): W056 connection endpoint port not found on its part, W057 unknown ISQ::/SI:: name, W058 name: differs from the file name, W059 private element referenced from outside its package.
  • Fixed: inline-feature redefines:/subsets: are resolved; a VerificationCase may verify a SysML requirement (E104); W007 counts a type used only by a sub-action or parameter; W502 understands Pkg::*/Pkg::**, {target, filter} entries and ViewDef.
  • Views: syscribe view render <View> materialises what a view exposes (tree/table/json/mermaid), with filterCondition: / per-entry filter: (@Metadata, not, and, or). PlantUML now renders Action, Allocation and UseCase diagrams. show prints ends, connections, parameters, sub-actions, time slices, imports, aliases and expose.
  • SysML v2 ingest: package imports are kept (bare imported library names no longer raise E111); anonymous connect, bind, perform, exhibit, interface … connect, interface def ends, port directions, ~PP conjugation and ref are mapped; one bad member no longer discards the whole file (W541 per member); dropped body members are counted in W543; a view's filter becomes filterCondition:. Dotted connect endpoints (eng.pwr) keep their full path as Owner::eng::pwr (GH #206): validation resolves the tail through the head's typedBy:/supertype: chain (E127/W056 for a missing member), the graph edge lands on the deepest resolvable prefix, export-sysml writes the dotted chain back, and connect no longer raises W542.
  • SysML v2 export: exports enumerations, library packages, allocations, use/analysis/verification cases, views, viewpoints, concerns, flows, individuals; imports/aliases, interface and connection ends, conjugation, bindings, flows, performs/exhibits, time slices, variation, parallel, action parameters, assert/negation, requirement subject/actors/requires/assume. Output is valid SysML v2 (per-segment quoting, relative feature chains, unquoted expressions, no duplicate anonymous connection) and every field it cannot write becomes a // dropped: comment counted in the summary.
  • Fixed: an unreadable directory now fails the model walk instead of silently dropping its subtree (this also stabilises the LSP failed-reload test).

0.51.0 — 2026-10-09

Review fixes

  • Security: the feature editor's restore op (POST /api/feature-model/edit, MCP edit_feature) joined a caller-supplied path onto the model root unchecked, so an absolute path or .. could create or delete files anywhere the process could, even on a preview or dry run. Every path the edit engine touches is now confined to the model.
  • Security: Markdown bodies are no longer rendered with live HTML. Raw HTML is shown as text and a link or image with a javascript:, vbscript: or data: target is pointed at # (the element card, detail panel and export-html).
  • Security: syscribe-server listens on 127.0.0.1:3000 by default (it has write routes and no authentication; pass --bind 0.0.0.0:3000 to expose it) and no longer sends permissive CORS headers, so another website open in the same browser can no longer drive its write API.
  • Fixed: an abstract feature's derived value could contradict the model. Each value is now fixed in turn so together they form one real model of the feature model (an alternative group whose members are abstract no longer derives all of them off), and a configuration that breaks requires:/excludes: no longer gets a spurious E219 on a mandatory abstract feature.
  • Fixed: derived abstract values are re-computed wherever configuration inheritance is rebuilt (the LSP rename gate no longer sees them vanish), show no longer claims a derive-less configuration inherits, the load list leaves them out, and W011/W012 skip abstract features.
  • Fixed: setAbstract refuses a feature some configuration already names (it would become E238), listing the configurations.
  • Fixed: MCP apply_changes now refuses update/delete of an entry synthesized from a shared sheet, as update_element/delete_element do (a delete removed the whole sheet).
  • Fixed: move of an element that has a directory of children beside its file moves both (it used to strand the file and break every rewritten reference), and rewrites qualified names inside appliesWhen:/formula expressions.
  • Fixed: the MCP watcher stops deferring reloads for a new file that stays broken (after four deferrals it reloads and reports the file), a lagging WebSocket client is told to reload instead of going silent, the diagram tab bar works (its inline handlers were malformed and broke on a quote in a directory name), the planning board no longer fetches twice (a ?who= deep link could be overwritten), undo/redo run one at a time, and the element panel retries after a failed load and refreshes after a live reload.
  • Tests: every testFunctions: name in a TestCase must now exist (tc_test_functions), which found and fixed three stale references; regression tests for each fix above.
  • Fixed (second pass): write_confined refuses an absolute path or .. before creating any directory; PATCH /api/diagrams/layout refuses an element that is not a Diagram; the guarded-write candidate copy follows directory symlinks and skips dangling ones; the detail panel's Save removes a key whose line was deleted (never type or id) and no longer writes the qualified name into name:; move no longer rewrites a name: label that happens to equal the moved name; an edit_feature undo/redo is refused when the file was changed elsewhere in between, so that change is not lost; the server skips a watcher reload for a change it already loaded (its own guarded write), keeping the cached baseline, and the page reloads once on WebSocket reconnect; the feature page serialises choices, drops overlapping selection responses (no doubled Impact block), keeps a typed configuration name after a refusal and refuses to save without an analysable model.
  • New: warning W240 when the model has more than 5000 features, so abstract features' derived values are not computed.
  • Derived abstract values need at most 5000 features in the model (the deep-analysis limit); above that an abstract feature has no derived value.

0.50.0 — 2026-10-08

An abstract feature's value is derived (REQ-TRS-FMED-004)

  • Changed: an abstract feature now has a value in every configuration, derived from the concrete selection: on exactly when the feature model forces it on (a selected child, a mandatory abstract parent, a requires: that targets it), otherwise off. Every reader of a configuration's selection sees it, so an appliesWhen: on an abstract feature is active exactly where the concrete selection entails it, projection and the matrix show it, and a requires: of an abstract feature is met by what entails it. show marks such entries (derived), and the configurator's load list does not offer them as choices.
  • Removed: warning W238 (an appliesWhen: naming an abstract feature), which flagged the gap this closes. It was emitted only in 0.49.0.

0.49.0 — 2026-10-08

Abstract features (REQ-TRS-FMED-004)

  • New: a feature can be marked abstract (isAbstract: true) from the browser's Edit mode and the MCP tool (setAbstract), and it now behaves as an abstract feature does in a proper feature model: it does not distinguish products (the product count, feature-check --enumerate and the configurator count variants over concrete features only), a Configuration must not name it (E238, selected or not; the configurator can still select one to explore, and its Save leaves abstract features out) and is judged on its concrete features with the abstract ones completed, a requires: that targets one a configuration does not name is not an E219, an appliesWhen: that names one is W238, and one with no children is W239. The diagram draws it dashed and italic and the Inspector says "abstract".

0.48.1 — 2026-10-08

A bound parameter is not removed (REQ-TRS-FMED-004)

  • Changed: removing a parameter that a Configuration binds is refused. The reply names the configurations, and the bindings must be removed first: the new removeBinding operation (a ✕ beside each binding in the Impact section in Edit mode, and in the MCP edit_feature tool) removes one. In 0.48.0 removing the parameter silently removed its bindings. Removing a whole feature still removes the choices and bindings that named it.
  • New: the Impact section lists the configurations' bindings of a feature's parameters, with their values.

0.48.0 — 2026-10-08

Feature editing everywhere, and a leaner write path (REQ-TRS-FMED-004, REQ-TRS-MCP-MEM-000)

  • New: the MCP tool edit_feature applies the same semantic feature-model edits as the browser's Edit mode through the guarded write: featureDelta says which features become dead or false-optional, whether the model becomes void and which configurations become invalid; an edit that makes things worse is held (needsConfirmation) until accept_worse; a commit returns its undo.
  • New: parameters can be added, replaced and removed (setParameter, removeParameter, and a form in the Edit panel); removing one removes its bindings from every Configuration, and removing or renaming a feature does the same for its parameters' bindings.
  • New: sheet entries take every edit. Rename, move, remove, constraints and parameters now work on features defined in a featureTree: sheet, including its crossTreeConstraints: list and the derived ids that a rename would change. Undo restores the touched files exactly.
  • Changed: a guarded write on a large model (3,000 elements or more) holds one model in memory instead of two, and keeps the live model's validation findings between writes instead of revalidating it before each. On a 12,000-element model the peak across writes falls from 126 to 85 MB and a write from 2.4 to 1.7 s.

0.47.0 — 2026-10-08

Feature model viewer, configurator, editor and analysis (REQ-TRS-FMED-001 to -007)

  • New: /features (header link Features) shows the product line's feature model as a feature diagram in FODA notation: mandatory and optional marks, XOR and OR group wedges, requires and excludes constraints as curves, parameters inside the box. Parents are centred over their children and several trees sit side by side. Collapse and expand subtrees, search by name or id, fit to the window, and click a feature for its state, why, its constraints and its documentation.
  • New: the SAT analysis is overlaid on the diagram, live: core, dead and false-optional features are marked with the constraints responsible, and a void model shows its conflict and the corrections that would fix it. GET /api/feature-model/analysis returns the same data.
  • New: diagramKind: FeatureModel draws the same diagram from a Diagram element (subject: a feature, a feature-model sheet or a package of features), exportable as SVG, PlantUML and Mermaid with diagram export and from the page; + Diagram offers it.
  • New: a Configure mode turns the diagram into a configurator: click to select, deselect or leave open; the model propagates the consequences at once (implied features shown as rings), counts the valid products that remain, and refuses a choice nothing can satisfy with the choices and constraints at fault. Load a stored Configuration, or save the completed product as a new one (REQ-TRS-FMED-003).
  • New: an Edit mode changes the feature model from the diagram: rename, mandatory or optional, XOR/OR/free groups, add and remove features and requires/excludes constraints, move a feature under another or drag it there. Every edit goes through the guarded-write engine and is checked first: one that makes a feature dead, forced on, the model void or a configuration invalid is held with the exact consequences until you confirm. Undo and redo for the session (REQ-TRS-FMED-004).
  • New: selecting a feature shows its Impact: the elements whose appliesWhen: names it by type (and through which packages), the configurations that select or deselect it, what requires or excludes it, and a preview of what removing it would break (REQ-TRS-FMED-005).
  • New: a Matrix of features against every stored configuration, with a two-way comparison that highlights where two configurations differ (REQ-TRS-FMED-006).
  • Changed: the feature analysis handles 5,000 features, up from 1,000, and is several times faster: each satisfying model witnesses every feature at once instead of one solver call per feature and direction, and an unsatisfiable core is found on one incremental solver instead of rebuilding it per constraint. A 2,000-feature model is analysed in about 0.2 s and a configurator click answered in about 0.3 s. Expand level opens a large model one level at a time, and a diagram too wide to read is shown from its first root instead of as a speck (REQ-TRS-FMED-007).
  • Fixed: moving or renaming an element (syscribe mv, MCP move_element) did not rewrite qualified names used as map keys, so a Configuration's features: and parameterBindings: still named the old feature.
  • Fixed: feature-check --deep reported a mandatory feature with the default group kind as false-optional (W018). Only an optional member can be false-optional.

0.46.0 — 2026-10-08

MCP server memory (REQ-TRS-MCP-MEM-000)

A model of 12,000 elements used 121 MB at rest and grew by 27 to 40 MB with every guarded write, reaching 342 MB after a few operations. It now uses 62 MB at rest, does not grow with writes, and peaks at 126 MB.

  • Changed: an in-memory element record is 1,792 bytes instead of 7,008. Rarely-set frontmatter fields are boxed in three tiers and allocated only when an element sets one; every field is still read and written as before.
  • Fixed: resident memory kept climbing after each write or reload on Linux. The server now caps glibc's per-thread malloc arenas at startup and returns free memory after every rebuild.
  • New: the server_stats MCP tool reports element count, body bytes, bytes per element record, and resident and peak resident memory (Linux). The watcher's reload log line includes the resident size.
  • New: a regression test loads 12,000 elements and fails if memory exceeds its budget or grows across guarded writes. Measurements and the ideas still open are in docs/design/mcp-memory.md.

Planning dashboard (REQ-TRS-VIS-027)

  • New: /planning (header link Planning) is a live board of PlanningItems: counts per status, who and which agents are working now with claim ages, a column per status, and who/done filters. It refreshes on the model-reload WebSocket and a timer, so claim, release and agent edits show as they happen.

Element panel in the diagram editor (REQ-TRS-VIS-026)

  • New: clicking a shape, port or edge in a diagram opens an Element side panel with the depicted element's rendered Markdown (headings, tables, code, Mermaid), its identity and an Open full detail button; a port or part usage that is only an inline feature shows its declared properties and its type's documentation (REQ-TRS-VIS-026).

0.45.0 — 2026-10-08

Create diagrams in the browser; sequence diagrams, tabs and folders fixed (REQ-TRS-VIS-023, -024, -025)

  • New: a + Diagram button in the model browser opens a dialog to create a diagram — a name, a kind, derive from a subject or blank, an optional/required subject with suggestions limited to the element types that kind accepts, and a package (default Diagrams). It posts through the guarded-write engine, then opens the diagram in a tab.
  • New: a ⊕ Add existing element toolbar button opens a picker over the model and adds the chosen element to a hand-listed (manifest) diagram through POST /api/diagrams/shapes/{qname}: one guarded write that lists it under shapes: unpinned, so ELK places it, and never touches the element's file. Refused for a derived diagram, an unresolved or already-present element, and a diagram as the element (REQ-TRS-VIS-024).
  • Fixed: clicking a folder in the model browser did not show its contents straight away: the first click flipped the arrow and loaded nothing, the second collapsed it and then loaded the children (so the folder looked open under a closed arrow), the third did nothing. The row's inline onclick and an htmx hx-trigger filter shared one piece of state and the inline handler always ran first. One handler (static/js/tree-toggle.js) now owns the arrow, the state and the request: the first click opens and loads, the next collapses, and a failed load puts the row back. The model root row, which has no children to load, no longer shows a dead arrow.
  • Fixed: a hand-listed Sequence diagram without layout: pins (the demo's MissionExecutionSeq) drew piled at the origin in the browser and could not be exported (ELK layout failed: The edge needs to have exactly one edge section). It is now placed with the geometry a derived sequence diagram uses — lifelines in declaration order, one row per message, activation bars, fragments boxed around the messages whose ref lies under theirs, unlabelled messages named by their ref — and ELK's fixed algorithm is used only when every shape is pinned (REQ-TRS-VIS-025).
  • Fixed: in the web UI a diagram tab opened to a blank canvas with no tab strip. The stylesheet hides #sprotty-viewport and #canvas-tabs by default and the page script "showed" them by assigning an empty display, which only removes the inline style and leaves the stylesheet's none in force. Present since the editor first landed (2026-07-30); the editor itself, the REST routes and every exported picture were unaffected, which is why API-level tests and the exports never saw it. A new test (frontend/test/page-wiring.test.mjs) fails for any element the stylesheet hides that the page tries to show with an empty display.

0.44.1 — 2026-10-08

Windows release asset restored; stdio-plugin SIGPIPE fix

  • Windows: the 0.44.0 release has no x86_64-pc-windows-msvc asset — the PlantUML writer's snapshot files were named after qualified names containing ::, which Windows cannot check out. They now use __ (Diagrams__PowerSystemIBD.puml); every other 0.44.0 asset was built and published normally, including the embedded QuickJS/ELK on every cross-compiled target.
  • Stdio plugins: a plugin that exits without reading its stdin (echo '{}' is a legitimate plugin) could kill syscribe outright with SIGPIPE while the request was being written, because the binary restores SIGPIPE's default disposition so that piped output exits quietly. The runtime now masks the signal for the duration of that write. This was the intermittent run_missing_alias_entry_fails_clearly failure in CI; the test now reports the child's exit status and signal.
  • No format, schema or validation-code changes.

0.44.0 — 2026-10-08

Traceability export (ADR-SYS-TREX-001)

  • New command: syscribe trace-export [--config <C>] [--sort directory|asc|desc] [--out <file>] and the read-only MCP tool trace_export {config?, sort?} emit one JSON document covering every requirement in the model — native Requirement and SysML RequirementDef/Requirement — with its identity (qname, id, name, type, status, reqClass, reqDomain, file), derivation (derivedFrom, derivedChildren, breakdownAdr), satisfaction (satisfiedBy with type and domain), verification (verifiedBy with level, status and the ingested verdict), refinedBy, and a computed coverage block (leaf, satisfied, verified, integrationVerified) plus a summary of the counts (REQ-TRS-TREX-000..004).
  • Why: coverage questions were answered one requirement at a time (trace, why, who-verifies), as a grid (matrix) or by joining the whole-model export by hand; none of those could be restricted to a product-line variant and sorted predictably. One schema computed from the same reverse indices validate maintains — coverage applies exactly the W300/W002/W305 rules, a retired TestCase is listed but never counts, and a coverage = true link type that extends a built-in link contributes — keeps an external checker and the validator in agreement.
  • Usage: every reference is a full qualified name plus id; a dangling one is kept as { "qname": "<as written>", "unresolved": true }. --config projects onto a stored Configuration or an ad-hoc feature set exactly as export --config does (inactive elements omitted from every list; config records {id, qname, name, activeFeatures}; an invalid configuration is a usage error). --sort fixes the order of the requirement list and every nested list (directory, the walker order, is the default); the output is byte-identical across runs. Documented in syscribe help trace-export, docs/cli and the MCP help; qualified by REQ/TC-TRS-TREX-001..004 (PI-TREX-001).

CLI diagram toolkit removed (ADR-SYS-VIS-001, REQ-TRS-VIS-013)

  • Removed: the syscribe diagram command and all of its subcommands — list, render, measure, compose, layout, seq, req — together with its taffy/Cassowary/A* layout engine, *.layout.json workspace files, syscribe help diagram, the docs/cli section, the composed-SVG workflow in the authoring prompt, and the qualification cases REQ-TRS-DIAG-004/TC-TRS-DIAG-004 and REQ-TRS-META-002/TC-TRS-META-002. TC-TRS-LINK-002 is retired; REQ-TRS-LINK-002 will be re-verified against syscribe diagram export --format svg when it lands.
  • Why: the visualisation redesign (ADR-SYS-VIS-001, docs/design/visualisation.md) makes one Diagram IR in syscribe-model::vis the only rendering path, laid out in the browser; no backwards compatibility is kept for the old renderers. Phase 0 clears the ground.
  • Unchanged: render <diagram_path>, syscribe plantuml / plantuml render, every Diagram validation rule (E400–E404, W400–W415), and magicgrid --svg, which keeps its text metrics and element theme under crates/syscribe/src/svgkit/.
  • Dependencies: cassowary and pathfinding dropped from the syscribe crate.

Visualisation rebuilt on one Diagram IR (ADR-SYS-VIS-001, REQ-TRS-VIS-000..022)

  • One representation: every Diagram is built as one intermediate representation in syscribe-model::vis — from a hand-listed shapes:/edges:/layout: manifest, or derived from the model when the diagram declares only diagramKind: and subject: — and every renderer and exporter reads that IR. Design: docs/design/visualisation.md.
  • Derived diagrams for seven kinds: BDD (definitions, inheritance, composition, attribute/port compartments), IBD (boundary, owned parts, ports with direction, connections/flows/bindings), StateMachine (states, initial/final pseudostates, transitions labelled event [guard] / effect), the new Action kind (steps, decision/merge, fork/join, loops, successions — SysMLv2's action-flow view), Requirement (deriveReqt/satisfy/verify/containment with satisfying and verifying context nodes), Sequence (lifelines, messages in succession order, alt/loop fragments, activations) and Allocation (logical/physical lanes). include:/exclude: narrow a derived diagram; shape ids are deterministic (s-<qualified-name-slug>) so layout: pins survive regeneration. Demo diagrams: Diagrams::*Derived*.
  • Browser editor: the sprotty client lays diagrams out with ELK (sprotty-elk + elkjs, vendored, no CDN) — measured labels, orthogonal routing, ports on borders, inheritance pointing up. A dragged node becomes a pin; Pin all, Auto-layout and Save companion SVG are the three new toolbar actions; the connect gesture is port-aware and writes dotted chains relative to the subject. One style table (vis::style, stereotypes, arrowheads per spec §8.16.8, applied-MetadataDef banners) is owned in Rust and served to the client.
  • The same ELK engine inside the executable: the vendored elk.bundled.js runs under an embedded QuickJS, with node sizes computed once in Rust from shared font metrics and sent to the browser, so diagram export --format svg, export-html, MkDocs and MCP draw every diagram — pinned or not — with the same layout the browser shows. A committed Node-versus-QuickJS determinism test and a bundle-version pin guard it.
  • New command: syscribe diagram export <qname> --format plantuml|mermaid|svg [--out <file>]; MCP render_diagram accepts the same formats. Mermaid output carries %% ref: annotations; SVG output carries sysml:ref/sysml:source/sysml:target and [links] hyperlinks (REQ-TRS-LINK-002 re-verified).
  • New API routes: DELETE /api/diagrams/layout/{qname} (clear every pin; PATCH accepts null to remove one and w/h to pin a size) and PUT /api/diagrams/svg/{qname} (save a companion SVG, setting svgMode/svgFile).
  • New validation codes: E405 a malformed shapes:/edges:/layout: entry (previously the diagram rendered empty, silently), W416 a stale layout: pin, W417 an include:/exclude: entry naming no member (or filters on a manifest diagram), W418 a derived diagram whose subject: type does not fit its kind. W080 now applies only to manifest-sourced sequence diagrams.
  • Behaviour changes: manifest kind: values outside the spec vocabulary (TestCaseDef, flowConnection, supertype) are E405 — the demo model's three were corrected; export-html draws the IR first and uses a companion SVG only when there is nothing to draw; the PlantUML writer takes a block's stereotype from the element's real type rather than the manifest's word for it.
  • Dependencies: rquickjs (QuickJS, MIT; a C compiler is needed at build time), ab_glyph/fontdb moved to syscribe-model; frontend adds sprotty-elk and elkjs (EPL-2.0, vendored under crates/syscribe-model/vendor/elkjs/). Binaries grow by roughly 2.5 MB.
  • Qualification: REQ/TC-TRS-VIS-001..022 (plus -013 for the removal and -014 for coverage), TC-TRS-LINK-002 revived; PI-VIS-001..012 track the phases. Noted limits: a 200-node/300-edge layout takes about 7 s in a debug build under QuickJS (0.9 s under Node); release builds are faster.

0.43.0 — 2026-09-26

MCP guarded writes: the delta now reports every error (#187)

  • Before: validationDelta.newErrors and resolvedErrors contained only dangling references (EREF) and user-defined link-type errors (E630–E636). A change that failed a full validate (for example E310, a derived requirement with no breakdownAdr) came back with newErrors: [] and could be committed unnoticed.
  • Now: both lists contain every validator error the change introduces or resolves, and each error entry has a boolean gating. It is true for EREF and E630–E636 only.
  • Commit gate unchanged: only gating: true errors refuse a commit, so incomplete drafts stay creatable. The rest are reported with gating: false.
  • Note: some failures now list two errors, for example EREF and E103 for a dangling derivedFrom. REQ-TRS-MCP-008 / TC-TRS-MCP-008.

MCP guarded writes: no spurious findings for paths outside the model root (#186)

  • Before: the candidate copy was validated in the system temp directory, so a model-relative path leaving the model root ([plantuml] style_file = "../.plantuml/x.iuml", sourceFile: ../tests/t.py) never resolved there. Every write showed a spurious W415 or W004, once as new and once as resolved.
  • Now: the candidate is staged as a sibling of the model root (a hidden .syscribe-mcp-cand-* directory, removed after every call), so ../ paths resolve as in the real tree. If the parent is not writable it falls back to the temp directory. Finding messages that named the candidate root are rewritten to the real root, so a finding present before and after cancels out of the delta.

Install script and release checksums

  • install.sh: curl -fsSL https://raw.githubusercontent.com/sjames/syscribe/main/install.sh | sh installs the latest release binary for Linux (static musl build) or macOS into ~/.local/bin (--dir or SYSCRIBE_INSTALL_DIR to change it).
  • Checksums: each release now publishes <asset>.sha256 next to every binary, uploaded in the same step. The installer verifies the download against it and aborts on a mismatch. A release with no checksum asset, such as 0.42.0 and earlier, installs with a warning.
  • Mirrors: SYSCRIBE_DOWNLOAD_BASE overrides the download location.

Docs

  • README: reorganised around agent-safe writes, with a tagline, a real demo transcript and GIF (demo/), a short quickstart, cargo install --git instructions, and --read-only next to the MCP config examples. The long feature list moved to "Full Feature List".
  • Example: examples/chat-to-code/ is a real agent session that took an idea to a tested library through design discussion, ADRs, requirements, tests, a plan and implementation.
  • Site: the docs site description and title follow the new tagline.

0.42.0 — 2026-09-25

MCP server reloads automatically when model files change (#181)

  • Before: syscribe mcp loaded the model once and refreshed it only after its own write tools. Edits made by an editor, the CLI (set, claim, move), git checkout or another agent stayed invisible until the client called reload.
  • Now: a file watcher covers the model directory and any [repos] peers. After a short quiet period it reloads, but only when the model's inputs actually changed, so the server's own writes don't reload twice.
  • No blocking: the fresh model is built without holding the lock, so tool calls are never blocked.
  • Half-saved files: a file that newly fails to parse defers the reload (reload_deferred) and keeps the last good model.
  • Clients: they get a {"event":"reload","source":"watch"} log message and notifications/resources/list_changed.
  • Controls: the reload tool stays, and --no-watch disables watching. REQ-TRS-MCP-048 / TC-TRS-MCP-049.

Docs

  • README: a "Ways to use it" overview (CLI, GitHub Action, MCP server, LSP, web browser), and copy-paste setup for connecting the MCP server to Claude Code (claude mcp add) and to mcpServers-JSON clients.
  • Action description: the GitHub Action's Marketplace description is corrected and now mentions the MCP server.

0.41.0 — 2026-09-25

This release comes out of a full documentation and specification consistency review. The review checked the spec, the LLM prompts, the help pages and the guides against the code and the binary, found about 110 inconsistencies, and logged 37 tool bugs (#125–#179). All are fixed; #150 turned out not to be a bug. Several documented behaviours change as a result, so read the Behaviour changes section before upgrading a CI gate.

Behaviour changes

  • Unresolved structural references are now errors. Before, they were silently accepted. The new codes are E110 supertype, E111 typedBy (on the element or an inline feature), E112 subsets, E113 redefines and E114 satisfies. [repos] models still report them as E512. (#125)
  • validate gates:
  • --all-configs now applies --deny, --max-warnings, --warnings-as-errors, --profile and --file to each variant, and --config honours --profile and --file.
  • Exit codes are consistent everywhere: 0 clean, 1 errors or a usage error, 2 a gate tripped. An unresolvable --config now exits 1; it used to exit 2. (#126)
  • --config on a model with no feature model: it must now name a stored Configuration, and anything else is a usage error instead of a silent whole-model fallback.
  • trace, why, who-verifies, refs and links now apply the lens. (#139)
  • Code renumbering: the derive pass moves to E504–E506 (derive cycles are now detected, as E504). E500–E503 are only the Allocation codes. (#127, #141)
  • Argument checking: unsupported --where operators, invalid enum and count values, and unknown options are now usage errors; before, they matched nothing or were silently ignored. lint-docs on a missing path now fails. diagram subcommands now fail on an unknown element. (#129, #130, #133, #168)
  • Removed false positives:
  • W406/W407 only check inline-SVG diagrams, which removes 90 warnings from the bundled models. (#158)
  • Package-registry implementedBy: values are external, so they no longer raise W023. (#134)
  • Requirements derived from a safety or cybersecurity goal are not W005 orphans. (#151)
  • W301 had already been retired in 0.40.x.

New and completed features

  • Configuration inheritance through derivedFrom: (spec §9.8), with E234–E237. (#137)
  • repoImports mounting: peers mount at <package>::<as>, including for subConfigurations: and cross-tier bindings. E515 now also catches the same id exported by two peers. (#138, #146)
  • SysMLv2 allocation def is mapped, and allocate … to … clauses become allocation edges. (#142, #144)
  • New and completed fields:
  • about: comments on elements, with E027/W052.
  • locale: documentation variants.
  • ADR deciders:.
  • FaultTreeEvent ref:, with E927.
  • derive: is a recognised field.
  • The qualifiedName: identity override is removed; it now raises W049. (#164, #160, #159, #148, #141)
  • Constraints now enforced: ConfirmationMeasure status (E924), SL range (E925), Zone/Conduit status (E926), a transition with no endpoint (W929), a features-form allocation outside an Allocation element (W930), an FMEA row with no id (E923), and an overridden rpn: (W928). (#136, #142, #132)
  • Commands:
  • template works for every element type. (#135)
  • list matches every type. (#167)
  • MCP explain_finding explains every code. (#128)
  • set evidence.add no longer duplicates entries and keeps comments. (#152)
  • summarize --no-cache doesn't write the cache. (#169)
  • The attack-tree roll-up starts from the structural root. (#149)
  • The report is titled from the model's root package. (#174)
  • lint-docs and validate share the shape-ref rule. (#172)
  • Concurrency fix: the guarded-write temp directory could collide under concurrent writes; each write now gets a unique directory. (#156)

Documentation

  • Spec, spec digests, LLM prompt and guides now agree with the tool.
  • Field names are corrected, e.g. allocatedFrom/allocatedTo and diagramKind.
  • The qualified-name rule is stated correctly, and the ISO 26262/21434/61508 examples use the real schema.
  • Every element type is inventoried, and Asset and Baseline get schema sections.
  • Guarded by tests:
  • every documented YAML example validates (287 checked);
  • the validation-code catalogue, the rules page and spec §11.12 match the emitted codes;
  • --help is generated from the command registry;
  • the CLI reference, help pages and MCP/LSP pages cover the binary, and help-page examples run.
  • Site:
  • The landing page, README and web-UI docs are refreshed; the retired /canvas is gone.
  • Release notes for 0.1.1–0.39.0 are backfilled.
  • mkdocs build --strict passes.

CI and distribution

  • Static musl Linux binaries: syscribe-x86_64-unknown-linux-musl and syscribe-aarch64-unknown-linux-musl are published alongside the existing five.
  • More CI coverage:
  • The qualification workflow now runs cargo test --workspace, about 950 tests. (#179)
  • It triggers on prompts/, spec/, docs/ and workflow changes. (#154)
  • A SIGPIPE race that made qual harnesses flaky is fixed. (#178)

0.40.1 — 2026-09-24

This release replaces 0.40.0, which has been withdrawn. The 0.40.0 release accidentally committed about 23 MB of unrelated, in-progress test fixtures (crates/syscribe-model/tests/fixtures/plugins-src, including node_modules and built .wasm). The affected commits were rewritten to remove them, and the 0.40.0 tag and release were deleted. 0.40.1 contains everything listed under 0.40.0 below, plus:

  • Agent instructions use valid command syntax. The LLM authoring prompt (--agent-instructions) wrote 83 commands as syscribe model/ <cmd>, which the CLI rejects. They now use syscribe -m model/ <cmd>, and so do 15 more examples in the model guides. Two new tests check the embedded prompts: no example passes the model root without -m, and every example names a real subcommand.

0.40.0 — 2026-09-24 (withdrawn — superseded by 0.40.1)

Projects can declare their own relationship types in a [linkTypes.<name>] table of .syscribe.toml and write them on elements under a namespaced links: map (ADR-SYS-LINKTYPE-001, spec §12.10, guide).

  • Declared rules: each type can set description, inverse, sourceTypes/targetTypes, cardinality, acyclic and suspect. The codes are E630–E636, W630 and W631.
  • Variants of built-in links: extends = "satisfies" | "verifies" | "derivedFrom" | "refines" makes a type a named variant of that built-in link, with the same rules and reverse index. relax = [...] switches specific rules off for that type only (E312/E313, E104, E105/E310/W303, E316). coverage = false keeps the rule checks but gives no coverage credit. Built-in links are never relaxed.
  • Traversal:
  • New follow <elem> <link> [--reverse] [--transitive] [--depth N] [--format text|json|dot] and link-types [--json] commands.
  • links, refs, impact --kinds, trace, show, connectivity, the coverage reports, export-html, export-reqif and sbom all include custom links.
  • Findings raised by an extending link name it, e.g. (via links.<type>).
  • MCP:
  • New read-only link_types and follow tools.
  • A write that would introduce an E630–E636 error is refused.
  • LLM discovery:
  • syscribe -m <root> --agent-instructions appends the project's declared link types.
  • The authoring prompt tells agents to run link-types and never invent a type.
  • E630 lists the declared types.
  • Suspect links: custom links take part in suspect-link detection unless suspect = false.
  • Worked example: examples/link-types/.

W301 retired: a leaf requirement may have several satisfiers (#121)

  • A leaf requirement satisfied by more than one element is now legitimate, for example a PartDef plus the StateDef that gives it its behaviour, or redundant channels.
  • Leaf vs parent depends only on derivedFrom.
  • E312 and W300 are unchanged.

Package membership is generated from the directory (#120)

  • show <package> prints a ## Members (N) table. The web UI detail panel and export-html package pages list the same members, taken from the directory rather than from _index.md prose.
  • New advisory W103 in lint-docs: an _index.md that hand-lists three or more of its own members. It doesn't change the exit status.
  • The bundled models' _index.md files were rewritten to describe purpose and scope (ADR-SYS-PKG-001).

Fixes

  • ingest-results merges instead of overwriting. A session-log ingest no longer wipes earlier cargo-json/junit verdicts, or the other way round. Each format replaces only its own section of .syscribe/results.json, and legacy sidecars still load. The MCP ingest_results tool merges the same way.
  • --config on a model with no feature model: the argument must now name a stored Configuration, for example a MagicGrid parametric variant, in which case the whole model is used. Anything else exits non-zero instead of silently running over the whole model. This applies to every CLI --config command and the MCP config arguments (REQ-TRS-PROJ-001). A Baseline's frozenScope.config is unchanged.
  • MCP why_active reports a config it can't resolve instead of treating it as an empty selection.
  • Help text: set help now states that only status= is byte-preserving; the list operations re-serialize the frontmatter block.

Qualification

  • The 13 previously skipped qual TCs now have harnesses, so the suite runs 308/308 with 0 skipped.
  • New TCs: TC-TRS-LINKTYPE-001..012 and TC-TRS-PKG-001/002.
  • Fixed a SIGPIPE race that made grep assertions on large outputs flaky (qual/tests/lib.sh).

0.39.0 — 2026-09-15

Annotated-source ingestion

A package _index.md can declare annotationFormat: <label> with inline marker: (a regex), include: and exclude: (globs). Syscribe then scans the matching source files in-process for comment blocks that start with the marker and parses each block with the same frontmatter schema a .md file uses (ADR-SYS-ANNOTATE-001, guide).

  • doc: in a marker block becomes the element's documentation body.
  • implementedBy: is filled in from the marker's own source location when it isn't set (W563).
  • A native TestCase can verifies: an annotation-synthesized element (E104 widened a third time).
  • New codes E560, E561, W560–W563. annotationFormat: is mutually exclusive with foreignFormat: and sysmlSubmodel: on the same package (W562).
  • New annotations scan <qname-or-label> --dry-run scans one package without merging or validating.
  • Worked example: examples/annotated-source/c-firmware/.

Session-log results for manual verification (#113)

ingest-results --format session-log <file> ingests a JSON array of per-Gherkin-scenario records (testCase, scenario, steps, result, timestamp). A malformed record is a hard error and nothing is written. A TestCase with no testFunctions: gets its verdict from its scenario titles: any fail is a fail, every scenario recorded as pass is a pass, and partial coverage stays unknown. trace, matrix, safety-case and testplan show these verdicts.

PlanningItem workflow

  • set command (#112): set <id> status=<value>, set <id> evidence.add ref=<id>|path=<path> [rationale=<text>] and set <id> achieves.add <req-id>. Values are checked before anything is written, status= rewrites only that one line, and --dry-run previews a diff.
  • claim / release (#115): claim <PI-id> --by <agent-id> sets the new advisory claimedBy:/claimedAt: fields. It refuses a done item or one claimed by someone else. release <PI-id> clears both. claimedBy appears in show and list PlanningItem --json.
  • W310 (#114): a done PlanningItem whose achieves: requirement doesn't meet the W002/W305 verification bar is flagged on the PlanningItem's own file.
  • W311: two active PlanningItems (in_progress or claimed) that share an achieves: requirement or an evidence[].path.

CLI output

  • validate summary line (#116): text output now starts with a line such as 0 errors, 51 warnings. When a gate trips, the line ends in FAIL and names the mechanism (--deny, --warnings-as-errors, --profile or --max-warnings).
  • show Related footer (#117): show lists the relevant follow-up commands for the element's type (trace, who-verifies, impact, refs, connectivity, n2). --no-related hides it.

Documentation

  • Docs, templates and prompts now use the canonical derivedFromCybersecurityGoal field name that W804/W807 report (#84). The legacy alias still works.

0.38.0 — 2026-08-24

Stdio-subprocess foreign-format plugins

A package _index.md can declare foreignFormat: <alias> to hand its whole subtree to an external process configured under [plugins.<alias>] in .syscribe.toml (ADR-SYS-PLUGIN-002, guide). Syscribe writes one JSON request to the process's stdin and reads one {elements, diagnostics} envelope from its stdout. The plugin can be written in any language.

  • Plugins are not sandboxed. timeout_ms is the only enforced limit.
  • Plugin elements take part in cross-references like hand-authored ones, and a native TestCase can verifies: a plugin-synthesized element.
  • New codes E550, E551 and W550–W553.
  • New plugins run <alias> --dry-run shows a plugin's raw envelope.
  • Worked example: examples/stdio-plugins/toy-python/.

E108: duplicate qualified name

New E108 reports two elements with the same qualified name, whatever their origin. Before this, the last one silently won. It found redundant _index.md wrappers in model_sil/ and in qual fixtures, which were removed.

More SysMLv2 constructs mapped

Native SysMLv2 submodel ingestion now maps several more constructs onto the existing native schema:

  • state def/state → StateDef, with canonical transitions
  • action def/action → ActionDef, with a subActions: tree
  • view def, viewpoint def and rendering def
  • concern def/concern
  • flow def/flow, which also lifts onto the owning part's flowConnections:
  • enum def/enum
  • case def, analysis def and verification def

use case def is still unmapped.

VS Code extension 0.2.0

The extension in editors/vscode/ is ready for the Marketplace:

  • It finds or downloads the syscribe binary automatically. The new syscribe.version setting pins a release.
  • It is bundled with esbuild.
  • Activation has a timeout and fails with a clear error instead of hanging.
  • A CI workflow builds the .vsix on vscode-v* tags.

0.37.0 — 2026-08-18

Derived ids for featureTree: entries

A featureTree: entry's id: is now optional (REQ-TRS-FM-006). When it's left out, it is derived from the entry's dotted name:, so Platform.CortexM becomes FEAT-PLATFORM-CORTEXM. An explicit id: always wins. Invalid or colliding derived ids are reported by the existing E006 and E101. A plain per-file FeatureDef still needs an id (E201). MCP describe_type now lists FeatureModel.

0.36.1 — 2026-08-18

  • Bumped sysml-v2-parser from 0.53.0 to 0.54.0, which brings upstream parser fixes. No behavior change for Syscribe models.

0.36.0 — 2026-08-18

Single-file feature models

A type: FeatureModel sheet can hold a whole feature tree as one flat featureTree: list (REQ-TRS-FM-005, spec §9.6a). The walker turns each entry into an ordinary FeatureDef.

  • Entry names are dot-separated paths relative to the sheet (Platform.CortexM), so they get the same qualified names a directory layout would.
  • An optional crossTreeConstraints: list keeps requires:/excludes: edges in one place.
  • parameterConstraints: is accepted directly on the sheet.
  • New codes E231–E233 and W048.
  • Worked example: examples/single-file-feature-model/.

Fixes

  • requires:/excludes: now resolve bare FEAT-* ids. Before, they raised a false E212 and were dropped from feature-check --deep.
  • parameterConstraints: no longer triggers a false W047.
  • The features tree now nests by real FeatureDef ancestry.
  • Write operations (update_element, delete_element and move_element, in both the web server and MCP) now refuse elements that were synthesized from a shared sheet, such as FMEA/TARA rows or featureTree: entries. Before, they rewrote or moved the whole sheet file.
  • LSP go-to-definition on a featureTree: entry now jumps to that entry's line.

0.35.0 — 2026-08-14

SysMLv2 submodel improvements

  • @Syscribe* metadata annotations (#92): on a part def/part, these annotations set domain:, asilLevel:/silLevel:/plLevel:, shortName: and implementedBy:. The existing validation then applies to them.
  • Doc-comment lifting (#94): doc /* ... */ comments become the synthesized element's documentation body.
  • Connections (#95, #99): connect a to b (, c)* endpoints become resolvable connections: edges. A two-segment endpoint resolves to a nested feature redeclared on the usage. New W542 warns when an endpoint is truncated to its head (#104).
  • Trailing doc bodies (#98): a named connection usage's own trailing doc body is lifted.
  • Doc-comment directives (#100): interface def, port def and connection def accept @SyscribeDomain:, @SyscribeIntegrity:, @SyscribeShortName: and @SyscribeImplementedBy: lines in their doc comment.
  • Scoped n2 (#97): the axis now includes qname-nested child parts.
  • Package-relative references (#105, #107): package-relative typedBy:/supertype: references now resolve for W600 suppression, W007 usage tracking and the graph's TypedBy edge.

Validation and CLI

  • Shorter ids: the category segment is now optional in REQ, TC, ADR and PI ids, so REQ-042 is valid.
  • W600 (#101): no longer fires on a Part usage whose typedBy: target is documented.
  • template PlanningItem (#102): now works on the CLI and through MCP.
  • Configuration reference: spec fields now has a complete .syscribe.toml reference.

0.34.0 — 2026-08-08

PlanningItem assignedTo:

A PlanningItem can declare assignedTo: <username> (REQ-TRS-PLANITEM-008).

  • The value must be a Unix-style username (E723).
  • When .syscribe.toml has a non-empty [users] roster (alice = "Alice Nakamura"), the username must be in it (E722). A malformed roster key is W309.
  • show prints the display name.

0.33.0 — 2026-08-07

Native PlanningItem element type (#91)

type: PlanningItem (PI-* ids) is a work-item tree that is part of the traceability graph (ADR-SYS-PLANITEM-001).

  • Fields: status (todo | in_progress | blocked | done) and an optional itemType (bug | task | feature).
  • Hierarchy: a single parent: per item, with cycle detection.
  • Goals: achieves: is required on top-level items and must name Requirements. It is kept separate from satisfies:.
  • Variants: appliesWhen: gating works for PlanningItems.
  • Evidence: evidence: entries are ref: or path:, each with an optional rationale: waiver. A leaf item marked done needs at least one non-waived evidence entry that resolves (E719).
  • Dependencies: blockedBy: names what the item is waiting on. E720 reports a dangling target, E721 a cycle, and W308 a non-empty blockedBy: when the status isn't blocked.
  • Codes: E706–E721.
  • Worked example: examples/planning-item/.

Hierarchical product-line composition

A Configuration can consolidate other, already-configured Configurations through subConfigurations:, locally or across [repos], at any depth (ADR-SYS-HPLE-001).

  • Validity: each entry must resolve to a valid Configuration (E516–E518).
  • Parameter bindings: parameterBindings: reaches through the whole subtree. E519 and E523 reject illegal or redundant cross-tier bindings.
  • Open parameters: the opt-in W513 flags a required parameter left open anywhere in the subtree.
  • Isolation: a lower tier never refers to the configuration that consolidates it, and bindTo: never crosses a subConfigurations: boundary.
  • Worked example: examples/hple-multitier/.

Native SysMLv2/KerML submodels (#89)

A package marked sysmlSubmodel: true can hold .sysml/.kerml files. They are parsed in-process and merged into the graph (guide).

  • Merging and mapping: same-named packages from different files are merged, and a fixed set of element kinds is mapped.
  • Traceability: satisfy/verify can target native Requirements, and a native TestCase.verifies: can target a SysMLv2 element.
  • Variability: @SyscribeFeature{featureId} becomes appliesWhen:.
  • Codes: a stray nested _index.md is W540, and a parse failure is W541.
  • Worked example: examples/sysmlv2-submodel/.

Web UI: diagram-driven editing, /canvas removed

  • Editable diagrams: non-Mermaid diagrams use a new sprotty-based editor for create, delete, connect and move. Each edit goes through the guarded write engine, which now lives in syscribe-model::mutate, and returns a validation delta.
  • /canvas removed: the Cytoscape.js graph explorer (/canvas, /api/graph) and the old SVG-canvas drag/layout code were removed.
  • JSON API: responses use camelCase throughout. A refused write returns written: false.
  • Live reload: the tree and any open diagram refresh after a reload event.

Fixes (#90)

  • W024 no longer reports a FeatureDef as an orphan when it is referenced by bare id in appliesWhen:.
  • Attribute elements are no longer labelled Other.
  • The validation report now shows satisfies: targets written as qualified names.
  • delete_element's reference guard and the referential-integrity gate now see nested Allocation references (#87).

0.32.0 — 2026-07-23

Language Server (syscribe lsp)

A stdio Language Server for editors, using only standard LSP (ADR-SYS-LSP-001..003):

  • Navigation: diagnostics, go-to-definition, references, hover and workspace symbols.
  • Completion and rename: completion for cross-reference fields and enums, and rename of stable ids.
  • Code lenses: counts for verifiedBy, derived children and suspect links.
  • Quick fixes: for E310 (pick an accepted ADR) and W090 (accept a suspect link as reviewed).

A minimal VS Code client is included in editors/vscode/. The README now also covers suspect links, baselines and the MCP server.

0.31.0 — 2026-07-13

Suspect links flag a trace link whose target changed after the link was reviewed (ADR-SYS-SUSLINK-001).

  • Baselines: the source element stores a traceBaselines: map from each target to a blake3 hash of the target's normative content. A mismatch is W090.
  • Opt-in: links without a baseline stay silent in validate.
  • CLI: suspect list, suspect accept <src> <tgt>, suspect accept --all and suspect accept --all-unbaselined (for onboarding).
  • MCP: suspect_list, and a guarded suspect_accept.

Release baselines

type: Baseline (BL-*) freezes a scope of the model into a snapshot that is content-hashed and tied to a git commit (ADR-SYS-BASELINE-001).

  • Commands: baseline create, verify, diff, list and show.
  • Scope: frozenScope can cover the whole model, a package subtree, or type/status/tag filters. It can also project a Configuration (config=) or take the trace closure of a goal (closureFrom=).
  • Drift and tampering: drift is graded by status (E520 for released, W520 for approved). Tampering between the seal and the manifest is E521, and an unresolved supersedes is E522.
  • Output locations: configurable with [baselines] in .syscribe.toml.
  • MCP: read-only baseline_list, baseline_diff and baseline_verify.

0.30.0 — 2026-07-04

Scanning large requirement sets

New read-only commands, each also available as an MCP tool:

  • stats: histograms by facet, plus coverage and orphan rollups.
  • digest: one compact line per requirement, paged to a token budget.
  • search-text: BM25 full-text search.
  • summarize: a per-package summary built from excerpts.
  • topics: distinctive keywords per package.
  • clusters: TF-IDF k-means clustering.

All of them run offline and give the same result every time.

Schema

  • displayOrder: new optional numeric field that sets presentation order without renumbering ids.
  • W047: new warning for unrecognized frontmatter keys. reqClass is now a recognized field.

Fixes

  • find no longer panics when its length cap falls in the middle of a UTF-8 character.
  • matrix now shows a covered-but-failing requirement as ▣ instead of ✗.

0.29.0 — 2026-06-29

  • Consistent coverage: MCP coverage and coverage_matrix now use one shared classifier. A requirement covered only by draft TestCases is planned, not verified, and a covered requirement whose latest verdict is fail is failing. As a result, verified counts drop for models that rely on draft tests.

0.28.2 — 2026-06-29

  • Added a requirement and a regression test that every MCP tool input property has an object schema.

0.28.1 — 2026-06-29

  • MCP fix: the fields argument of create_element, update_element and apply_changes now has an object JSON schema. Strict MCP clients, including Claude Code, had rejected the whole tool list.

0.28.0 — 2026-06-29

Static HTML export

export-html [--out <dir>] [--css <file>] writes the whole model as a static site that works offline. It includes a page per element, inline diagrams, validation, coverage and traceability reports, and client-side search.

Eight more MCP tools

  • Evidence: ingest_results, coverage_matrix, coverage_gaps and evidence.
  • Diagrams and docs: lint_docs, render_diagram, diagram_coverage and generate_view.

This brings MCP to 37 tools. help mcp and the CLI docs now cover all of them.

0.27.1 — 2026-06-29

  • MCP coverage now reports only non-draft requirements as gaps.
  • The demo model gained integration-level TestCases for its approved parent requirements, which clears the W305 warnings.

0.27.0 — 2026-06-29

MCP server (syscribe mcp)

A Model Context Protocol server over stdio that lets LLM clients query and edit a model (ADR-SYS-MCP-001):

  • Read and navigate: search (with filters and full-text search), get_element, tree, trace, impact, validate and others.
  • Authoring helpers: template, next_id, check_ref, coverage and others.
  • Guarded writes: create_element, update_element, move_element, delete_element and the atomic apply_changes. Writes are dry-run by default and return a validation delta and a diff.
  • Feature-model tools: features, feature_check, configure, project, diff_configs and why_active.
  • Reports: run_report runs an allowlisted, read-only report command.
  • Read-only mode: --read-only hides the write tools.
  • Coverage: coverage separates uncovered leaf requirements from parents that are missing integration-level (L3–L5) tests.

0.26.41 — 2026-06-22

  • Extra id prefixes: the [ids.prefixes] table in .syscribe.toml adds stable-id prefixes per element type. For example, Requirement = ["STK", "SYS"] makes STK-SCHED-001 valid. The built-in prefix stays valid. A malformed entry is W046 and is ignored.
  • All clippy lints are resolved. No behavior change.

0.26.40 — 2026-06-22

  • CLI commands piped into a reader that exits early (| head, | grep -q) now exit quietly instead of panicking.

0.26.39 — 2026-06-22

  • Docs audit: docs, CLI help, spec templates and agent instructions were checked against the implementation.
  • All emitted E/W codes are now documented.
  • CLI help lists every subcommand.
  • Missing types were added to the spec templates.

0.26.38 — 2026-06-20

PlantUML styling and coverage

  • Styling: diagrams use a SysML-style colour scheme, shared via .plantuml/sysml.iuml, with a built-in fallback.
  • IBDs: containers nest recursively.
  • Labels: shapes and edges accept a label:.
  • Links: SVGs link to <base_url>/<path>.md, so links can point at GitHub. Links are omitted when base_url isn't set.
  • Demo models: model_auto/ now has one example of each diagram kind.

0.26.37 — 2026-06-19

plantuml render

  • Rendering: plantuml render [--jar <path>] [--dry-run] runs PlantUML on every companion .puml file. It finds PlantUML via --jar, then [plantuml] jar, then PLANTUML_JAR, then PATH.
  • Image links: plantuml adds a Markdown image link to the element body when it has none.
  • Demo models: all example diagrams now use pumlMode: companion with rendered SVGs.
  • CI: PlantUML generation and rendering run in CI.

0.26.36 — 2026-06-19

PlantUML companion diagrams

  • Generation: the new plantuml subcommand generates .puml source for Diagram elements marked pumlMode: companion (BDD, IBD, StateMachine, Sequence, Requirement). Use pumlFile: to set the output path.
  • Styling: configured under [plantuml] in .syscribe.toml (theme, style_file, base_url).
  • Codes: new E403, E404 and W413–W415.
  • Docs: the W023 docs were extended to Interface/InterfaceDef.

0.26.34 — 2026-06-18

implementedBy / W023 extended to Interface and InterfaceDef

Interface and InterfaceDef elements now participate in the §12.8 implementation-trace chain. Add implementedBy: to link an interface definition to its header file, IDL, ROS message definition, or any other source artifact that defines the interface contract. W023 fires for missing local paths on non-draft elements, with the same opt-in, draft-suppression, and remote-URI-exemption rules that apply to Part/PartDef.

  • W023 — extended to cover Interface and InterfaceDef (previously Part/PartDef only)
  • template interfacedef and template interface updated with commented-out implementedBy: examples
  • Spec, frontmatter reference, traceability guide, and LLM prompt all updated
  • 11 unit tests (REQ-TRS-IFACE-000..002, ADR-SYS-IFACE-001)

0.26.33 — 2026-06-17

Template and spec updates for build system integration fields

Documentation-only follow-up to v0.26.32. The template configuration output now includes commented-out buildOverrides: and parameterBindings: examples; the spec fields PLE table documents buildExports, buildOverrides, and the buildVar parameter sub-field.

No code or validation behavior change.

0.26.32 — 2026-06-15

Build-system configuration from a Configuration

The new build-config subcommand turns a Configuration's feature selections and parameter bindings into build variables. It outputs cmake, c-header, makefile, env, json or kconfig.

  • Schema: buildExports: on FeatureDef, buildVar: on a feature parameter, and buildOverrides: on Configuration.
  • Precedence: later sources win, in this order: buildExports:, then buildVar:, then buildOverrides:.
  • Flags: --all-configs emits a JSON array for CI matrices, and --prefix namespaces the variable names. The configuration is SAT-checked first unless you pass --no-validate.
  • Codes: new E050 (two features set the same variable) and the opt-in W050.
  • Fixes: spec/help now work after -m <root>, -mPATH is recognized, and derivedFrom: accepts a single string.
  • Docs: a new multi-page Practitioner Guide section.

0.26.31 — 2026-06-13

Documentation: multi-repository composition

Full documentation pass for the §14 multi-repo / git-submodule work (W510–W512):

  • New guide — Multi-Repository Composition: [repos] declaration, repoImports: mounting, cross-repo resolution, the reproducibility gates, and how [repos] composes with git submodules. Added to the site nav and the Modeling-Guide index.
  • Validation overview — the code-range table in docs/validation/index.md now covers the whole §13–§22 backlog (TestPlan, review records, multi-repo, decomposition/budgets, trade studies, IEC 62443, behavior), and the stale qualification-suite counts were corrected.
  • Cross-links and the W512 row added across the rule reference, CLI reference, and frontmatter reference; the README "What It Supports" list now includes variability, multi-repo composition, and the expanded rule set; CLAUDE.md gained a multi-repo commands block.

Documentation-only; no code or validation behavior change. mkdocs build --strict is clean.

0.26.30 — 2026-06-13

Submodule gitlink/ref consistency gate (W512, GH #62)

Multi-repo composition now integrates with git submodules (§14, REQ-TRS-TYPE-023). When a peer repo's path is a git submodule of the composing model's repository, validation compares the commit its ref: resolves to against the gitlink the parent repo records for that path (git ls-tree HEAD <submodule-path>) and emits W512 when they disagree — catching a .syscribe.toml ref: that has silently diverged from the .gitmodules pin. Gate CI with validate --deny W512. W512 is independent of W511 (gitlink pin vs ref:, not checkout vs ref:) and is never raised when path is not a submodule, no ref: is configured, or either commit cannot be resolved — so non-submodule compositions (sibling checkouts, monorepo paths) are unaffected. Verified by TC-TRS-TYPE-023 (4 assertions over a real parent-repo-plus-submodule). Qual 246/246; all models clean.

The two layers are complementary: a submodule provides the pinned checkout, and [repos] adds model-level cross-reference resolution plus the W511/W512 reproducibility gates on top.

0.26.29 — 2026-06-13

Peer-repository ref-drift gate (W511, GH #62)

Multi-repo composition now enforces reproducibility (§14, REQ-TRS-TYPE-022). When a peer repo in [repos] declares a ref:, validation compares the peer work tree's HEAD with the commit the ref: resolves to and emits W511 on drift — gate CI on a pinned composition with validate --deny W511. The drift state is computed once at load time (single source of truth shared by validation and the repos CLI); repos status reports the same drift and exits 2, and repos sync brings the checkout back to its ref:. Drift is never falsely reported when it cannot be determined — git unavailable, the peer is not a work tree, the ref: does not resolve, the path is absent, or no ref: is configured. Verified by TC-TRS-TYPE-022 (4 assertions over real isolated git work trees). Qual 245/245; all models clean.

0.26.28 — 2026-06-13

Multi-repository model composition (GH #62)

Large programs may now split a system model across repositories (§14, REQ-TRS-TYPE-021). A model declares peer repos in the [repos] table of its model-root .syscribe.toml (path, optional root default model/, optional ref), and a Package _index.md mounts a peer sub-tree with repoImports: [{repo, qname, as}]. Cross-repo verifies:/derivedFrom:/satisfies:/allocatedTo: references resolve against the local model first, then each loaded repo in declaration order — by global stable ID (REQ-*, TC-*, … unique across the whole composition) or qualified name.

  • Validation — E510 circular repo import, E511 missing path (no ref), E512 dangling cross-repo trace reference, E513 unknown repoImports alias, E514 unresolved import qname, E515 duplicate stable ID across repos, W510 unpinned repo (opt-in, --deny W510). The whole block is inert unless [repos] is configured, so single-repo models are unaffected.
  • CLI — repos list [--json] (configured repos with path/ref/on-disk + sync status), repos status [--json] (whether each pinned repo is at its ref; exits 2 on drift), repos sync [--all | <alias>] (git fetch + git checkout <ref>).
  • Verified by TC-TRS-TYPE-021 (10 assertions: the seven rules, a clean cross-repo composition, and repos list). Full qual suite 244/244; all shipped models validate clean.

This completes the §13–§22 spec-feature backlog (GH #61–#74).

0.26.27 — 2026-06-13

IEC 62443 Zone/Conduit model (GH #61)

  • Native Zone (ZN-*) and Conduit (CD-*) element types (§13) for industrial cybersecurity: a Zone groups parts under a Security Level (targetSL/achievedSL, members:); a Conduit connects two zones (fromZone/toZone, achievedSL, implementedBy: controls). PartDef/Part may carry targetSL/achievedSL/inZone:. (REQ-TRS-TYPE-020)
  • Validation — E950–E956 (required fields, ZN-*/CD-* ids, conduit endpoints resolve to zones, member/inZone type checks) and W950–W953 (SL gap, weak conduit boundary, isolated SL claim, approved zone with no conduit).
  • CLI — zones [--coverage] [--json] (zones + SL gap, or Zone × SecurityControl cross-table), conduits [--json] (conduits + SL adequacy), and template Zone/template Conduit. The demo model is extended with an avionics control zone, a datalink zone, and the conduit between them.

0.26.26 — 2026-06-13

lint-docs — diagram reference resolution (GH #74)

  • lint-docs now validates diagram references against the model, beyond the existing prose stable-ID check (W099): a qualified name (A::B::C) inside a ```mermaid block that does not resolve raises W100; an SVG sysml:ref="…" that does not resolve raises W101; a local Markdown image/diagram embed path (![](…), <img src>) that does not exist raises W102. (REQ-TRS-LINT-002)
  • lint-docs now scans .svg files in addition to .md. Qualified names in prose remain deliberately unresolved (no false-positive regression); SVGs with no sysml:ref are opaque; remote URIs (https://…) are accepted as external. All findings appear in text + --json and are gateable (--deny W100).

0.26.25 — 2026-06-13

ReqIF 1.2 export — export-reqif command (GH #73)

  • syscribe export-reqif [--output <f>] [--scope <qname>] [--config <C>] [--include-tests] [--zip] — exports native Requirement elements (and their packages) as a ReqIF 1.2 XML document for interchange with DOORS Next / Jama / Polarion / PTC. Read-only, export-only. (REQ-TRS-OUT-020)
  • Each requirement → a SPEC-OBJECT (SYSCRIBE_ID/NAME/QUALIFIED_NAME/STATUS enum/SIL_LEVEL int/ASIL_LEVEL/DOMAIN enum + an XHTML DESC converted best-effort from the body, Gherkin omitted); packages → a nested SPEC-HIERARCHY; derivedFrom: → DERIVED_FROM SPEC-RELATIONs; --include-tests adds TEST_CASE objects + VERIFIED_BY relations.
  • --output writes <file>.reqif, or <file>.reqifz with --zip (a stored ZIP, no external deps); --scope/--config restrict/project. Output is well-formed ReqIF 1.2 XML.

0.26.24 — 2026-06-13

SBOM generation — sbom command (GH #66)

  • syscribe sbom [--format cyclonedx|spdx] [--config <C>] [--output <f>] [--include-tests] [--scope <qname>] — generates a Software Bill of Materials from the implementedBy: links on Part/PartDef (and, with --include-tests, TestCase.sourceFile:). Read-only; no new element types or rules. (REQ-TRS-OUT-019)
  • An implementedBy: value matching <registry>:<package>@<version> (crates.io/npm/pypi/maven/nuget/github) becomes an external package component with a PURL (pkg:cargo/tokio@1.38.0); any other value (incl. a repo: link) is a local file component. Local components carry references back to the requirements the part satisfies (CycloneDX externalReferences syscribe://<REQ> / SPDX GENERATED_FROM).
  • --format cyclonedx (default) emits CycloneDX 1.6 JSON (serialNumber urn:uuid, tool + timestamp metadata, components); --format spdx emits SPDX 2.3 JSON (packages + DESCRIBES/CONTAINS/GENERATED_FROM). --config projects to a variant; --output writes a file.

0.26.23 — 2026-06-13

Behavioral coverage — behavioral-coverage command (GH #72)

  • syscribe behavioral-coverage [<qname>] [--depth N] [--format text|json] [--uncovered-only] [--include-planned] — reports how completely the active TestCases exercise the behavioral elements (ActionDef/Action/StateDef/State), via four coverage paths: source overlap (sourceFile under implementedBy), requirement chain (verifies→satisfies→typedBy/supertype), test function (testFunctions[].file under implementedBy), and allocation (allocatedTo). Read-only; no new element types or rules. (REQ-TRS-OUT-018)
  • --include-planned counts draft/review/approved tests in a separate planned column; --uncovered-only filters while keeping the true percentage; text/json ({scope, covered, total, coverage_pct, elements}).
  • The demo model now links its flight-control behaviours (TakeoffAction/MissionExecution/LandingAction) to the realizing firmware and the HIL fault test, so it reports 60% behavioral coverage out of the box.
  • Fixed a CLI argument bug where a value-taking flag (--format/--depth) with no positional could be mistaken for the positional (affected n2/impact/behavioral-coverage).

0.26.22 — 2026-06-13

Change impact analysis — impact command (GH #65)

  • syscribe impact <qname|id> [--direction downstream|upstream|both] [--depth N] [--format text|json|dot] [--kinds <csv>] — traverses the traceability graph from a named element and reports every reachable node, its hop distance, and the edge kind that connects it ("if I change this, what else may need to change?"). Read-only; no new element types or validation rules. (REQ-TRS-OUT-017)
  • Downstream follows reverse links (specializedBy, derivedChildren, verifiedBy, satisfiedBy, refinedBy, conditionalOn, allocatedFrom, safetyGoalChildren); upstream follows forward links (supertype, derivedFrom, verifies, satisfies, refines, allocatedTo, derivedFromSafetyGoal). --depth limits hops; --kinds restricts edge kinds; text (indented tree) / json ({root, nodes}) / dot (Graphviz). Cycle-safe; accepts qnames and stable IDs.

0.26.21 — 2026-06-13

N² interface matrix — n2 command (GH #64)

  • syscribe n2 [<qname>] [--depth N] [--format text|html|json] [--interfaces-only] [--allocations] — generates an N² (N-squared) interface matrix: in-scope PartDef/Part elements on the diagonal, and each off-diagonal cell (R, C) listing the named interfaces directed from R to C (from the connection's typedBy: ConnectionDef/InterfaceDef or its name). Derived read-only from the existing connections:, flowConnections:, and (with --allocations) allocatedTo: edges — no new element types or validation rules. (REQ-TRS-OUT-016)
  • Without a <qname> the axis is every part in the model; with one it is the composite's subpart types, expanded --depth levels. text / html (self-contained <table>) / json ({ scope, elements, matrix }) formats; --interfaces-only drops unconnected elements.

0.26.20 — 2026-06-13

Native TradeStudy element — weighted-criteria evaluation (GH #63)

  • TradeStudy (TRD-*) — a first-class, profile-independent weighted-criteria evaluation of design alternatives: criteria: (weight + maximize/minimize), alternatives: (optional element: ref), a scores: matrix, and optional objective: (Requirement) / decision: (ADR). (REQ-TRS-TYPE-019)
  • Computed scoring — the tool computes (never writes) min-max normalised scores per criterion (direction applied), weighted by the normalised criterion weight, a total per alternative, and a rank.
  • Validation — E869–E877 (required fields, TRD-* id, criteria/weight/direction, empty/unnamed alternatives, unknown score keys, non-numeric score) and W061–W064 (complete-without-decision, unresolved objective, incomplete matrix, unresolved alternative element — the last three draft-suppressed).
  • CLI — trade-study [<TRD-id>] [--json] lists studies or prints one's ranked normalised scoring table. When the model contains TradeStudy elements this command takes precedence; the MagicGrid MoE trade-study (REQ-TRS-MG-007) remains for models without them. template TradeStudy added.

Code note: the spec drafted these as E400–E408 / W400–W403, which collide with the Diagram codes; reassigned to E869–E877 / W061–W064 and the spec §15.5 corrected.

0.26.19 — 2026-06-13

Native ReviewRecord element — thin, GitHub-pointer design (GH #71)

  • ReviewRecord (RR-*) — a first-class, baselined element capturing a formal review event (design / requirements / hazard / test-readiness review, inspection, walkthrough) and the model elements it covers. Deliberately thin: a recordedAt: URI points to the external review (e.g. a GitHub PR/review) so the discussion stays in the review tool while the model keeps the auditable traceability anchor and the coverage gate. (REQ-TRS-TYPE-018)
  • Validation — E700 (required fields), E701 (RR-* id pattern), E702 (status enum), E703 (reviewType enum), E704 (unresolved reviews: entry), E705 (item disposition enum), W700 (closed review with an open action item), and W704 (a non-draft Requirement covered by no review — dormant unless ReviewRecords exist; gateable with --deny W704).
  • CLI — reviews [<qname>] [--open-only] [--json], review <RR-id> [--json], reviews --coverage [--json] (requirement coverage cross-table), and template ReviewRecord.

Code note: the spec drafted the coverage warning as W701, already in use (Requirement asilLevel → verificationMethod); reassigned to W704 and the spec §19 corrected. E700–E705/W700 were free. The recordedAt: field was added to §19 for the thin/pointer design.

0.26.18 — 2026-06-13

Budget expression language for CalculationDef (GH #67)

  • bodyLanguage: budget — a CalculationDef can now carry a restricted arithmetic body: (+ - * /, parentheses, number literals, and feature_ref operands resolving to inline attribute value:/default:). The tool evaluates it without a full KerML expression evaluator. A new evaluate: field names a ConstraintDef bounding the result. (REQ-TRS-BUDGET-001)
  • Validation — E866 (evaluate: is not a ConstraintDef), E867 (budget syntax error), E868 (operand resolves to no numeric attribute), and W060 (budget value violates the evaluate: constraint — best-effort for <lhs> <op> <number> bounds; draft-suppressed; gateable with validate --deny W060).

Code note: the spec drafted the errors as E800–E802, already in use (HazardousEvent); reassigned to E866–E868 and the spec §22.2 corrected. W060 was free.

0.26.17 — 2026-06-13

ASIL D / SIL 4 decomposition pair completeness (GH #69)

  • E865 — non-independent decomposition — when an ASIL D (or SIL 4) requirement's integrity-bearing derivedChildren are all strictly lower (a decomposition claim per ISO 26262-9 §5 / IEC 61508-2 §7.4.9), two sibling channels that name the same element in their satisfies: lists are flagged — decomposed channels must be architecturally independent. (REQ-TRS-SAFE-012)
  • W860 — incomplete decomposition — an ASIL D / SIL 4 parent with a single uniformly-lower child is flagged (a decomposition needs ≥2 independent channels). Draft-suppressed; gateable with validate --deny W860.
  • decompositionKind: field on Requirement — independent | redundant | diverse, informational; surfaced in the safety-case report (text + JSON) and the template Requirement skeleton.

Code note: the spec drafted the error as E860, which is already in use (ConfirmationMeasure/CybersecurityGoal, 0.26.7); it is assigned E865 and the spec §22.3 is corrected.

0.26.16 — 2026-06-13

State machines — behavior resolution + decision transitions (Phase E; completes SysMLv2-faithful HSM)

  • W079 — unresolved behavior reference — a state's entryAction/doAction/exitAction or a transition's effect (a qualified-name string or {typedBy:}) that resolves to no model element is flagged. accept.payload is intentionally not resolution-checked (payloads frequently name informal event labels). Draft-suppressed; gateable with validate --deny W079. (REQ-TRS-SM-008)
  • Decision transitions guaranteed legitimate — two or more guarded transitions from the same source (SysMLv2 §8.4.13.3 decision transitions) are valid branching and do not raise W072; W072 is reserved for same-source, same-payload transitions where none is guarded. Now covered by a regression check.

This completes the state-machine work: one canonical transition schema (§8.8.3) and a recursive, hierarchy/region-aware validator covering W070–W079 over flat, parallel (orthogonal) and composite (hierarchical) machines, faithful to SysMLv2 §7.18.

0.26.15 — 2026-06-13

State machines — hierarchy/composite + endpoint resolution (Phase D of SysMLv2-faithful HSM)

  • Composite (hierarchical) state machines validated recursively — a substate that carries typedBy: or an inline subStates: list is a composite state (SysMLv2 §7.18). The §22.1 checks now run recursively over the hierarchy: each level's substates are checked by W070–W074 with a composite substate treated as a single node, and every inline-subStates: substate is recursed into and checked as its own region (findings name the enclosing region). A typedBy: substate is a node only — the referenced StateDef is validated as its own element. (REQ-TRS-SM-006)
  • W076 — unresolved transition endpoint — a transition source/target that names no state anywhere in the machine's hierarchy and resolves to no model element by qualified name is flagged (typos, references to removed states). Draft-suppressed; gateable with validate --deny W076. (REQ-TRS-SM-007)
  • Unified engine — the flat (Phase B), parallel (Phase C) and composite paths now share one recursive walk (check_state_node) over one transition extractor, so a composite substate no longer suppresses its enclosing level's dead/trap checks.

0.26.14 — 2026-06-13

State machines — parallel/orthogonal regions (Phase C of SysMLv2-faithful HSM)

  • Parallel state machines validated per region — an isParallel: true StateDef/State is now understood as concurrent regions (its direct substates, each a composite region per SysMLv2 §7.18). The completeness checks run per region: W073/W074 (initial cardinality) and the flat W070/W071/W072 apply within each region, with findings naming the region. (REQ-TRS-SM-004)
  • W077 — cross-region transition — a transition connecting substates in two different regions of a parallel state is flagged (SysMLv2 forbids transitions between the substates of a parallel state). The scan covers the parallel parent's own transitions and each region's internal transitions. (REQ-TRS-SM-005)
  • W078 — parallel arity — an isParallel: true state with fewer than two regions is flagged. (REQ-TRS-SM-005)
  • Both draft-suppressed and gateable (validate --deny W077/W078). The flat (W070–W074) and parallel paths share one transition extractor and one region checker; non-parallel composite machines still defer W070/W071 to the upcoming hierarchy phase.

0.26.13 — 2026-06-13

State machines — flat completeness W070–W074 (Phase B; closes GH #68)

  • W070–W074 state-machine completeness — single-region StateDef/State machines are now checked, over the canonical transition edge model (§8.8.3), for: dead states (W070 — no incoming transition, not isInitial), trap states (W071 — no outgoing transition, not isFinal), non-determinism (W072 — two+ transitions from one source with the same accept payload and no guard), missing initial (W073), and multiple initial (W074). All draft-suppressed; gateable with validate --deny W07x. (REQ-TRS-SM-003)
  • Scope — these flat checks apply only to non-isParallel, non-composite machines (a composite substate carries typedBy:, an inline subStates:, or isParallel:). Parallel/composite machines raise none of W070–W074; their region/hierarchy-aware treatment lands in later phases. The demo machines (FlightStates, ChargingSessionStates) are clean.

0.26.12 — 2026-06-13

State machines — schema consolidation (Phase A of SysMLv2-faithful HSM; GH #68)

  • One canonical transition schema — StateDef/State transitions are now defined by a single SysMLv2-faithful vocabulary (source / target / accept{payload,via} / guard / effect, §8.8.3), authored either nested under a subStates: entry (implicit source) or top-level (explicit source:). A single transition extractor yields one edge model from both placements, so downstream state-machine checks never disagree. (REQ-TRS-SM-001)
  • W075 — deprecated transition keys — the legacy top-level spelling from: / to: / trigger: is not SysMLv2 vocabulary. It is still accepted as aliases (from≡source, to≡target, trigger≡accept.payload) so existing models keep parsing, but now raises W075 directing migration to the canonical keys. Draft-suppressed; gateable with validate --deny W075. The one model using the legacy form (model_mg ChargingSessionStates) is migrated to canonical and given an explicit isInitial state. (REQ-TRS-SM-002)

This is the foundation for the hierarchy/region-aware completeness checks (W070–W078) landing in later phases.

0.26.11 — 2026-06-13

New features (issue #70)

  • W080 — Sequence diagram send/receive completeness — a type: Diagram element with diagramKind: Sequence whose subject: resolves to an ActionDef now raises W080 for every SendAction/AcceptAction reachable through the subject's sub-action tree (subActions:/steps:, recursing into IfAction then:/else: branches) that no edges: entry references. A message action is "covered" when an edges: entry's ref: equals its qualified name (<ActionDef>::<action>) or its bare name. The rule (previously advisory in §8.16.8.3, now normative per §22.4) is draft-suppressed and gateable with validate --deny W080. (REQ-TRS-DIAG-002)

0.26.10 — 2026-06-13

  • GitHub Action fixed: the composite action now runs syscribe -m <model-path> validate. Its new args: input passes extra flags, for example --profile magicgrid or --deny <code>.
  • Per-model CI flags: CI now validates each model with its own flags, so model_mg is checked with --profile magicgrid.
  • Qualification fixtures: fixed E002/E015 errors in the qualification TestCases.
  • Dependencies: replaced the deprecated serde_yaml with serde_yaml_ng.

0.26.9 — 2026-06-13

  • Discoverability: spec types, spec safety, spec fields, spec validation and template now show Asset (ASSET-*) and TestCase.securityTestMethod. Both shipped in 0.26.7 but weren't listed there (#56, #59).
  • Dependencies: bumped petgraph, quick-xml, taffy and toml.

0.26.8 — 2026-06-13

New features (issue #60)

  • derive: block for computed fields — any element's YAML frontmatter now accepts an optional derive: mapping of fieldName → formula. Formulas are evaluated top-to-bottom within an element; later entries may reference earlier ones via self.<field>. Operators: sum, max, min, count, collect over children/parent collections; elements["Qualified::Name"].<field> for cross-element refs; +, -, *, / arithmetic; ?? null coalesce. Derived values appear under Derived Fields in syscribe show <qname>. Errors: E501 (parse error), E502 (unknown element ref). (REQ-TRS-DERIVE-001–005)

0.26.7 — 2026-06-13

New features and fixes (issues #54–#59)

  • AssumptionOfUse.appliesTo accepts CybersecurityGoal — AOUs can now cross-link to CybersecurityGoal elements for ISO/SAE 21434 §9 SEooC obligations. An explicit type check (E859) fires when appliesTo targets an element that is not a SafetyGoal, CybersecurityGoal, Argument, or Requirement. (REQ-TRS-SEC-004)
  • ConfirmationMeasure.confirms accepts CybersecurityGoal — TARA review CMs can now confirm CybersecurityGoal elements. Targeting an element of an invalid type raises E860. (REQ-TRS-SEC-005)
  • derivedFromCybersecurityGoal: field on Requirement — renamed from derivedFromSecurityGoal: for clarity; the old key is a serde alias for backward compatibility. E831 enforces resolution to a CybersecurityGoal element. W804 message updated. (REQ-TRS-SEC-006)
  • W039 extended to CAL3 CybersecurityGoals — a CAL3 CybersecurityGoal with no I2 (or I3) cybersecurity_assessment ConfirmationMeasure now triggers W039, per ISO/SAE 21434 §15.9. The existing CAL4→I3 check is unchanged. (REQ-TRS-SEC-007)
  • securityTestMethod: field on TestCase — ISO/SAE 21434 §13 security-specific test methods (fuzz, penetration_test, security_regression, vulnerability_scan, threat_modeling). Invalid value → W809. (REQ-TRS-SEC-008)
  • Native Asset element type — first-class asset identification per ISO/SAE 21434 §15.3 with stable ASSET-* IDs, cybersecurityProperties, assetOwner, and relatedSafetyGoal fields. DamageScenario.assets links scenarios to identified assets. Validation: E861 (required fields), E862 (id pattern), E863 (invalid property), E864 (bad assets ref), W810 (unreferenced asset). (REQ-TRS-TYPE-017)

0.26.6 — 2026-06-13

New features (issues #48–#52)

  • fmea report command — renders all FMEASheet entries as a Markdown table sorted by RPN descending. --fmea-sheet <id> restricts to one sheet; --json emits a JSON array. (REQ-TRS-RPT-001)
  • fault-tree render <id> command — emits a Mermaid flowchart TD diagram for a named FaultTree element, showing gates and events with type labels and input edges. (REQ-TRS-RPT-001)
  • list AssumptionOfUse SRAC-oriented output — list AssumptionOfUse now shows an ID | Name | Applies To | Status table instead of the generic table. --json includes appliesTo (array) and body (string | null) for safety-manual pipeline automation. (REQ-TRS-OUT-015)
  • lint-docs command — scans external Markdown files or directories for stable-ID tokens (REQ-*, TC-*, ADR-*, FEAT-*, FM-*, FTE-*, AOU-*, SG-*, CM-*) that do not resolve to a known model element. Emits W099 per finding; exits non-zero for CI gating. --json flag for structured output. (REQ-TRS-LINT-001)
  • safety-case implicit fold-in suppression — goals with at least one explicit Argument in support: no longer show the duplicate implicit SafetyGoal → Requirement → TestCase chain alongside the explicit argument tree. --no-implicit suppresses the fold-in for all goals regardless. (REQ-TRS-SAFE-011)
  • safety-case [unknown] verdict footnote — when TestCase leaves have unknown verdicts and no results sidecar has been ingested, a one-line footnote (verdicts unknown — run syscribe ingest-results to populate) is appended. In JSON: "verdictsUnknown": true at the top level. (REQ-TRS-SAFE-010)
  • fmeaRef: / ftaRef: cross-reference fields — FaultTreeEvent accepts fmeaRef: pointing to the reconciling FMEAEntry; FMEAEntry rows accept ftaRef: pointing to the corresponding FaultTreeEvent. Missing targets raise W926 / W927 respectively. Both fields are surfaced by refs. (REQ-TRS-FMEA-003)

0.26.5 — 2026-06-13

Bug fix (issue #53)

  • Fix #53A — template AssumptionOfUse now emits list-form appliesTo:. The template was showing scalar appliesTo: SG-PREFIX-001; multi-goal SRACs require list form. Template now emits the list variant so scaffolded files are immediately valid for multi-goal use.
  • Fix #53B — spec validation now lists ConfirmationMeasure codes (E847–E851, W038, W039) and FMEA E922. These codes were only discoverable via spec safety or by empirically triggering them. They now appear in the spec validation table with their conditions. W039 description updated in all spec files to include silLevel: 3/4 alongside asilLevel: D.

Also fixes qual CI failure for v0.26.4 (E011: TestCase gherkin blocks were missing in the two new test cases).

0.26.4 — 2026-06-13

Bug fixes (issues #45, #46, #47)

  • Fix #45 — FMEA entry canonical field fmeaSeverity: now accepted; unknown keys raise E922. The parser was reading severity: while the spec and element schema documented fmeaSeverity:. Both keys are now accepted (fmeaSeverity: canonical, severity: as a deprecated alias). Any key in an entries: row that is not in the recognised set raises error E922 (silent drops in a safety analysis are unacceptable). The template now emits fmeaSeverity:. (REQ-TRS-FMEA-002)
  • Fix #46 — W903 RPN auto-compute now works when rpn: is absent and fmeaSeverity: is used. The root cause was that the walker was reading severity: for the S component; an entry written with fmeaSeverity: (the canonical key) produced S = None, disabling the auto-compute. Fixed by the same key-reading fix as #45. (REQ-TRS-FMEA-002)
  • Fix #47 — W039 now fires for silLevel: 3 and silLevel: 4 items. W039 was checking only asilLevel: D, ignoring the equivalent IEC 61508 integrity levels. W039 messages for SIL 3/4 items now reference IEC 61508-1 §8. (REQ-TRS-SAFE-009)

0.26.3 — 2026-06-13

New feature: list TestCase with config projection and multi-tag filtering

list TestCase now produces execution-oriented output tailored for CI test selection:

  • Columns: ID | Name | Level | Status | Verifies | Tags instead of the generic table.
  • JSON fields: testLevel, verifies, tags, sourceFile, testFunctions in --json output.
  • --config <id> projection: filters to only test cases active in the given configuration (respects appliesWhen:).
  • Repeated --tag <t> (AND semantics): --tag integration --tag performance returns only test cases that carry all listed tags. Enables fine-grained CI suite selection from a single command. (REQ-TRS-OUT-014, REQ-TRS-TAG-002)

0.26.2 — 2026-06-13

Diagnostic improvements

  • W042 message clarity — W042 now says "qualified-name segment 'X'" instead of "name 'X'", removing the ambiguity with the free-text name: label field.
  • W042 on FeatureDef cross-references E209 — When W042 fires on a FeatureDef with a hyphenated name, the finding now appends "a hyphen in a feature name causes E209 when the feature appears in an appliesWhen expression", surfacing the downstream consequence where the rename is cheapest.

0.26.1 — 2026-06-13

Bug fixes

  • Fix #43 — template output failed its own validation. Every syscribe template <Type> command was still emitting the removed title: field instead of name:, causing freshly scaffolded elements to immediately fail with E025. All 23 templates updated (including TARASheet inline entry rows).
  • Fix #44 — W042 false positives on id-identified filenames. W042 ("not a SysMLv2 basic name") was firing on elements whose filename follows the <id>-Description.md convention (e.g. AOU-KERNEL-001-AmpOutsidePerimeter.md with id: AOU-KERNEL-001). The exemption now covers any element whose declared id: is a stable id and whose filename stem is not the element's SysML name: label. Name-identified types that also carry a stable id (FeatureDef) remain W042-checked as before.

0.26.0 — 2026-06-12

name is the universal label; title removed (E024 retired, E025 generalised)

name is now the single human-readable label on every element type — Requirement, TestCase, ADR, PartDef, Package, FeatureDef, the safety/security types, all of them. The earlier identity-class split (title for id-identified types, name for name-identified types — introduced in 0.21.0) is removed:

  • name labels all types (≈ SysMLv2 declaredName). For id-identified types (identity is a stable id ≈ declaredShortName) name is required free prose — spaces and punctuation are allowed and W042 does not apply. For name-identified types name is also the identity segment, so the basic-name rule (W042) still applies.
  • title is removed. Declaring title: on any element is now error E025 ("rename it to name"). Error E024 (formerly name: on an id-identified type) is retired — a Requirement carrying id + name validates clean. Every type that previously required title now requires name (same error codes).

Migration renamed title: → name: across all bundled models (model, model_auto, model_mg, model_sil) and the qual model + fixtures, including nested FMEA/TARA table-row labels. (REQ-TRS-NAME-002.)

Breaking: a model that carried a title: field now fails validation (E025) — rename it to name.

syscribe --version

syscribe --version (also -V, or the version subcommand) prints syscribe <semver> to stdout and exits 0, with no model directory required. (REQ-TRS-CLI-007.)

clap-based top-level router; unknown commands rejected

The top-level command line is now parsed by a clap router whose subcommand registry is derived from the single man-page list, so an unknown command is rejected with a clear error (error: unrecognized subcommand '<name>') and a non-zero exit — from any directory, before model resolution. Per-command flags pass through to their handlers unchanged, and man-page help (--help/-h/help <cmd>), --version, --agent-instructions, spec, and model-resolution are unchanged. The explicit report command now runs the default full validation report. (REQ-TRS-CLI-008.)

CI gates on validation of every model

The qualification workflow now fails the build if any bundled model (model, model_auto, model_mg, model_sil, qual) has a validation error, and its path triggers were widened to include model*/** so model-only edits are validated.

Suite at 204 test cases, all passing.

0.25.0 — 2026-06-12

MagicGrid visualisation — grid matrix, magicgrid --svg (word-wrapped), matrix grids

The MagicGrid reports now look like the grid:

  • magicgrid opens with the recognisable 3×4 grid matrix (rows B/W/S × the four pillars) of per-cell counts — the B3 System of Interest marked ◆, empty cells marked ·, and an N/12 cells populated summary — above the per-cell detail. The count matches --audit readiness. (REQ-TRS-MG-015.)
  • magicgrid --svg [-o <file>] renders the grid as a self-contained SVG — colour-banded rows, the four pillar columns, each cell's elements, the SoI highlighted, empty cells de-emphasised — laid out with the shared taffy layout engine and the diagram theme + font metrics for visual consistency with the other diagrams. Long cell labels are word-wrapped to the cell width (metrics-based, no truncation) and cells/rows stretch to fit. It is a drop-in Diagram companion (svgMode: companion), so it renders in the browser like any other diagram. (REQ-TRS-MG-016.)
  • The companion matrices — matrix --allocations (sources × targets ✓ matrix with a gap rollup) and trade-study (Configuration × MoE scored matrix with a winner) — are confirmed as 2-D grids and regression-locked. (REQ-TRS-MG-017.)

Verified by TC-TRS-MG-015/016/017; qual suite 189/189.

0.24.0 — 2026-06-12

--agent-instructions magicgrid — teach an LLM to model with MagicGrid

syscribe --agent-instructions now accepts an optional topic. With no topic it prints the general model-authoring prompt (unchanged); syscribe --agent-instructions magicgrid prints a dedicated, self-contained MagicGrid modeling prompt that teaches an LLM the method and how to express it with this tool — the mg_ overlay fields, the [profiles.magicgrid] gate, the cell-by-cell authoring workflow (stakeholder needs → use cases → system context → MoEs → system requirements → functional analysis → logical/physical architecture → allocations → configurations → trade study), the magicgrid / magicgrid --audit / trade-study / matrix --allocations commands, and the MG### codes with how to clear each. An unknown topic exits non-zero naming the available topics. (REQ-TRS-CLI-006, verified by TC-TRS-CLI-006.)

Built-in SI units, ISQ quantity types, and dimensional consistency (W044)

A second open/curated recognition tier (on top of the closed ScalarValues/Base of 0.22.0): the common ISQ quantity-value types (MassValue, ForceValue, EnergyValue, VoltageValue, …) and SI units (the seven base units + common derived units) are now recognised — by full name or symbol (SI::kilogram ≡ SI::kg ≡ bare kg). Recognised members resolve cleanly (no W404); unlike the closed packages, an unrecognised ISQ/SI member is lenient (never W043), and unit: stays fully permissive (USD, kWh, percent accepted). (REQ-TRS-LIB-002.)

When an element/feature declares both a recognised quantity type (typedBy: ISQ::…) and a recognised unit (unit: SI::…), the tool now checks their physical dimensions agree over the seven SI base quantities and raises new warning W044 on a mismatch — e.g. typedBy: ISQ::MassValue with unit: SI::metre. Dimensions are prefix-independent; the check is lenient when either side is unrecognised. The engine is a small in-tree dimension table (no external units crate — uom/dimensioned are type-level, rink-core is heavy with non-SysML names). (REQ-TRS-LIB-003, verified by TC-TRS-LIB-002/TC-TRS-LIB-003; qual suite 186/186.)

0.23.0 — 2026-06-12

Allocation: two forms over one edge model (allocatedTo + derived allocatedFrom)

Allocation can now be authored two ways, sharing a single unified edge model (§12.9):

  • allocatedTo: on the source element — the OSLC-canonical, lightweight default. The source holds allocatedTo: <target> and allocatedFrom is derived, never authored — same link direction as satisfies/verifies/refines. The target gains a computed allocatedFrom reverse index, surfaced in show (a ## Allocated from section), links, and the export computed block.
  • The standalone Allocation element (naming both endpoints) stays first-class for documented allocations whose body carries rationale — e.g. the freedom-from-interference / deployment allocations of §12.6. No forced migration; existing models are unchanged.

A single extractor now feeds MG041, MG081, matrix --allocations, and the derived index, so the matrix and the MagicGrid gate can never disagree — and a features: entry is an edge when it carries both allocatedFrom and allocatedTo, with or without a per-entry type: Allocation (the inconsistency that previously produced false MG041/MG081). Declaring the same edge in both forms is redundant — new warning W503. (REQ-TRS-ALLOC-001, verified by TC-TRS-ALLOC-001; qual suite 183/183. The model_mg/ example's 10 simple allocations were converted to the allocatedTo form.)

0.22.0 — 2026-06-12

magicgrid --audit — MagicGrid findings, readiness, and a verdict

A new audit mode on the magicgrid command runs the gated MagicGrid validation and rolls it into one dashboard: error/warning counts, a per-code table grouped by category (Grid · Refines · Context · SoI · MoE · MoP · Layer · Variant · Coverage), the individual error and warning lines, a readiness summary (grid completeness, the System of Interest, MoE/MoP/Configuration counts), and a PASS/FAIL verdict (exit 0/2, FAIL when the gate would fail). magicgrid --audit --json emits the structured rollup for CI. (REQ-TRS-MG-013.)

MagicGrid completeness / gap-analysis checks (MG080–MG083)

The MagicGrid gate gains the coverage half of the method's validation — advisory warnings (draft-suppressed, gateable, promotable) surfaced by the audit:

  • MG080 — a B1 stakeholder need neither refined by a use case nor derived into a system requirement (orphan need).
  • MG081 — a W2 functional-analysis element allocated to no logical (W3) subsystem.
  • MG082 — the model declares an external actor but no mg_soi System of Interest.
  • MG083 — a Measure of Effectiveness with no Measurement of Performance refining it.

(REQ-TRS-MG-014, verified by TC-TRS-MG-013/TC-TRS-MG-014; qual suite 181/181. The model_mg/ example was extended with W2→W3 functional allocations and a fourth MoP so it audits clean.)

Built-in standard-library type recognition (W043)

The auto-imported standard-library packages with fully-known membership — ScalarValues (Integer, Real, Natural, Boolean, String) and Base (Anything, DataValue) — are now recognised: a type reference to a known member (typedBy: ScalarValues::Real, supertype: Base::DataValue, an operation returnType/parameter typedBy, a feature parameters[].type) resolves cleanly with no W404. A reference into one of these packages to a member it does not declare (e.g. ScalarValues::Flota) is flagged as a likely typo with new warning W043, listing the package's known members — across every type-reference context (this previously passed silently). Import-only packages (SI, ISQ, …) are not enumerated and stay lenient (never W043). (REQ-TRS-LIB-001, verified by TC-TRS-LIB-001.)

0.21.1 — 2026-06-12

trade-study — ambiguous parameter binding is now unevaluable

The trade-study MoE-variable resolver no longer silently picks one of several parameterBindings keys that share a final ./:: segment. An exact key still wins; the final-segment convenience match now resolves only when exactly one binding matches — a bare token matching two or more bindings is ambiguous and the cell is reported n/a (excluded from that column's weight normalisation), rather than guessing. (REQ-TRS-MG-012, verified by TC-TRS-MG-012.)

0.21.0 — 2026-06-12

MagicGrid methodology support (opt-in overlay)

The MagicGrid MBSE method (Morkevičius/Aleksandravičienė) is now expressible as a pure overlay on the SysMLv2 model: all MagicGrid-specific data rides on custom_fields: with an mg_ prefix, and every MagicGrid-specific validation is gated behind a [profiles.magicgrid] profile (magicgrid = true) — non-MagicGrid models are entirely unaffected.

  • Grid classification & report — mg_cell places elements on the B/W/S × Requirements/ Behavior/Structure/Parameters grid (MG020/MG021); the new magicgrid command renders the grid, flags empty cells, and identifies the System of Interest (mg_soi, B3).
  • Traceability — refines: is a base-format link on use cases and behavioral defs (ActionDef/StateDef) with E316 (bad target), W307 (a non-draft use case with no refinement, draft-suppressed) and a computed refinedBy index.
  • System Context — use-case actors: are gate-validated (MG010–MG013) with an mg_external boundary marker and the mg_soi System-of-Interest marker (MG060–MG062).
  • Measures — Measures of Effectiveness (mg_moe/mg_moe_*, MG030–MG033) and Measurements of Performance (mg_mop/mg_mop_refines, MG050–MG052) with a mopRefinedBy index linking MoPs to the MoEs they refine.
  • Solution architecture — mg_layer logical/physical layering (MG040–MG042) and the new matrix --allocations view (function→structure and logical→physical, with a gap rollup).
  • Trade study — the new trade-study command scores and ranks Configurations against the MoEs (weighted, threshold-aware). A Configuration marked mg_variant: true is a parametric variant that may omit featureModel: (MG070), so trade studies compare parameter-only alternatives without a feature model.
  • DX — an unresolved cross-reference that wrongly includes the model-root package name now carries a corrective hint (REQ-TRS-XREF-006); the root package name is documented as excluded from qualified names.

Requirements REQ-TRS-MG-001…011 and REQ-TRS-XREF-006, verified by TC-TRS-MG-001…011 and TC-TRS-XREF-006. A complete worked example lives in model_mg/ (an EV DC fast-charging station). See the MagicGrid guide.

Author appliesWhen from the CLI (applies-when)

A new applies-when <element> --set "<expr>" | --clear [--dry-run] command adds, replaces, or removes an element's appliesWhen: gate. The element resolves by qualified name or stable id; each operand resolves to a FeatureDef by its FEAT-* id or its qualified name (interchangeably). The edit is refused without writing if the expression is malformed/unresolved (E209) or the placement is forbidden (E228); only the appliesWhen: key is changed (the rest of the file is byte-preserved). After a successful --set, the feature model is validated for bad configurations (feature-check --deep: void E223, dead E224, invalid configurations E225) and the command exits non-zero if any are found. (REQ-TRS-AW-001.)

With no flag, applies-when <element> is a read-only display of the element's own and effective gate — the latter including any condition inherited from an ancestor package (transitive package conditioning), or "always applies" when gated nowhere; --json emits {element, own, effective, inheritedFrom}. (REQ-TRS-AW-002.)

One label field per element, fixed by identity class (E024 / E025)

Every element now carries exactly one human-readable label field, determined by how it is identified — never both:

  • Id-identified types (Requirement, TestCase, TestPlan, Configuration, ADR, and the safety/security types — identity is a stable id) label via title. A name: on one of these is now error E024.
  • Name-identified types (all SysML structural types, Package, Diagram, FeatureDef — identity is the name/path) label via name. A title: on one of these is now error E025.

FeatureDef stays name-labelled; the id and label axes are independent. This closes the gap left by W042 (which constrained only the characters of a name, not which label field applies); previously elements could silently drift into carrying both name and title. The bundled models and qual model were migrated to one label field each. (REQ-TRS-NAME-002.)

Mandatory feature ids (FEAT-*)

The FEAT-* stable id introduced in 0.20.0 is now mandatory on every FeatureDef — a feature with no id is error E201 (the shared PLE required-field error). Features stay name-identified (label/qname = name); the id is the stable reference. All bundled and fixture features were migrated to carry an id. (REQ-TRS-ID-006.) Unlike the other stable-id types, a feature id need not end in a number — FEAT-ABS, FEAT-QUADROTOR and FEAT-ABS-001 are all valid (pattern ^FEAT(-[A-Z0-9]{2,12})+$); the E023 digit-cap applies only to a numeric trailing segment.

Breaking: (1) a model that carried both name and title (or the wrong one for its type) now fails validation — remove the stray field (title for id-identified types, name for everything else); (2) a FeatureDef with no FEAT-* id now fails (E201) — add one.

Suite at 166 test cases, all passing.

0.20.0 — 2026-06-11

Feature stable IDs (FEAT-*)

A FeatureDef may now carry an optional stable id (FEAT-ABS-001) as a short-name alias, and a feature can be referenced by that id or by its qualified name — interchangeably — in appliesWhen: and in a Configuration's features: keys (they canonicalise to one key space, so appliesWhen: FEAT-ABS-001 gates identically to appliesWhen: Features::Anti_Lock). A hyphenated feature name reference still errors E209 — only the stable-id form may contain hyphens. (REQ-TRS-ID-006.)

Per-element-type tool-qualification requirements

New REQ-TRS-TYPE-* family: every element type now has a dedicated recognition/validation requirement + test, filling the gap for the SysML structural types (ConstraintDef/Constraint, CalculationDef/Calculation, Concern, Case/AnalysisCase/VerificationCase/UseCase, AllocationDef, SuccessionDef, RenderingDef, State/ExhibitState, Metadata, BindingConnector, LibraryPackage/Namespace, Dependency, …).

Fix

  • show/list previously mislabelled 9 recognised element types (ConcernDef, Concern, CaseDef, EventOccurrenceDef/EventOccurrence, SuccessionDef, RenderingDef, ExhibitState, BindingConnector) as "Other" — the type_label fallthrough now names them.

Suite at 163 test cases, all passing.

0.19.0 — 2026-06-11

Basic-name validation now covers package/directory names (GH #42)

W042 (SysMLv2 basic-name check) previously covered element names and _index.md-backed packages. It now also flags directories without an _index.md — their namespace segment is still a referenceable qualified-name prefix, so it must be a basic name too (e.g. a Brake-System/ directory → rename to Brake_System / BrakeSystem). Stable-id elements (REQ-, TC-, …) remain exempt; only the directories that contain them are checked.

Suite at 146 test cases, all passing.

0.18.0 — 2026-06-11

SysMLv2 basic-name validation (GH #42)

Element names now follow the SysMLv2 basic-name grammar [A-Za-z_][A-Za-z0-9_]*. Previously a hyphenated name (e.g. a FeatureDef Anti-Lock) parsed as a file/qname but failed E209 when referenced in appliesWhen: — because a hyphen is the subtraction operator in the expression grammar.

  • New warning W042: an element's own name that is not a basic name (and not a stable id, which legitimately contains -) — with a rename hint (Anti-Lock → Anti_Lock / AntiLock). Advisory and gateable, so existing models have a migration path.
  • The appliesWhen parse error for - now points at the basic-name convention.

(SysMLv2 unrestricted quoted names are not supported; the convention is basic names.) Requirement-first: REQ-TRS-NAME-001 + TC-TRS-NAME-001. Suite at 146 test cases, all passing.

Internal

  • The release workflow now uploads assets via the gh CLI with retry (replacing a Node20 action that intermittently failed the Windows upload under matrix contention).

0.17.0 — 2026-06-10

Configurable stable-ID suffix width (GH #41)

Stable IDs (REQ-, TC-, TP-, ADR-, and all safety/security ids) previously ended in exactly 3 digits. They now accept a 3–8 digit numeric suffix by default, and the maximum is configurable:

# .syscribe.toml
[ids]
max_digits = 8   # default 8; raise (e.g. 12) or lower (e.g. 4). Minimum stays 3.
  • Existing 3-digit IDs are unchanged; up to 8 digits works out of the box.
  • A suffix longer than the cap is the new error E023; shorter than 3 is still E006.
  • A reference to an over-long ID still resolves — the defect surfaces on the ID-bearing element, not as a dangling reference.

Requirement-first: REQ-TRS-ID-005 + TC-TRS-ID-005. Suite at 145 test cases, all passing.

0.16.2 — 2026-06-10

Docs site

  • Aligned the §9 table-of-contents anchors in the published format specification so all TOC links resolve on the site; the fix (em-dash → colon in three headings) keeps the same anchors working on GitHub's renderer too. mkdocs build --strict is clean.

0.16.1 — 2026-06-10

Docs site

  • The canonical format specification (spec/markdown-sysml-format.md) is now published on the documentation site under Format ▸ Full Specification (a symlink — single source of truth).
  • Fixed two broken links on the CLI reference page that pointed outside the docs tree; mkdocs build --strict is clean again.

0.16.0 — 2026-06-10

TestPlan documentation + template TestPlan

  • syscribe template TestPlan — emits a ready-to-fill TestPlan frontmatter skeleton (TP-* id, title, status, scope, a testCases member, with configurations/demonstrates/selection shown as commented optional fields); TestPlan is now listed among the template command's known native types.
  • Documentation — the TestPlan element (0.13.0/0.15.0) and custom_fields (0.14.0) are now fully documented across the format spec (§8.12.6), the embedded prompts/spec and create-model guides, the site format/validation references, and a new Test Plans model-guide page.

Suite at 144 test cases, all passing.

0.15.0 — 2026-06-10

audit --plan — scoped readiness verdict (GH #40)

Completes the --plan lens (deferred from #38): audit --plan TP-X scopes the readiness verdict to a TestPlan. Validation runs over the whole model — so a reference escaping the plan subset (a requirement's breakdownAdr ADR, a member's out-of-scope verifies: target) resolves and is never mistaken for a defect — and only findings on the plan's in-scope elements (in-scope requirements ∪ member TestCases ∪ their satisfying architecture) count toward the verdict. The dashboard sections are scoped to the plan but resolve references against the full model. Composes with --config; exits 1 on an unknown plan id; dormant-safe.

--plan is now available on matrix, verification-depth and audit. Suite at 144 test cases, all passing.

0.14.0 — 2026-06-10

User-defined custom fields (GH #39)

A dedicated custom_fields: frontmatter map lets you attach arbitrary user data to any element — making it intentional and addressable instead of being silently swallowed by the unknown-key catch-all.

  • Schema — custom_fields: is a flat string → scalar | list-of-scalars map, accepted on every element type, serialised in stable sorted order.
  • Validation — W041 shape-check: a value that is not a scalar or a list of scalars (e.g. a nested map) is flagged, naming the key. Freeform keys, no registration.
  • Query — --where custom.<key> on ls / find / list: exact (=), regex/substring (=~), list-membership (~=), and bare presence; composes (AND) with the type/tag/status filters.
  • Rendering — a ## Custom Fields section in CLI show, and a read-only key/value table in the web detail panel (never editable via the element editor).

Requirement-first: REQ-TRS-CFLD-001..003, TC-TRS-CFLD-001..003 with fixtures. Suite at 144 test cases, all passing.

0.13.0 — 2026-06-10

Native TestPlan element (GH #38)

A first-class TestPlan (type: TestPlan, stable TP-* id) groups TestCases into the unit a team executes and reports against. TestCases stay reusable atoms; a plan is a curated, per-product artifact.

  • Schema & validation — scope (recommended vocab + free-form), configurations: (scalar/list of Configurations, or absent = config-agnostic), demonstrates: (optional safety-case evidence link), testCases: + an additive selection: query (testLevels/domains/tags). New rules E600–E606 and W610–W616: malformed id, unresolvable member/config/demonstrates target, bad selection levels/domains, non-recommended scope, escaping member, empty plan, pinned-draft member, demonstration gap, results-gated failing member, duplicate (configurations, scope). W614 honours goal-closure — demonstrating a parent goal whose leaves are tested does not false-fire (cf. GH #37).
  • testplan command — testplan lists every plan (scope, configs, effective-TC count, coverage %, verdict); testplan TP-X shows members (with escaping flags), in-scope requirements, a per-config coverage grid and a rolled-up verdict (pass|fail|incomplete|empty); --json on both. Coverage and verdict reuse the existing matrix/results machinery.
  • --plan TP-X lens — on matrix and verification-depth: restricts rows to the plan's in-scope requirements and the TestCase universe to its members; composes with --config. (audit --plan is deferred — GH #40.)
  • matrix --config now reduces the grid to the selected Configuration's column.

Requirement-first: REQ-TRS-PLAN-001..006, TC-TRS-PLAN-001..006 with fixtures covering every code. Suite at 141 test cases, all passing.

0.12.1 — 2026-06-09

Fixes

  • audit no longer mis-lists a parent requirement as unsatisfied/unverified (GH #37). A parent (a Requirement with derivedChildren) is satisfied and verified only transitively through its leaves and can never be satisfied directly (§12.4 / E312 forbid it appearing in any satisfies: list). The orphan section nonetheless flagged every such parent under unsatisfiedRequirements (and structurally under unverifiedRequirements), disagreeing with validate, which already suppresses parents in W002/W300/W306. The orphan loop now skips parents from both sets; genuine gaps still surface on the leaf requirements. Covered by a new parent-rollup fixture under TC-TRS-OUT-013.

0.12.0 — 2026-06-09

Configuration lens on the analysis & audit commands

  • audit now honours --config (GH #35). The dashboard was always computed over the 150% superset, so a requirement gated out of a variant still tripped the verdict. audit --config <CONF|features> now projects the entire dashboard — verdict, W306, orphan sets and coverage — onto the elements active in that Configuration, exactly like validate --config. New audit --all-configs audits every stored Configuration's variant and exits non-zero if any fails (the product-line CI gate).
  • audit --config and validate --config now agree (GH #36). A TestCase that survives the projection but whose verifies: target was projected out was mis-counted as a dangling error-severity finding. The verdict now uses the projection-aware validate_projected path, and dangling detection considers only the active TestCases while resolving their references against the full model — so the two commands report the same error count for a variant.
  • The --config lens extends to the other read-only safety/security commands. metrics, cyber-risk, co-analysis, verification-depth and safety-case each accept --config <C> and compute their report over the projected active subset (dormant when no feature model; unresolvable --config exits 1).

Requirement-first: REQ-TRS-OUT-013 (audit lens + #36 agreement) and new REQ-TRS-PROJ-006 (lens on the analysis commands), with TC-TRS-OUT-013 / TC-TRS-PROJ-006 harnesses and fixtures. Suite at 135 test cases, all passing.

0.11.1 — 2026-06-09

Fixes

  • W306 no longer flags a satisfied-via-leaf parent requirement (GH #34). The "unsatisfied" sub-condition demanded a direct satisfier, contradicting E312 (a parent requirement may not appear in a satisfies: list — it is satisfied transitively through its leaves). High-integrity parents were therefore permanently flagged and audit could never PASS on a hierarchical model. The sub-condition now applies to leaf requirements only (mirroring the existing W002 parent suppression); genuine gaps still surface on the unsatisfied leaf, and status: draft / active-in-no-config still apply to parents. Covered by a new satisfied-via-leaf parent fixture in TC-TRS-TRACE-010.

0.11.0 — 2026-06-09

A large safety/security + tooling release. Every feature is requirement-first (a REQ-TRS-* + TC-TRS-* with fixtures); the tool-qualification suite grew to 134 test cases, all passing.

Safety & security analysis (ISO 26262 / IEC 61508 / ISO/SAE 21434)

  • Safety ↔ security co-engineering — hazardRef links DamageScenario/ThreatScenario to the HazardousEvent/SafetyGoal they endanger (E844); W030 flags a safety-tagged damage scenario with no link; new co-analysis command shows which cyber threats can violate each safety goal.
  • Cybersecurity risk determination — computed risk (severity × feasibility) per ThreatScenario, riskTreatment/residualRisk fields, W031 (untreated high/critical threat) and W032 (CAL below risk), new cyber-risk command.
  • Quantitative HW metrics — diagnosticCoverage/latentDiagnosticCoverage, SPFM/LFM/PMHF computed per SafetyGoal vs ASIL/SIL target (W033), new metrics command. First-order FMEDA approximation.
  • Freedom from interference — W034 flags differing-integrity elements sharing an allocation target without an ffiRationale.
  • Attack trees — new AttackTree/AttackTreeGate/AttackStep types with weakest-link feasibility roll-up (AND=min, OR=max) reconciled against the linked threat (W035).
  • Confirmation measures & DIA — responsibility field (W038), ConfirmationMeasure type + W039 (missing independent assessment for ASIL-D/CAL4).
  • GSN safety case — Argument/AssumptionOfUse types and a safety-case command rendering the goal → argument → evidence tree.
  • Unsatisfied safety mechanism W306; WCET evidence W029 + list --has-wcet.

Reports, queries & CLI

  • New audit (safety-readiness dashboard with PASS/FAIL), verification-depth (independence report + --min-levels gate), connectivity (element-rooted subgraph as text/DOT/JSON), extref (lookup by external reference).
  • list/matrix gain --status/--sil/--has-wcet/--gaps-only filters, coverage-% footers, JSON, and executed-evidence glyphs/annotations in matrix/trace from ingested results.
  • Named severity profiles — .syscribe.toml [profiles.*] (SIL/ASIL-scopable code promotion) via validate --profile / audit --profile.
  • extRef common field (external-tool references) + W028 duplicate check.
  • Model-root auto-discovery — .syscribe.toml walk-up; -m stays primary (backward-compatible).
  • Detailed per-command help — syscribe help <command> and syscribe <command> --help/-h (man-page style for every command), plus syscribe help index.

Format & correctness

  • bindingTime on feature parameters (compile/load/runtime) with ordering (E229) and value (E230) checks, W027, and W017 suppression.
  • typedBy cycle/self-reference now detected (E107) — previously silently accepted.
  • Ports & Interfaces modeling guide (SysML v2) added to the spec, syscribe spec types, and the LLM prompt.
  • Discoverability: the full safety/security field & type set is now documented in syscribe spec fields/types/safety, and all new commands/types are in the --agent-instructions LLM prompt.

0.10.0 — 2026-06-08

Model-root auto-discovery (REQ-TRS-CLI-004)

  • With no -m/--model flag and no SYSCRIBE_MODEL, the tool now walks up from the current working directory to the nearest ancestor containing a .syscribe.toml and uses that directory as the model root — run any command from anywhere inside the model tree (the git/cargo ergonomics). Full resolution order: --model → SYSCRIBE_MODEL → walk-up to .syscribe.toml → the literal model/ default.
  • The marker is the existing config file (repo_root / [matchers] / [remote]); an empty .syscribe.toml is a valid root marker. It is a tooling locator only — it never affects qualified-name resolution or the implicit root namespace.
  • Fully backward-compatible: the flag, env var, and model/ default behave exactly as before; a tree with no marker falls straight through to the default.

Tests

  • REQ-TRS-CLI-004 + TC-TRS-CLI-004 (discovery from a subdirectory, explicit -m override, explicit -m on a model with no marker, and fallback-with-miss). Tool-qualification suite 115 → 116 test cases, all passing.

0.9.0 — 2026-06-08

Feature-parameter binding time (REQ-TRS-PARAM-004)

  • A FeatureDef parameter may declare an optional bindingTime: — when its value is resolved, from the product-line-engineering triad ordered earliest→latest: compile (build / codegen) · load (deployment / startup) · runtime (live). Orthogonal to isFixed:/value: (a value fixed in the model); an absent binding time is unspecified and opts out of the checks.
  • E230 — an unrecognised bindingTime: value (validate). E229 — a parameter computed from a derivedFrom/bindTo source it depends on cannot bind earlier than that source (feature-check; checked only when both ends declare a binding time). W027 — a Configuration that binds a runtime parameter (resolved by the running system, not at configuration time); for the same reason W017 is suppressed for an unbound runtime parameter. The feature/features cards show param [bindingTime].

External references on all elements (REQ-TRS-EXTREF-001/002)

  • New optional common field extRef (string or list) on every element type — marks an element as the representation of an artifact in another tool (a requirement in DOORS Next, an element in a SysML tool, a ticket). Opaque values (a URI or a tool:id token); syntax unconstrained; never a model cross-reference target.
  • New extref <ref> [--json] command looks up the element(s) carrying a reference (exact match, returns all matches, exits non-zero on a miss). W028 warns when the same extRef is declared by two or more elements. show surfaces the field and spec fields lists it.

Tests

  • Requirement-first: REQ-TRS-PARAM-004 + REQ-TRS-EXTREF-001/002 with TC-TRS-PARAM-004 and TC-TRS-EXTREF-001/002 and fixtures. Tool-qualification suite 113 → 115 test cases, all passing.

0.8.1 — 2026-06-08

Fixes (GH #14 re-open)

  • Parameter range: is now enforced by feature-check, not only validate. The binding rules (E203–E206/E222/W017) were extracted into a shared check so a product line validated holistically (feature-check) gets the same range/binding enforcement — an out-of-range binding (e.g. 99 against range: "1..=8") now fires E205 under feature-check.
  • A parameterConstraints expression that used the legacy ::-member form (Features::F::param) was silently dropped (no error, no evaluation). It now raises E213 with a hint to use the canonical dotted form Features::F.param — a declared constraint can never silently no-op.
  • Hardened the constraint arithmetic tokenizer to reject unexpected characters (previously swallowed, so a stray operator could yield a spurious value).

Tests

  • New feature_model unit tests for the constraint evaluator: all comparison operators, arithmetic precedence/parentheses/unary-minus, unresolved/malformed → no-match, and range: parsing (incl. ..=). Model unit tests 33 → 40.

0.8.0 — 2026-06-07

Typed feature-parameter constraints enforced (closes #14)

  • E221 — feature-check now evaluates parameterConstraints expressions (numeric comparison == != >= <= > < over + - * / arithmetic of literals and parameter references) against every Configuration whose appliesWhen: predicate holds; a violation is an error. W025 — the same violation when the constraint declares severity: warning. Both gateable with --deny.
  • Compound appliesWhen: on parameterConstraints is now boolean-parsed (and/or/not), fixing a spurious W014.
  • range: now accepts the inclusive form "min..=max" as well as "min..max", so E205/E202 actually fire (a 1..=8 range was previously dropped silently).
  • Schema: a feature-parameter reference is now the canonical dotted form Features::Feature.param (a single . before the parameter member) everywhere — parameterBindings: keys, parameterConstraints expressions, and bindTo: targets. The legacy all-:: member form is rejected (E222). Existing fixtures and the demo model were migrated.

Transitive package appliesWhen (REQ-TRS-VAR-006)

  • A Package (_index.md) may declare appliesWhen: to gate its whole subtree — enabling/disabling a cohesive variant of requirements + architecture + tests with one declaration. An element's effective condition is its own appliesWhen:, else the nearest ancestor package's, else always-active; conditions are never combined.
  • E228 — invalid placement (at most one declaration per root-to-leaf path): a nested declaration, or appliesWhen: on a FeatureDef/Configuration, a package whose subtree contains one, or the model root. W026 — a gated package with an empty subtree.
  • All consumers honour the effective condition: --config projection, escaping refs (E226/W019), matrix, why-active (now shows "inherited from package"), feature-card gates, list --feature, and feature-check --deep edges.

Tests

  • The appliesWhen boolean grammar is now covered by an exhaustive oracle (3000 random expression ASTs evaluated across all assignments), precedence-vs-parentheses checks, and operator-substring/whitespace/double-negation edge cases.

0.7.0 — 2026-06-07

Feature discoverability commands

Five read-only commands for navigating a product line, plus an orphan-feature check:

  • features [--json] — the feature model as a tree: each FeatureDef's groupKind, requires/excludes, parameters, and a "selected in N/M configs" rollup.
  • feature <qname> [--json] — one feature's card: doc, group, constraints, parameters, the Configurations that select it, and every element it gates (whose appliesWhen: names it).
  • matrix --features — a Feature × Configuration grid (which feature ships in which product), complementing the Requirement × Configuration view.
  • list <type> --feature <F> — restrict a listing to elements whose appliesWhen: names F (orthogonal to --tag/--config).
  • why-active <element> --config <C> — explain a projection: the element's appliesWhen:, the config's relevant selections, and a Verdict: of active / inactive / always active.
  • W024 — feature-check now flags an orphan feature (referenced by no appliesWhen: and selected by no Configuration); gate with feature-check --deny W024. Never emitted by base validate.

Feature-model schema: mandatory: membership (ADR-FM-003)

A new optional boolean mandatory: on FeatureDef separates membership (relative to the parent) from grouping (groupKind, which now governs child layout only). A node can be both mandatory: true and groupKind: alternative — a mandatory XOR group (every product selects exactly one child). Backward compatible: the legacy groupKind: mandatory remains a shorthand for mandatory: true on a leaf.

UAV model is now a full product line

The bundled model/ is a runnable 150% UAV product line: a feature model (Features/) with three mandatory XOR groups (Propulsion/Payload/DataLink), an optional DualFlightController, cross-tree requires, and a typed parameter; three products (Configurations/CONF-UAV-*); variant-conditioned architecture, requirements, and tests under ADR-SYS-PLE-001; and implementedBy: traces into firmware/. Every variability command runs against it cleanly (feature-check --deep, matrix, validate --all-configs). With the new mandatory: field the earlier synthetic Base workaround feature was removed.

Documented in the variability guide, modeling guide, CLI reference, format spec §9, and syscribe spec prompts.

0.6.0 — 2026-06-07

Implementation trace (implementedBy:, closes #13)

Closes the downstream leg of the V-model: Requirement ─satisfies→ Architecture ─implementedBy→ Code ─verifies→ Test.

  • implementedBy: — a new optional field on Part/PartDef (string or list) linking an architecture element to the source artifact(s) that realise it. Paths resolve with the same rules as a TestCase's sourceFile (model-/repo-relative, model:/repo: prefixes, absolute, file://, remote scheme://).
  • W023 — a non-draft Part/PartDef whose implementedBy: path is missing on disk (one finding per missing path). Opt-in (only when implementedBy: is present), draft-suppressed, remote-tolerant, and gateable with validate --deny W023.
  • Discoverability — links <element> lists implementedBy paths; refs <path-or-dir> reverse-maps a source path (or directory prefix) back to the declaring architecture element(s).

Documented in format spec §12.8, syscribe spec validation/spec fields, the validation-rule reference, the traceability guide, and the LLM authoring prompt.

0.5.0 — 2026-06-06

Configuration selections (fixes #12)

  • template Configuration now emits the canonical features: map (was selections:, which the parser silently ignored — every cell came back N/A).
  • W016 — a Configuration that parses zero feature selections while a feature model exists is now flagged instead of silently ignored.
  • show <Configuration> displays parsed feature selections (and featureModel/appliesWhen), so a parse failure is visible locally.

Feature parameters (§9.7, single-level)

  • FeatureDef.parameters: are now validated against a Configuration's parameterBindings::
  • E203 bind for an unselected feature · E204 bind a fixed parameter · E205 value out of range: · E206 value not in enumValues: · E222 binding path resolves to no declared parameter · W017 selected feature's required, default-less parameter left unbound.
  • Two-level bindTo: propagation, derived-expression cycles, and cross-feature parameterConstraints remain unimplemented (documented).

0.4.0 — 2026-06-06

Product-line variability (opt-in)

The variability dimension stays dormant — and changes nothing — unless the model declares a FeatureDef and links something to it.

  • Boolean appliesWhen: — conditions any element (including a TestCase) on an expression over FeatureDef qualified names: and / or / not / parentheses. Bare QName and list (AND) forms remain valid. E209 now checks every operand.
  • TestCase variant membership is derived from appliesWhen: — a test runs in a Configuration iff its condition holds for that configuration's selections (no runsIn field).
  • syscribe matrix [--json] [--tag] — Requirement × Configuration coverage grid (covered / gap / N-A); falls back to a flat view when no feature model is present.
  • W015 — per-Configuration coverage rule: a requirement active in a configuration with no covering in-config TestCase. Honours draft suppression; gate with --deny W015.
  • list --tag / generic tags — free-text tags: filtering across list and matrix, orthogonal to the feature model.
  • Configuration.features: selection maps now parse; refs <CONF> lists the TestCases that run in a configuration.

Documented in format spec §9.10–9.11, syscribe spec validation/spec fields, the CLI help, and the LLM authoring prompt (Part 9b).

0.3.0 — 2026-06-06

  • CI severity gating for validate (--deny, --max-warnings, --warnings-as-errors; exit codes 0/1/2)
  • Function-level traceability (W009) and structured model-graph export (JSON / NDJSON)
  • Gherkin scaffolding (scaffold-gherkin) and test-result ingestion (ingest-results, W010)
  • Atomic move with reference rewriting
  • sourceFile location semantics (model/repo-relative, absolute, file://, remote) with an opt-in --fetch-remote download hook
  • Active-only source-drift scoping with informational I010

0.2.0 — 2026-05-28

Demo models

  • Engine ECU (model_auto/) — full ISO 26262 / ISO/SAE 21434 reference model: ASIL A–D safety goals, HARA, FTA, FMEA, TARA, 14 test cases
  • SIL 4 Computer-Based Interlocking (model_sil/) — full IEC 61508 / EN 50128 / EN 50159 reference model: SIL 4 2oo2D architecture, formal B-Method specification obligation, quantitative FTA (< 10⁻⁸ /h), 11 test cases
  • Separate documentation pages for each demo model in the docs

CLI

  • Model root is now set with -m <path> / --model <path> or the SYSCRIBE_MODEL environment variable — positional argument removed
  • New spec subcommand: syscribe spec, syscribe spec types, syscribe spec fields, syscribe spec validation, syscribe spec traceability, syscribe spec safety — in-terminal format spec browser
  • New trace, why, who-verifies commands for traceability queries
  • New next-id, template, check-ref, path-for commands for model authoring
  • New validate --json flag for machine-readable output
  • New types and untyped commands for model inspection

Validation

  • Safety/security integrity level rules: E841/E842/E843 (ASIL/SIL consistency across inheritance and deployment), W808 (integrity level not set on safety-critical element)
  • W806: SafetyGoal not grounded in any HazardousEvent or HARA element
  • W305: parent Requirement must have at least one integration-level (L3/L4/L5) TestCase
  • W410/W411/W412: cross-reference target existence checks
  • W408/W409: %% ref: annotation validation in Mermaid diagram blocks
  • Various false-positive fixes (W006, W007, W406/W407 SVG-internal IDs)

Format

  • derivedFromSafetyGoal: link from Requirement to SafetyGoal (IEC 61508 / ISO 13849)
  • derivedFromSecurityGoal: link from Requirement to CybersecurityGoal
  • allocatedFrom / allocatedTo now accept lists for multi-source allocation
  • Full Tier 4 safety analysis elements: FaultTree (file-per-node), FMEA (exploded entries), TARASheet (exploded container)
  • Full safety/security analysis documentation added to the Modeling Guide

Web browser

  • Interactive Cytoscape.js model canvas at /canvas
  • Validation errors and warnings highlighted on canvas nodes
  • Validation findings shown in element detail panel
  • Element documentation body rendered as Markdown with embedded Mermaid diagram support
  • diagram CLI with compose, layout, expose sub-commands; Cassowary-based layout solver
  • SEQ and REQ diagram renderers; A* obstacle-aware edge routing; full SysML edge style set
  • JS dependencies vendored and served from the embedded binary (no external CDN at runtime)
  • Unified engineering blueprint colour scheme across docs and canvas

0.1.4 — 2026-05-28

Diagram CLI

  • diagram subcommand: list, measure, render and compose produce companion SVGs (svgMode: companion).
  • Layout: diagram layout is a Cassowary-based layout solver. compose can read a Diagram element's expose: list, and --emit-placement prints the layout so an LLM can refine it.
  • More diagram kinds: diagram req draws requirement trees and diagram seq draws sequence diagrams.
  • Rendering: IBD ports and nested ports, A* obstacle-aware edge routing, and the full SysML edge style set.

Validation and authoring commands

  • New commands:
  • validate shows only errors and warnings, with --json and --file.
  • list, types and untyped.
  • template, next-id, path-for and check-ref.
  • New codes: W007 (unused *Def), W008 (no type:), and E016–E018 (cycles in supertype, derivedFrom and subsets).
  • Fixes: stack overflow in tree caused by the root _index.md, and W007 false positives from nested typedBy:.

0.1.3 — 2026-05-27

  • Mermaid references: a %% ref: annotation in a Mermaid diagram must resolve (W408), and a Mermaid diagram with no annotations is W409.
  • Link checks: new W410–W412 check %% link:, shape link: and SVG href references.
  • render command: render <diagram> prints a diagram with its links injected.

0.1.2 — 2026-05-27

  • Fixed duplicate changelog entries in the release workflow.

0.1.1 — 2026-05-27

  • Reworded the GitHub Action description in action.yml.

0.1.0 — 2026-05-26

Initial public release.

Format

  • Full Syscribe format specification (§1–§12)
  • 40+ element types covering SysMLv2 structural, behavioral, and requirements constructs
  • Native Requirement (REQ-), TestCase (TC-), ADR (ADR-), and Configuration (CONF-) elements
  • operations: field (§8.3.4) on PortDef/InterfaceDef for synchronous operations and async receptions
  • Six §12 traceability rules enforced by the validator

Validation engine

  • 80+ validation rules across 12 groups (E001–E503, W001–W601)
  • Computed reverse indices: verified_by, derived_children
  • CLI report tool: syscribe -m model/ — 10-section Markdown output

Web browser

  • Axum + Askama + HTMX — no JavaScript framework
  • BDD, IBD, StateMachine, and Requirement diagram rendering (SVG, server-built)
  • Mermaid diagram rendering (client-side, CDN)
  • Drag-to-reposition with layout persistence to .md files
  • WebSocket live reload on file-system changes

Demo model

  • UAV system — 111 elements across 20 packages
  • 9 native Requirements (3 parents, 6 leaves), 9 active TestCases, 2 ADRs
  • Full §12 traceability: domain classification, breakdownAdr, satisfaction links
  • 5 diagrams: BDD, IBD, StateMachine, Requirement, Mermaid