Version 7.6.0 ============= This release lands **OCL preconditions and postconditions end-to-end**, from the BUML metamodel through the Web Modeling Editor's class-diagram converter, validator, and canvas. ``Method.pre`` and ``Method.post`` are now first-class list fields on ``Method``, the OCL textbox in the editor speaks the canonical BOCL form (``context X (inv|pre|post) [name]: body``), and the validator walks every method's pre/post lists in addition to the domain model's invariants — so a typo'd pre constraint surfaces with a ``[Class::method kind name]`` label that points at the offending box. ``OCLConstraint`` exposes the parsed ``ast`` separately from the source-text ``expression``, giving downstream tools (Lean encoder, SQL CHECK generators, IDE tooling) a stable API surface. Alongside, the editor's template library gains a **Full Project tab** with multi-diagram bundles, project creation gains **modeling-perspective selection**, and a number of OCL hardening and codegen safety fixes land. New Features and Improvements ----------------------------- **OCL Metamodel — Pre/Post and AST/Source Split** * Added ``Method.pre`` and ``Method.post`` as first-class list fields on ``Method`` with name-uniqueness validated via property setters, plus ``add_pre`` / ``add_post`` helpers. Operation contracts no longer rely on naming-convention scraping to be discovered — they are anchored on the ``Method`` they constrain. * Tightened ``Constraint.expression`` from ``Any`` to strict ``str`` (``TypeError`` on non-str) and added ``OCLConstraint.ast`` exposing the parsed ``OCLExpression``. The constructor enforces that ``expression`` arrives parsed; the ``ast`` setter refreshes the source-text expression via the pretty-printer. The split gives walkers and analyzers a stable typed entry point while leaving ``expression`` as the canonical source representation. * ``DomainModel._validate_constraints`` now walks every ``Method.pre`` / ``Method.post`` in addition to ``domain_model.constraints``, so a precondition with a stale or external context is flagged the same way an invariant would be. * Documentation: ``docs/source/buml_language/model_types/ocl.rst`` adds a worked ``add_pre``/``add_post`` example and a sub-toctree pointing at new ``parsing.rst``, ``ast.rst``, and ``normalization.rst`` sub-pages; ``api_ocl.rst`` expands autodoc to cover ``clone``, ``parse_ocl``, ``pretty_print``, ``normalize``, and ``BOCLSyntaxError``; ``examples/ocl.rst`` is rewritten as a runnable end-to-end example. **Web Modeling Editor — OCL Pre/Post Wiring** * Added a ``parse_constraint_text(text, model)`` helper that inspects the BOCL header to extract kind / class / optional method / optional name, resolves the class manually, and delegates lex/parse to ``parse_ocl(...)`` with an explicit ``context_class`` (the upstream auto-detect regex doesn't handle the ``Class::method(params)`` form). ``process_ocl_constraints`` now returns ``(kind, OCLConstraint, class_name, method_name)`` routing tuples. * The class-diagram processor routes constraints by their parsed kind: invariants land on ``domain_model.constraints``; preconditions and postconditions land on ``Method.pre`` / ``Method.post``. Method lookup is by the ``(class, method)`` name pair and walks the inheritance chain, so a precondition written as ``context Sub::base_method() pre: ...`` resolves to a method declared on a parent class instead of warn-skipping. * The class-diagram converter on the BUML→JSON path emits the full BOCL header on every constraint box (invariant, pre, and post) so editor round-trips preserve kind, target method, name, and description without back-channel metadata. Pre/post emission walks ``Method.pre`` / ``Method.post`` directly. * Added a back-compat shim that transparently lifts body-only JSON files (saved during an intermediate iteration) to the canonical full-text shape on first ingest, then ``buml_to_json`` normalizes them on emit. Legacy projects round-trip cleanly without manual editing. * Validator (``services/validators/ocl_checker.py``) now walks every class's methods' pre/post lists in addition to ``domain_model.constraints``; error labels include the ``[Class::method kind name]`` triple so messages point at a specific constraint box instead of "constraint #3". * Auto-generated invariant names are embedded back into ``constraint.expression`` so the next BUML→JSON→BUML cycle parses out the same name instead of generating a fresh ``counter_blockidx`` suffix. * Tests: 17 new tests covering routing, malformed-OCL skip-with-warning, legacy ingest, and full-text round-trip stability. **Web Modeling Editor — OCL Constraint Box (Frontend)** * The OCL constraint box renders an italic stereotype badge above the body — ``«inv»``, ``«pre» ``, ``«post» `` — derived from the constraint's BOCL header, giving a visual cue for the kind without introducing a separate metadata field. When the text doesn't match the BOCL header regex (empty or malformed), no badge renders. * Added an optional ``description`` field on the constraint popup so users can attach a plain-language explanation that the validator surfaces as the violation reason instead of the raw OCL. * The constraint textbox is back to a single full-text field carrying the whole BOCL block (``context X (inv|pre|post) [name]: body``). Routing into ``Method.pre`` / ``Method.post`` happens entirely on the backend by parsing the OCL header tokens — no frontend metadata churn, no risk of body / metadata drift. * Added a "Library with OCL" structural-pattern template pre-populated with eleven canonical OCL constraints — invariants on ``Book`` / ``Library`` / ``Author`` plus preconditions and postconditions on common operations — so users get a working pre/post example one click away. **OCL — Other Improvements** * Added an optional ``description`` field on ``Constraint`` that threads end-to-end (metamodel, JSON↔BUML converters, validator output, code builder). Inline OCL ``--`` comments per constraint are also accepted on ingest, with the inline comment winning if both are present (#499). * De-duplicate constraint names across OCL boxes (whether typed by the user or auto-generated) instead of crashing ``_process_constraints``. The de-dup loop preserves insertion order, keeping the first occurrence and emitting a ``Warning: duplicate constraint name 'X'…`` so users can spot the collision in the validator output. Discovered via a 2000-constraint stress test (5 parallel agents exercising invariants, pre/post, multi-block, evaluator, and adversarial inputs). * Consolidated the OCL constraint pipeline around a single contract: ``constraint.expression`` carries the full canonical OCL text from the moment a constraint is parsed through every storage, transport, validation, and evaluation step. Three reconstruction layers and one mutation hack are gone (``_method_signature`` / ``_already_full_text`` / ``_canonical_invariant_text`` / ``_canonical_method_contract_text`` and the swap-and-restore around ``parser.evaluate()``); a narrow ``_ensure_canonical_expression`` legacy fallback remains for old BUML files (deprecated, removal target 2026-Q4). Hardening and Code Quality -------------------------- * **Identifier-injection hardening on BUML codegen**: ``constraint.name`` and ``method.name`` no longer flow straight into Python identifier positions on the LHS of assignments. Names like ``x=1;import os;os.system('id')#`` (no spaces, no hyphens, passes ``NamedElement.name``'s setter) used to land verbatim in code that gets ``exec()``'d. Every identifier emit site now routes through ``buml_code_builder.common.safe_var_name`` via a new ``_method_var_name(method)`` shim, replacing five different copies of ``method.name.split('(')[0]``. * Pre/post boxes preserve their ``description`` on JSON↔BUML round-trip; the BUML→JSON converter's invariant emit path is mirrored on the method-contract path so the field is no longer silently dropped. * Sorted ``method_contracts`` in ``domain_model_builder`` so the emitted Python is byte-stable across runs (matches how invariants and other emissions sort). * Narrowed the residual ``except Exception`` in OCL element processing to ``(BOCLSyntaxError, ValueError)`` so programmer errors propagate instead of being swallowed. * Dropped defensive ``getattr`` / ``hasattr`` guards on metamodel attributes that the metamodel now guarantees (``Class.methods``, ``Method.pre``, ``Method.post``). * Stress-tested the OCL pipeline with 2000 constraints across 5 parallel agents (invariants, pre/post, multi-block, evaluator, adversarial inputs) — surfaced and fixed the duplicate-name crash and the round-trip ``description``-loss above; the rest of the pipeline survived without regressions. Web Modeling Editor — Templates and Project Hub ------------------------------------------------ * Added a **Full Project tab** to the template library carrying multi-diagram project bundles (class diagram + GUI no-code diagram + agent diagram in one click) — a step beyond the existing single-diagram pattern templates. * Shipped two full-project templates: **Library Full Stack** (full class diagram + GUI + REST API skeleton) and **Personalized Gym Agent** (an end-to-end agent project demonstrating the multi-diagram model with a configured agent and supporting data model). * Project creation now offers a **modeling-perspective selector** so the project starts with the workspace already filtered to the diagram families the user intends to model, reducing the initial-noise problem on a fresh project. * Object diagrams: a referenced class can now seed a generated set of objects and links matching that class's structure, so a user editing an object diagram doesn't have to hand-construct every object instance from scratch. * Refactored project-import logic into ``shared/services`` so the import pipeline is reusable across the project hub and the GitHub-import path. * Workspace: setting up the diagram bridge when loading a project (the editor now wires the diagram-state bridge during project load instead of relying on a downstream component to do it, fixing a class of "diagram opens but feels frozen" bugs). * Renamed the **Full Application** perspective preset to **Full Web Application** so the label matches what the perspective actually selects (web frontend + backend + API), with no behavior change. * i18n: removed the German locale stub (it was incomplete and being toggled-on in production produced a half-translated UI). Web Modeling Editor — Backend Fixes ----------------------------------- * **Django generator**: re-introduced the ``chdir(temp_dir)`` guard around the ``django-admin startproject`` invocation. The pre-refactor ``backend.py`` wrapped the call in ``chdir/try-finally``; the extracted ``_generate_django`` helper in ``generation_router.py`` had dropped the guard, so the project got scaffolded in the FastAPI process's CWD while the harvester walked an empty ``temp_dir/``, surfacing as ``Django project generation failed: Output directory is empty``. The guard is now scoped to the worker thread and restores CWD in ``finally``. * **GitHub deploy**: ``deploy_webapp_to_github`` now branches on ``httpx.HTTPStatusError`` and surfaces the actual GitHub API error (``"name already exists on this account"``, expired token, rate limit) instead of letting it fall through to the catch-all 500 handler. ``401`` / ``403`` pass through; ``422`` maps to ``409 Conflict`` so the UI can offer rename / overwrite; other ``4xx`` pass through; ``5xx`` becomes ``502 Bad Gateway``. The frontend's deploy popup now shows something the user can act on. Modeling Assistant — Natural Language to OCL -------------------------------------------- Closes ``BESSER-PEARL/B-OCL-Interpreter#5``. The modeling assistant can now author OCL constraints from a plain-language description. When the user explicitly asks for an invariant, precondition, or postcondition (``"add a constraint that a Library always has at least one Book"``, ``"the precondition of Account::deposit is amount > 0"``, ``"after deposit the balance must not be negative"``), the agent emits an ``add_ocl_constraint`` modification, and the frontend spawns a constraint box on the canvas linked to the target class via a ``ClassOCLLink``. * **Modeling-agent** (``BESSER-PEARL/modeling-agent``): ``ClassModification`` adds the ``add_ocl_constraint`` action with optional ``changes.constraint`` (full BOCL block) and ``changes.text`` (plain-language description). The class-diagram system prompt gains an OCL section listing the four header shapes (``inv`` / ``pre`` / ``post`` / ``init``) plus five NL→BOCL examples. Emission is gated on the user explicitly asking — the prompt forbids unprompted OCL. * **Web Modeling Editor frontend**: ``ClassDiagramModifier.addOclConstraint`` consumes the new action and creates a ``ClassOCLConstraint`` element + ``ClassOCLLink`` to the anchor class, with the BOCL text in the constraint field and the plain-language description in the ``description`` field. The rendered box picks up the canonical stereotype badge (``«inv»`` / ``«pre»`` / ``«post»``) introduced earlier in this release. * **Validation**: pre-flight validation (calling ``/validate-diagram`` before writing) is a known follow-up — for now, malformed BOCL surfaces post-hoc through the ``parse_constraint_text`` validator path landed in PR #529. * **Deploy alongside**: this feature requires the matching modeling-agent commit (``c0e47e8`` on ``main``) to be live. Use ``./scripts/deploy.sh agent`` to roll the modeling-agent container forward at release time. Documentation ------------- * OCL: new sub-pages under ``buml_language/model_types/ocl/`` cover **parsing**, the **AST**, and **normalization** — the public surface a tool walking the OCL AST needs. * OCL: ``ocl_grammar.rst`` clarifies the ``.expression`` (str) / ``.ast`` (``OCLExpression``) split. * OCL: ``examples/ocl.rst`` rewritten as a runnable end-to-end example, with the prior invalid-syntax example fixed. * OCL: ``api_ocl.rst`` expands autodoc to cover ``clone``, ``parse_ocl``, ``pretty_print``, ``normalize``, ``BOCLSyntaxError``.