**Title:** Add a top-level `setNativeProps` method that accepts a native component ref

**Description:**

We need a public `setNativeProps(handle, nativeProps)` API on the React Native renderer (both `ReactNative` and `ReactFabric`). Unlike the existing `setNativeProps` mixin method (tied to component instances via `NativeMethodsMixin`), this new API should accept a ref that points to a native host component and apply the native property updates directly.

**Acceptance criteria / observable behavior:**

1. **Method signature & export:**
   - `ReactNative.setNativeProps(ref, nativeProps)` and `ReactFabric.setNativeProps(ref, nativeProps)` must exist.

2. **Ref validation & warning:**
   - If the provided ref does **not** have a `_nativeTag` (i.e., it does not represent a native host component), the function must warn in development with a message indicating that the ref is not a native component and suggesting `React.forwardRef` to obtain the underlying native component. In production, it must silently return without performing any update.

3. **Payload creation & bridge call avoidance:**
   - The native prop diff / payload creation logic must be reused (the same logic already used by the mixin).
   - If the resulting update payload is `null` (i.e., the new props are identical to the current props or there is no effective change), **no** call to `UIManager.updateView` may be made. This avoids expensive bridge overhead (especially on Android) and unnecessary view invalidations on iOS.

4. **Application of update:**
   - When the ref is a native component and there are changed properties, `UIManager.updateView` must be called with the native tag, the UI view class name, and the update payload.

5. **Development-time style warnings:**
   - In `__DEV__`, the same style-prop validation (e.g., `warnForStyleProps`) used by the mixin should run against the provided `nativeProps` and the component’s `viewConfig.validAttributes`.

6. **Renderer symmetry:**
   - The behavior must be identical for both the Paper renderer (`ReactNative`) and the Fabric renderer (`ReactFabric`), including the ability to update a Fabric-rendered component via `ReactNative.setNativeProps` and vice versa.

Adding ReactNative.setNativeProps that takes a ref (#14907)


I'm seeing a bug with the experimental React Blocks API when a block’s load data changes and a Suspense fallback is involved. The component renders stale data instead of the freshly loaded data, which makes the UI inconsistent.

**Steps to reproduce:**
1. Create a Block whose `load` function returns data based on its arguments, and the render function conditionally shows a Suspense boundary around part of that data (e.g., using `<Suspense fallback="Loading...">`).
2. Initially render the block with one set of arguments (e.g., `null`) so that the Suspense boundary displays a fallback or a non‑suspending state.
3. Trigger a re‑render of the block with **different** arguments (e.g., a string like `'Sebastian'`). The expectation is that once the data resolves, the component will show the new data.
4. During the resolution (for example, after a timer/ping), the displayed output still reflects the **old** data rather than the updated value.

**Expected behavior:**
After the block’s load arguments change and data resolves, the UI should always reflect the most recent loaded data. No stale data should ever appear.

**Impact:**
This leads to incorrect information being displayed to the user, especially in UIs that rely on dynamic data loading with Suspense for graceful fallback handling. The bug is persistent across subsequent renders until a full unmount/remount, making blocks unreliable for data‑driven views.

It seems like the framework is sometimes holding on to the `type` from a previous render rather than using the updated block data. Please ensure that when a block’s work-in-progress fiber is created or reset, the `type` field is kept in sync with the current fiber so that the data stays fresh.

[Blocks] Fix stale data on updates (#18810)


We need the React Native renderer’s prop diffing to systematically ignore function values, ensuring that changes in function identity between old and new props never produce attribute updates sent to the native side. Functions are not serializable and cannot be meaningfully consumed by native views, so treating them as equal regardless of reference equality is the correct default.

Acceptance criteria:

1. **Function props are always ignored during diff**
   When `diffProperties` (or the lower-level `defaultDiffer`) compares two props objects, any key whose value is a function in both the previous and next props must be considered unchanged. This applies regardless of nesting depth—functions inside objects, arrays, or any combination of structures must be treated equally.

2. **Explicit opt-in for function skipping**
   The `deepDiffer` utility used internally (imported from `react-native/Libraries/ReactPrivate/ReactNativePrivateInterface`) must accept an optional `options` argument with a boolean field `unsafelyIgnoreFunctions`.
   - When `unsafelyIgnoreFunctions` is `true` or not provided (default), `deepDiffer` returns `false` (not different) for any function values, preserving the current behavior.
   - When `unsafelyIgnoreFunctions` is explicitly `false`, a change in function reference is treated as a difference (`true`).
   - This options object must be forwarded through recursive calls so the setting applies at any depth.

3. **Default differ explicitly passes the option**
   In `packages/react-native-renderer/src/ReactNativeAttributePayload.js`, the `defaultDiffer` function must call `deepDiffer(prevProp, nextProp, {unsafelyIgnoreFunctions: true})`. This makes the decision to ignore functions overt and intentional, rather than relying on an implicit default.

4. **No regressions for non-function values**
   Primitives, objects, arrays, and `null`/`undefined` comparisons must continue to work exactly as before. Only the handling of function-typed values should be affected.

5. **Edge-case configuration via Flow types**
   The Flow type declaration for `deepDiffer` (in `scripts/flow/react-native-host-hooks.js`) should be updated to reflect the new signature, supporting both a positional `maxDepth` and a trailing `options` object with the `unsafelyIgnoreFunctions` key, as well as an overload where `options` replaces `maxDepth` positionally.

By following these criteria we will eliminate unnecessary native update payloads for changing function props while still allowing advanced use cases that source-of-truth for function identity changes if an escape hatch is ever needed.

Update deepDiffer usage in React Native renderer (#17282)


**Feature Request: Expose `pointerType` in Focus Event Responder Events**

**Context**
The `Focus` event responder currently provides callbacks (`onFocus`, `onBlur`, `onFocusChange`, `onFocusVisibleChange`) with a `FocusEvent` object that contains `target`, `type`, and `timeStamp`. Consumers need to know whether a focus change was triggered by a keyboard, mouse, touch, or pen interaction, but that information is not available.

**Desired Behavior (Acceptance Criteria)**
1. All `FocusEvent` objects passed to the responder callbacks must include a new `pointerType` property.
2. The `pointerType` must be one of these strings: `''` (empty string), `'mouse'`, `'keyboard'`, `'pen'`, or `'touch'`.
3. The value is determined by the most recent *primary* user interaction that leads to or directly precedes a focus/blur:
   - If a focus or blur occurs immediately after a `pointerdown`, `mousedown`, `touchstart`, or `keydown` (with `key === 'Tab'`), the `pointerType` must reflect that interaction (`'mouse'`, `'touch'`, `'pen'`, or `'keyboard'`).
   - If no such interaction has occurred before the focus event, the value must be `''`.
4. The `pointerType` must be tracked per `Focus` responder instance (i.e., per element managed by the responder), not globally.
5. The `pointerType` must appear in all four event types: `'focus'`, `'blur'`, `'focuschange'`, and `'focusvisiblechange'`.
6. When the environment supports Pointer Events, the actual `pointerType` from the native `PointerEvent` must be used for `'mouse'`, `'pen'`, and `'touch'`. When Pointer Events are not available (e.g., Safari), the responder must fall back to listening to `mousedown`/`mousemove`/`mouseup` for mouse and `touchstart`/`touchmove`/`touchend` for touch, and assign the appropriate `pointerType` value accordingly.
7. The existing behavior around `focusvisiblechange` (suppressing visibility after pointer usage) must be preserved while also populating the `pointerType` for those events.

This allows consumers to implement device-adaptive focus styling and behavior without resorting to hacks or custom listeners.

Event API: adds pointerType to Focus events (#15645)


Add an ESLint rule `no-cross-fork-types` under `react-internal` that prevents accessing fork‑specific fields of the shared Fiber type inside the wrong reconciler fork. Files named `*.old.js` or `*.old` belong to the old fork, files named `*.new.js` or `*.new` belong to the new fork.

Fields ending with `_old` are automatically considered old‑only (must not be accessed in new‑fork files). Fields ending with `_new` are automatically considered new‑only (must not be accessed in old‑fork files). Additionally, allow explicit per‑fork lists of field names that do not follow this naming convention, configured through rule options.

The rule should flag any member access (`obj.field`) or destructured property (`{field} = obj`) that uses a forbidden field for the current fork.

Lint rule to forbid access of cross-fork fields (#19679)


## Feature Request: Compiler warning for derived state computed within `useEffect`

### Problem
Developers often write `useEffect` calls that compute new state values from props or state, then call a `setState` setter with that computed value. This is a documented React anti-pattern because the derived value can usually be calculated directly during render, avoiding an extra render cycle, a redundant effect, and potential infinite loops.

For example:
```js
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
```
The `fullName` value is entirely derived from `firstName` and `lastName`. It could simply be `const fullName = firstName + ' ' + lastName;` in the component body.

Currently, the React Compiler does not detect or report these patterns. Developers only discover the problem through manual review or external lint rules.

### Expected Behavior
Introduce a new validation pass in the compiler that detects such unnecessary effects and emits a compiler error. The check should be opt-in, gated behind a new configuration flag (e.g., `validateNoDerivedComputationsInEffects`, defaulting to `false`).

When enabled, the validation should:
- Inspect each `useEffect` call where the dependency array is non‑empty and contains only identifier references.
- Examine the effect’s callback function. It should flag a `setState` call as invalid when:
    - The effect captures **only** the declared dependencies and `setState`‑typed functions (i.e. no other free variables from the component scope).
    - The dependency array elements are all actually used within the effect (otherwise the dependency list might be incomplete, making analysis unsafe).
    - The value passed to the `setState` call is computed solely from the effect’s dependencies (i.e., every operand in the computation’s transitive data‑flow graph traces back to one of the dependency identifiers).
- Bail out (produce no error) if:
    - Any control‑flow construct (branch, loop, terminal condition) uses a dependency value in a way that could affect the shape of the state update (e.g., the computed value is used in a conditional or loop exit).
    - The effect captures a variable that is neither a declared dependency nor a `setState` function.
    - The dependency array is empty or contains non‑identifier expressions.

The error should point to the specific `setState` call location and include a message with a link to the relevant React documentation (https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state).

### Impact
This feature would help developers follow React best practices, eliminate unnecessary effects, and reduce subtle performance issues. The opt‑in flag allows teams to adopt the check gradually without breaking existing codebases.


In the Node.js streaming SSR API, `ReactDOMFizzServer.pipeToNodeWritable` currently begins writing to the destination stream immediately while rendering is in progress. Change it so that writing does not start automatically; instead, the caller must explicitly start writing when ready.

## Implementation requirements
- `pipeToNodeWritable` must return a `Controls` object containing `startWriting`, in addition to the existing `abort`.
- Calling `startWriting` begins flushing buffered output to the stream and sets up the `'drain'` handler.
- `startWriting` must be idempotent; subsequent calls have no effect.
- Error propagation must remain functional even before `startWriting` is called – if an error occurs during rendering, the stream should still be correctly errored.
- `abort` must work as before, regardless of whether `startWriting` has been called.

The underlying `startWork` should no longer transition the request into a FLOWING state; that transition is deferred until `startWriting` (which invokes `startFlowing`).

[Fizz] Expose a method to explicitly start writing to a Node stream (#21028)


**Title:** Eden watcher: implement `allFilesGenerator` and fix integration test harness

**Background**
Watchman’s Eden watcher (`eden.cpp`) currently has a stub for `EdenView::allFilesGenerator` that returns `*num_walked = 0` and `true` without actually walking any files. As a result, any query that relies on the all-files generator (e.g., a query that doesn’t match a more specific generator like glob/path, or a query with `relative_root` + a type expression) will return no results even when files exist in the Eden mount.

**Request**
1. **Implement `allFilesGenerator` so that it enumerates real files from the Eden filesystem.**
   - Use Eden’s Thrift client (`getEdenClient()`) to call `sync_glob` with a pattern that respects the query’s `relative_root` (if set); if no `relative_root` is present, enumerate the entire mount.
   - For each file path returned by Eden, fetch its metadata via `sync_getFileInformation` so that `watchman_file` objects carry correct `stat` fields (mode, size, mtime) and `exists` flag.
   - Build temporary `watchman_dir` and `watchman_file` objects that the query engine can walk (a minimal “fake dirs” helper is acceptable—just enough to make `w_query_process_file` work; it’s expected that this will be cleaned up later).
   - Feed each file through the standard query processing path (`w_query_process_file`), respecting early termination if the function returns `false`.
   - Set `*num_walked` accurately.

2. **Ensure queries that use the all-files generator produce correct results for common expressions.**
   - Queries with `['type', 'f']`, `['type', 'l']`, etc. should return the expected subset of files and symlinks.
   - Queries with `relative_root` should correctly scope the file listing to that subdirectory and return relative names.

3. **Fix the Eden integration test harness.**
   - The `EdenFS` constructor used in `WatchmanEdenTestCase.setUp` now expects an `etc_eden_dir` parameter, and the system configuration files must live under `<etc_eden_dir>/config.d`. Adjust `setUp` to create `etc-eden/config.d` inside the temporary home directory and pass the appropriate keyword argument.
   - The old `eden_sys_config` path should be replaced; the new structure must be created before starting the EdenFS process.

**Constraints / Notes**
- The Eden watcher is selected only when the root is an Eden mount; the new code path must not affect other watchers.
- The temporary directory/file objects only need to live for the duration of the query walk; they don’t need to be persisted or re-used across queries.
- The implementation does not need to be efficient for huge trees yet—correctness comes first.


**Bug: Watchman query request_id not passed to Mercurial blackbox logs**

When executing a Watchman query that includes a `request_id` field, the expectation is that the identifier can be correlated with the Mercurial commands that Watchman performs under the hood. Specifically, the `HGREQUESTID` environment variable should be set on the `hg` child processes so that the identifier appears in the Mercurial blackbox log (if enabled). Currently, this does not happen: the `request_id` is not forwarded to Mercurial, making it impossible to tie a Watchman query to the corresponding HG operations in the log.

The SCM interface (`SCM::mergeBaseWith`, `SCM::getFilesChangedSinceMergeBaseWith`, etc.) already accepts an optional `requestId` parameter, and the Mercurial implementation already has a method to construct HG process options (`makeHgOptions`) that can propagate it. However, the `request_id` from the active query is not being passed through when these SCM methods are called during query execution, and the Mercurial option builder is currently ignoring the parameter.

**Desired behavior:**
- When a Watchman query specifies a `request_id`, that string must be set as `HGREQUESTID` in the environment of any `hg` commands that Watchman runs on behalf of that query.
- The `request_id` must be forwarded to `hg` for both merge-base lookups and “files changed since merge-base” operations.
- The change must be backward-compatible: if no `request_id` is provided, no `HGREQUESTID` environment variable should be set, and existing behavior should remain unchanged.
- The implementation should avoid race conditions or caching issues: the `request_id` must be tied to the specific query execution, not the repository instance.

This is a small but important observability improvement. It allows operators and automation tools to trace a Watchman request end-to-end through the Mercurial log.


**Title:** Watchman queries with multiple glob patterns on EdenFS miss files matching later patterns

**Overview**
When Watchman runs a query that includes multiple `glob` entries (e.g., `"glob": ["foo/*", "foo/*/*"]`) on an EdenFS mount, the results only contain files that match the first pattern. Files matching the second (and any subsequent) patterns are silently missing. This makes rules that depend on several globs unreliable and breaks build/watch workflows.

**Steps to reproduce**
1. Set up Watchman to watch a directory backed by EdenFS.
2. Create a tree that contains files reachable by different patterns, for example:
   - `bdir/noexec.sh`
   - `bdir/test.sh`
   - `cdir/sub/file` (where `cdir/sub` is a directory)
3. Run a query:
   ```json
   ["query", "<root>", {"fields": ["name"], "glob": ["bdir/*.sh", "bdir/test*"]}]
   ```
   Actual result: only the files matched by `bdir/*.sh` are returned; files matching `bdir/test*` are absent.
4. Similarly, a query like:
   ```json
   ["query", "<root>", {"fields": ["name"], "glob": ["cdir/*", "cdir/*/*"]}]
   ```
   returns only `cdir/sub` and omits `cdir/sub/file`, even though `cdir/*/*` should match the file.

**Expected behavior**
All files that match any of the specified glob patterns should be returned. If a file matches multiple patterns, it should appear only once (no duplicates).

**Root cause**
Investigation points to a bug in the EdenFS `globFiles` Thrift API: when multiple glob patterns are passed in a single request, EdenFS effectively ignores every pattern except the first.
- This is a known EdenFS issue; a fix exists on the EdenFS side but hasn’t been deployed widely yet.

**Task**
Implement a temporary workaround in Watchman so that it corrects this behavior regardless of the EdenFS version it talks to, until the EdenFS fix is fully deployed.

The workaround should:
- When the query involves multiple glob patterns, make a separate `globFiles` call to EdenFS for each pattern (instead of sending all patterns in one call).
- Merge the results from all calls, ensuring that no duplicate entries appear when patterns overlap.
- Preserve the existing fast-path when only one pattern is present (no unnecessary overhead).

**Constraints / edge cases**
- Overlapping glob patterns (e.g., `bdir/*.sh` and `bdir/test*` where `bdir/test.sh` matches both) must not produce duplicate entries in the final file list.
- The order of results is not required to be stable across the merge; correctness is measured by set equality.
- The workaround must be compatible with the existing EdenView query interface and should not affect non-Eden watchers.
- The implementation should be straightforward to remove once the EdenFS bug is fixed and the updated version is rolled out everywhere. (A TODO or guard to track this is fine.)

**Impact**
Without this workaround, any Watchman user on EdenFS who uses multi-pattern glob queries (including many build systems and custom watch rules) will experience incomplete file notifications, potentially leading to stale outputs, missed rebuilds, and broken workflows. This is a correctness issue that needs an immediate client-side mitigation.


## Bug Report: SCM-aware subscriptions suppress merge base change notifications when file list is empty

**Summary:** In SCM-aware mode (when using `mergebase-with` in the since query), Watchman should deliver a subscription update whenever the merge base changes, even if no files have changed. Currently it suppresses the update entirely in that case, breaking workflows that depend on merge-base change notifications.

**Steps to reproduce:**
1. Set up an SCM-aware subscription that includes a `mergebase-with` field in its `since` specification (as described in [Watchman SCM query docs](https://facebook.github.io/watchman/docs/scm-query.html)).
2. Perform a source-control operation that moves the merge base but does not modify any tracked files (e.g., checking out a branch or rebasing, where the only difference is the merge-base commit).
3. Flush the subscription and wait for an update.

**Expected behavior:**
The subscriber should receive a subscription PDU containing:
- An empty file list (since no files changed),
- A clock whose SCM merge base field (`clock.scm.mergebase`) reflects the new merge-base commit.

**Actual behavior:**
No subscription PDU is delivered at all. The update is suppressed because the file list is empty, so the merge-base change is lost.

**Impact:**
Applications that rely on the merge-base change to trigger rebuilds, reanalysis, or other invalidation see no notification, leading to stale derived artifacts.

**Desired fix logic:**
When deciding whether to suppress an empty subscription result, also check whether the merge base has changed. If the `since` spec includes SCM parameters and the current merge base differs from the query's previously recorded merge base, the result **must not** be suppressed, even if the file list is empty. The optimization that skips empty updates should only apply when both the file list is empty **and** the merge base is unchanged.

**Additional context:**
The existing optimization (returning `null` for an empty result set) is correct when nothing at all changed, but it must be refined to account for SCM-aware scenarios where a merge-base change itself is a meaningful event. The SCM parameters are available via `ClockSpec::hasScmParams()` and the merge baselines are compared through the clock positions stored in the query context and the `since` spec.

report merge base change when result set is empty


**Title:** BSER parser unsafe against crafted/corrupted inputs – integer overflow, negative lengths, unbounded allocations

**Description**
The BSER wire-format parser (the `bunser` family in `bser.cpp` / `bser.h`) is used by Watchman to deserialize messages from clients.  Fuzzing has uncovered several categories of problems when the parser encounters malformed or adversarial BSER payloads:

* **Signed‑size wraparound leading to out‑of‑bounds reads.**
  Length and availability calculations use `json_int_t` (int64_t) instead of unsigned sizes.  A carefully chosen negative “length” can pass existing checks, invert the direction of pointer arithmetic, and cause buffer over-reads or crashes.

* **No upper bound on container sizes.**
  There is no enforcement of a maximum array/object/string size.  A tiny message that claims to contain, for example, `2^63 - 1` elements will cause the parser to attempt an enormous memory allocation or loop forever, resulting in denial of service.

* **Negative sizes not consistently rejected.**
  Some code paths fail to reject negative sizes for arrays, objects, templates, and strings, allowing wraparound attacks.

* **`bunser` out‑parameter `needed` is unused by callers.**
  The public `bunser(buf, end, &needed)` signature is cumbersome and the `needed` output is no longer consumed.  The function can be simplified by removing it, which also removes a class of accidental misuse.

* **Error messages are inconsistent.**
  Some invalid encodings trigger generic “document too short” messages that do not pinpoint the problem, making auditing and debugging difficult.

**Expected Behavior / Requirements**
We need a from-scratch rewrite of the BSER parsing logic that satisfies the following invariants:

1. **Use `size_t` for all remaining‑buffer arithmetic.**  Convert lengths and counts to `size_t` early and ensure every pointer advance is guarded by an explicit bounds check.  Reject any input that would overflow `size_t` before the advance.

2. **Enforce a hard maximum container size** (e.g., `kMaximumContainerSize`, already defined) on arrays, objects, templates, strings, and any other counted entities.  Any payload whose declared count exceeds this limit must be rejected immediately.

3. **Reject negative sizes in every context.**  If an encoded length/count is less than zero, throw a descriptive parse error before any allocation or pointer movement.

4. **Preserve all existing BSER features** (v1 and v2, bytestrings, UTF‑8 strings, skip markers, templates) while making the parser smaller and more obviously correct.

5. **Simplify the `bunser` public API** so that the `needed` output parameter is removed and the function only returns the parsed value (or throws `BserParseError`).  Callers already ignore that parameter; keeping it around invites future misuse.

6. **Robust error messages.**  When the parser encounters an unexpected value type, an unsupported encoding, or a truncation, the error should include the offset in the document and the expected vs actual values.

**Impact**
These changes close multiple OOB‑read and excessive‑allocation vectors that are reachable from any client that can send BSER‑encoded RPCs to the Watchman daemon.  They also make the parser easier to audit and maintain going forward.


## Feature request: Trim glob upper bounds after the first unescaped `**`

**Background**

When Watchman submits queries to Eden it computes “glob upper bounds” – a small set of glob patterns that cover all paths Eden must monitor. For example, a `match` term with pattern `"foo/*/bar"` produces the upper bound `"foo/*/bar"`, and an `anyof` clause that contains several `match` terms will have their individual bounds merged and deduplicated before being sent to Eden.

**Problem**

Multiple `match` terms that share the same root up to a `**` component cause Eden to perform duplicate work, because Eden must still walk the entire `**` subtree for each distinct full pattern. For instance:

```
["match", "foo/**/bar", "wholename"]
["match", "foo/**/baz", "wholename"]
```

both force Eden to walk `foo/**`, but the current upper-bound computation emits the unabridged patterns `"foo/**/bar"` and `"foo/**/baz"`. Since the patterns differ after the `**`, they survive deduplication and both are sent to Eden.

**Request**

Improve the glob upper-bound calculation so that for any pattern containing an unescaped `**` we trim everything after the `**` (including the `**` itself). The trimmed pattern is a safe upper bound because it matches a superset of the original pattern’s matches.

For the example above, both patterns would produce the bound `"foo/**"` and the deduplication logic would then issue a single watch, avoiding wasted work.

**Edge cases & correctness constraints**

1. **Escaped `*` and `**`**
   A `*` or `**` that is escaped (for example `\*`, `\\**`, or inside a character class `[...]`) must **not** cause trimming.
   - `"foo/\\**/bar"` → bound is `"foo/\**/bar"` (no trimming)
   - `"foo/[**]/bar"` → bound is `"foo/[**]/bar"` (no trimming)
   - `"foo/*\\*/bar"` → bound is `"foo/*\*/bar"` (no trimming; the second `*` is escaped)

2. **Pattern starting with `**`**
   If the pattern itself begins with `**` (so the shortest prefix containing the first `**` is just `"**"`), we must **not** emit any upper bound. A bound of `"**"` would match the entire repository, provide no savings, and may even be harmful.
   Example: `"**/foo"` → no bound (i.e., `nullopt` in the existing upper-bound API).

3. **Trimming point**
   The bound should be the pattern prefix up to and including the **first** unescaped `**` token. If `**` appears multiple times only the first occurrence matters, because trimming at the first one already yields a superset.
   Example: `"foo/**/bar/**/baz"` → bound `"foo/**"`.

4. **Compatibility with `anyof` / `allof` deduplication**
   The deduplication logic that already merges bounds from `anyof` terms should naturally collapse multiple distinct patterns that now share the same trimmed prefix. For instance, an `anyof` expression containing `"foo/**/bar"`, `"foo/**/baz/quux"`, and `"foo/**/more/*"` should ultimately present a single bound `"foo/**"`.

5. **Case sensitivity**
   The trimming must work correctly regardless of whether the term is case-sensitive (`"match"`) or case-insensitive (`"imatch"`). The pattern fed to the trimming step already reflects the sensitivity demanded by the upper bound, so the operation is purely syntactic; no case-folding is needed during trimming.

**Impact**

This change should only affect glob patterns that contain an unescaped `**`. All existing tests for simple globs (no `**`) must continue to pass unchanged, while tests that included `**` in their upper-bound expectations will need to be updated to the shortened form. Additional unit-level testing for the edge cases listed above would be desirable.

**Future work (explicitly out of scope)**

The commit message mentions longer-term improvements like a full glob parser for even smarter `anyof`/`allof` collapsing (e.g., `anyof("foo/**", "foo/bar/**")` → just `"foo/**"`). That is not part of this task.

Trim components after `**` from glob upper bounds


**Title:** Replace Jansson’s `snprintf`-based double encoding with `fmt`
**Component:** `watchman/thirdparty/jansson/strconv.cpp` – `jsonp_dtostr`

---

### Problem
`jsonp_dtostr` currently formats doubles using `snprintf("%.17g", …)` and then runs locale-dependent post-processing (`from_locale`) to replace the locale’s decimal point with `'.'`.
This is slow, and on systems whose locale uses a different radix character the function can produce non‑standard JSON (e.g., a comma instead of a dot). The locale dependency must be removed entirely.

### Proposed change
Replace the body of `jsonp_dtostr` so that it uses `fmt::format_to_n` (or `fmt::print_to_n`) with the format specifier `{:.17g}`.

**Behavioural invariants / safety constraints**
- The output **must** be a valid JSON number literal.
- For values that are exact integers (e.g. `0`, `1`, `100`), the function **must** ensure the output contains a decimal point, e.g. `"0.0"` rather than `"0"`. This preserves the property that the value is decoded back as a JSON real, not an integer.
- Exponents emitted by `fmt` may include an explicit `'+'` sign (e.g. `"1e+20"` instead of `"1e20"`). This is valid JSON; **do not strip** the `'+'` or any leading zeros.
- Match the existing precision: 17 significant digits.
- Return the number of characters written (excluding a null terminator), or `-1` if the provided buffer is too small.
- Remove all locale-awareness code: delete the `from_locale` helper and the `#if JSON_HAVE_LOCALECONV` preprocessor blocks.
- The change must not alter the parsing side (`jsonp_strtod`).

**Acceptance criteria**
- JSON round-trips of real numbers are preserved: a double that survives JSON encode → decode must retain its value and remain a JSON real type.
- Performance of the double-to-string path is at least twice as fast as the current implementation.
- No locale-dependent behaviour.


Title: Watchman deadlocks when many subscriptions are cancelled concurrently

Description:
We’ve observed that the watchman daemon occasionally becomes completely unresponsive (deadlock) and stops processing commands from all clients. The hang seems to be triggered when a large number of subscriptions are torn down at roughly the same time. In our environment, this reliably occurs when a webserver process that holds many active Watchman subscriptions crashes or restarts, causing a flood of simultaneous client disconnections. The hang persists until the daemon is manually restarted.

The issue is intermittent and depends on timing; stress-testing with many concurrent subscription cancellations reproduces it. Expected behavior: watchman should safely handle simultaneous subscription teardowns without locking up.


Implement support for Eden’s new per‑mount `.eden` directory.

Eden now exposes a `.eden` directory at the root of every mount (reachable from any subdirectory via `stat` but not via `readdir`).  It contains two symlinks:

* `.eden/root`  → the mount root
* `.eden/socket` → the Eden server’s Unix‑domain socket

Use these to make Watchman’s Eden watcher mount‑aware and more robust:

1. **Mount detection** – when starting a watch, verify that the watch root is an Eden mount root by reading `.eden/root` and comparing it to the watch path.  If they don’t match, do not treat the path as an Eden mount.

2. **Server connection** – resolve `.eden/socket` with `readlink` and use the target as the server address.  The symlink target path may exceed the Unix socket path length limit, so always resolve the link before using it.  Remove the old hard‑coded per‑user socket address lookup.

3. **Client API** – all code that creates an Eden‑client connection must now receive the mount root and resolve the socket via `.eden/socket`.

4. **File listing** – file queries on the mount root must include the `.eden` directory and its symlink entries in the results (only at the root because `.eden` does not appear in `readdir` of subdirectories).


**Title**: Dark mode support for diagram rendering

**Problem**
When the user’s desktop environment switches to a dark theme, the Gaphor window adopts the dark appearance but the diagram canvas stays light. The background remains white and the diagram elements do not adapt their styling. Custom style sheets can already contain media queries like `@media (prefers-color-scheme = dark) { … }`, but these rules are never applied to the diagram, making it impossible for users to define dark variants of their models.

**Expected behavior**
1. The diagram canvas should respond to the system dark-mode setting. When dark mode is active, the canvas background should become dark (for example, following any explicit `background-color` defined in a matching `@media (prefers-color-scheme = dark)` rule, or falling back to a sensible dark background).
2. All elements rendered on the diagram should respect `@media (prefers-color-scheme)` rules in the active style sheet. Toggling dark mode on the fly must immediately re‑render the diagram, not just after a style‑sheet change.
3. The behaviour must degrade gracefully on the GTK 3 back‑end, where the system dark‑mode preference may not be available; in that case diagrams should keep their current (light) appearance.
4. When a diagram page is closed, any resources (such as signal subscriptions to the system style manager) must be cleaned up to avoid dangling references.
5. Updating the style sheet while in dark mode should still evaluate the media query correctly, without requiring the user to toggle the theme.

**Additional considerations**
- The canvas background and item styles must be consistent with the rest of the application when dark mode is enabled.
- The feature must not introduce performance regressions when dark mode is off (i.e. the default light rendering should be unchanged).
- The Gaphor style‑node hierarchy (the objects that represent the diagram, items, etc. during CSS matching) must expose the current dark‑mode state so that selectors compiled from the style sheet can test it. Today the media query selector function assumes a `color_scheme()` method that is never defined, which is why the rules never match.

Support dark mode in diagrams from the UI


**Title:** Containment relationships allow ownership cycles
**Type:** Bug
**Priority:** Medium

### Description
In diagrams that use containment relationships (the crossed-circle line notation), it is currently possible to create connections that introduce cycles in the ownership hierarchy. This makes the model invalid and can lead to subtle errors later.

### Steps to reproduce
1. Create a `Package` and a `Class` on a diagram.
2. Set the Class’s owning package to the Package (i.e., make the Class a child of the Package).
3. Draw a containment relationship line from the Class back to the same Package.

### Current behavior
The connection is allowed, resulting in a cycle where the Package contains the Class and the Class simultaneously contains the Package.

### Expected behavior
The containment connector should **reject** such a connection. When both ends of a containment relationship are bound to elements, the system must check whether the element on the *contained* end already belongs to the ownership chain (ancestor hierarchy) of the element on the *container* end. The check must traverse the full ownership chain (using the existing `self_and_owners` traversal) — i.e., prevent not only direct parent-child reversals but also deeper cycles where a grandparent is re-contained by a descendant.

### Notes
- The existing type-based restrictions (e.g., what kinds of elements can act as container or contained) should still be enforced; the cycle check is an additional safety guard that must operate on top of the current rules or supersede them where appropriate.
- This is observable to the user as a disallowed drop during diagram editing: when they attempt to complete the containment line, the rubber-band feedback should indicate the connection is invalid and the line should not be placed.

Avoid cycles when connecting Containment relations


When manually merging models after a Git conflict, the merge process produces a change set by comparing the **current** model directly with the **incoming** model. This yields a large, confusing list of modifications—many of which are already present in the current model—making the merge hard to review and apply correctly.

The merge should instead use the **common ancestor** model (the version from which both current and incoming diverged) as the baseline for computing differences. The resulting change set should contain only the changes introduced in the incoming model *since that common ancestor*, resulting in a smaller, more comprehensible set of modifications when applied to the current model.

Implementation notes:
- The ancestor model file is already available during conflict resolution (the `ancestor_filename` parameter in the merge conflict handler). The manual merge entry point must load this ancestor model and pass it to the diffing logic.
- The model comparison API should be extended to accept an ancestor model so it can compute a three-way diff: the comparison should be between the **ancestor** and the **incoming** models (not between the current and incoming models directly). Any exception reporting incompatible types should reflect the ancestor context.
- The progress feedback during the merge loading sequence should be updated to reflect the extra step (ancestor load), but the order of loading (current, then ancestor, then incoming) is flexible as long as the diffing uses the correct ancestor.

Compare incoming model with common ancestor to derive differences


The model merge tree (shown when comparing models) is supposed to nest changes so that composite children appear under their parent element. Currently the nesting logic uses a hardcoded list of property names (`"subject"`, `"ownedAttribute"`, `"ownedPresentation"`) to decide nesting, plus clumsy string checks on type names to exclude `"Diagram"` and `*Item` types. That makes it impossible for the view to work correctly with any modeling language other than UML, and even within UML it misses many legitimate composite relations.

**Change the merge‑change organizer so that it uses the modeling language’s property metadata instead of hardcoded strings.**
The organizer already has access to a `modeling_language` object (which can look up element types by name). It should resolve the type of both the owning element and the referenced element, then inspect whether the corresponding property has `composite = True`. A reference change should be nested as a child of the owner only when the property is composite; otherwise it should appear as a flat relation node (no further nesting).

During this work two important edge‑cases must be handled:

1. **Pending (not‑yet‑inserted) elements** – When an `ElementChange` describes an element that hasn’t been created yet, there’s no live element to call `type()` on. In that case the type must be obtained from the modeling language via the element name stored in the change record (e.g. `"Class"`, `"Diagram"`).
2. **Presentation (diagram‑item) updates** – When an existing diagram has changes on its owned presentation elements (e.g. a `ClassItem`’s `subject` reassignment or a property‑value change), those updates are currently omitted from the merge tree entirely. They should be collected and shown under the parent diagram node as child nodes representing the affected presentation elements.

The interface of `organize_changes` already receives the modeling language from the caller; adjust that call site if necessary, but the organizer must use property‑metadata‑driven logic everywhere.

**Observable behaviour after the fix**
- A UML class attribute (which is owned by a class via a composite property) appears nested under the class node, regardless of whether it is added, removed, or updated.
- A non‑composite reference (e.g. a `Diagram`’s `element` reference) appears as a flat relation node without further nesting.
- Value/ref changes on a `ClassItem` inside an existing diagram appear under a node for that diagram, labeled with the presentation type.
- Relation‑change labels reflect the *actual* property name used by the model (e.g. `"ownedDiagram"`) rather than a guessed short name.

Keep the existing tree‑structure invariants (one top‑level node per diagram, element‑change nodes group their own value/ref changes). The fix must work across the supported modeling languages (UML, SysML, RAAML, C4) without per‑language special‑casing.


The association end text updating currently triggers a cascading `request_update` from inside the end's text-setting method, causing the item's `update` to be called again within the same update cycle. Clean this up so that `AssociationItem.update` updates the end text directly and the text-update method on `AssociationEnd` no longer triggers a full item update. Also replace the explicit getters for the name and multiplicity strings with a public read-only property that exposes the currently displayed name.


Move session lifecycle management from the UI layer into `Application`.

Currently, `gaphor/ui/__init__.py` subscribes to `ActiveSessionChanged` and `SessionShutdown` events for every new session. Those subscriptions update `Application.active_session` and, on shutdown, call `Application.shutdown_session` then quit the GTK application when no sessions remain. This tightens coupling between the UI and core application state, and forces callers that create sessions to remember to duplicate these subscriptions (e.g., in `two_sessions` helper used by tests).

Instead, `Application` itself should:

- Track its own active session (`_active_session`) and update it correctly when sessions are created or `ActiveSessionChanged` fires.
- Listen for `SessionShutdown` on each session’s event manager so that session shutdown is handled directly within `Application`, not in the UI layer.
- Trigger application quit (e.g., `self.quit()`) when a session shutdown leaves no remaining sessions, but do so through a user-supplied callback (e.g., `on_quit` constructor parameter) rather than by calling GTK directly.
- Remove the `subscribe_to_lifecycle_events` function and its use from `gaphor.ui.run` and from any callers that create sessions.

No change in externally visible behavior: creating a new session must still set the active session, shutting down the last session must still trigger quit, and quitting while a session refuses to close must still abort the quit.

Move session lifecycle management in Application


**Title:** Model browser shows non-PackageableElements at top level

**Description:**
In the model browser (Namespace tree), elements that are not PackageableElements (e.g., Actions) incorrectly appear as root-level entries when they have no owning namespace. According to UML, only PackageableElements should be allowed at the top level of a model. Additionally, some elements like InstanceSpecification and Relationship should never appear in the tree (this was already partially enforced, but must be preserved).

**Acceptance criteria:**
1. The tree’s root nodes must only contain UML elements that are `PackageableElement` instances and have no parent namespace. For example, a free-floating `Action` must not appear at the root.
2. Elements that are not `PackageableElement` but *do* have a parent namespace (i.e., they are owned by another element) should still be displayed as children.
3. `InstanceSpecification` and `Relationship` instances must remain entirely hidden from the tree, regardless of their namespace.
4. When a user attempts to drag an element that is not a candidate for reparenting (e.g., something that is not a diagram, Package, or Type), the feedback should clearly indicate that the element cannot be moved, rather than a misleading “not part of the model” message.

Only allow PackageableElement at top level


## Request: Pseudostate tree icons should reflect the element kind

### What’s happening now
In the model tree view, every `Pseudostate` element (initial, choice, junction, fork, join, history states, entry/exit point, terminate) shows the same generic icon. Other UML element types that have distinct sub‑kinds already show kind‑specific icons, but `Pseudostate` is falling back to a default icon regardless of its `kind` attribute.

### Expected behaviour
The tree view icon for a `Pseudostate` should depend on its UML kind:

- **`initial`** → icon resource name `gaphor-initial-pseudostate-symbolic`
- **`choice`** → `gaphor-choice-pseudostate-symbolic`
- **`junction`** → `gaphor-junction-pseudostate-symbolic`
- **`fork`** → `gaphor-fork-pseudostate-symbolic`
- **`join`** → `gaphor-join-pseudostate-symbolic`
- **`deepHistory`** → `gaphor-deep-history-pseudostate-symbolic`
- **`shallowHistory`** → `gaphor-shallow-history-pseudostate-symbolic`
- **`entryPoint`** → `gaphor-entry-point-pseudostate-symbolic`
- **`exitPoint`** → `gaphor-exit-point-pseudostate-symbolic`
- **`terminate`** → `gaphor-terminate-pseudostate-symbolic`

When the `kind` attribute is `None` or missing, the icon should default to the **`initial`** variant (since `"initial"` is already the default kind for `Pseudostate`).

### Constraints
- The icon names must follow the existing kebab-case naming convention that is already used for element-kind‑specific icons elsewhere (e.g., `CamelCase` kind values get converted to `camel-case`).
- The change should only affect `Pseudostate` icon resolution; all other UML element types must keep their current behaviour.
- The mapping must reuse the existing helper that converts CamelCase strings to kebab-case (present in the icon‑name resolution area), so that future kind additions automatically produce the right resource name.

### Where to look
The icon resolution for UML elements lives in the UML module and uses a single‑dispatch mechanism to associate elements with icon names. There is already a custom dispatch for `Class` elements; `Pseudostate` will need a similar explicit registration that reads the element’s `kind` attribute.

Map pseudostate icon names for tree view


As a user of Gaphor's operation syntax, I'd like to be able to write `args: string[]` to indicate a parameter with an unbounded upper multiplicity. Currently, I can use `[0..*]` or `[*]`, but the common shorthand `[]` is not supported and either fails to parse or leaves the multiplicity fields blank.

**Acceptance criteria:**

1. When parsing an operation parameter like `name: Type[]`, the resulting parameter object must have:
   - `upperValue == "*"` (unbounded upper)
   - `lowerValue` unset (`None`) – no explicit lower bound
   - `typeValue` and `name` set as usual.

2. The parser must continue to accept all existing multiplicity notations:
   - `[n..m]`, `[*]`, `[n]` (where `n`, `m` are non-negative integers) and no multiplicity at all.
   - These existing forms must produce the same values as before, without regression.

3. The empty bracket form `[]` should be equivalent to `[0..*]` in its semantic effect on `upperValue` and `lowerValue`; it is just a shorthand for “unbounded.”

Please ensure the fix only affects operation parameter parsing and does not change any other parsing rules.

Allow `[]` notation for operation parameters


When undoing a deletion that involved a model element or diagram item with attributes and associations (for example, a Class with a name and linked via `subject` to a diagram item), the restored items are missing their relationships after undo. The undo action stack – which collects create, attribute-update, and association/unlink events – does not enforce a useful ordering. The required execution order is: any re-creation actions (restoring deleted elements) must happen first, then attribute changes and association sets/adds, and finally any unlink events must run last. Adjust the undo execution so that undo actions are applied in an order that respects this dependency.


When an element is moved into or out of another model element (for example, dragging a class into a package in the model browser, or reassigning a class’s package in the diagram), the navigation tree does not always update to show the new parent-child relationship. The element may remain under its old parent until the tree is manually refreshed or collapsed/expanded, giving the appearance of a stale state.

**Steps to reproduce:**
1. Use a template that starts with a root model element (e.g., the UML template).
2. Create a package and a class.
3. In the tree or via a diagram, assign the class to the package (i.e., make the class owned by the package).
4. Observe the model browser tree.

**Expected behavior:**
The tree should visually move the class node to be a child of the package, updating child counts accordingly. The tree should refresh without requiring a manual collapse/expand cycle.

**Actual behavior:**
The class remains shown only at its old location (e.g., under the root) after the ownership change. The tree item counts and structure are not updated until an external refresh occurs.

**Additional requirements:**
- Ensure the tree update is triggered both when ownership is set explicitly (direct owner change) and when the `ownedElement` derived collection changes (e.g., through model manipulation that doesn’t go through the owner setter).
- Avoid unnecessary flickering: if the tree branch for the element’s new parent is already expanded and showing its children, the update should still occur, but do not cause a redundant double-refresh that would lead to visual flickering. Only trigger the update when the branch has not yet been materialized, to prevent redundant notifications.

Also trigger update if Element.ownedElement changes


**Bug: Text editing in property fields produces a separate undo step per character; undo should group all edits while the field has focus**

**Description**
When editing a textual property (e.g., the name of a diagram or the description of a C4 model element) the undo manager records each individual change as its own undoable action. Pressing Undo after typing a word therefore reverts one character at a time rather than restoring the text to its state before the user started editing. This makes undo nearly useless for text entry and is inconsistent with typical editing behaviour.

**Expected behaviour**
- While the text field has focus (the user is actively typing or modifying the text), all consecutive changes to the same property should be merged into a single undoable transaction.
- The undo manager should finalise (“close”) the merged transaction as soon as focus leaves the editing widget, so that a subsequent separate editing session on the same property starts a new undoable step.
- When the property value becomes `None` (e.g., the text is completely deleted) the UI should display an empty string rather than crashing or showing an uninitialised state.

**Technical hints**
- The `Transaction` class already accepts a `context` parameter. You can use `context="editing"` to mark transactions that should be amendable.
- The undo manager (`UndoManager`) already knows how to push and pop action stacks; the requirement is to make it recognise that a new `editing` transaction should amend the previous one instead of creating a separate entry, but only if that previous transaction is still open (i.e., focus has not left the field).
- A focus-change signal from the main window can be used to notify the undo manager that the current editing session has ended, after which the next `editing` transaction must start a fresh undo step.
- Affected property pages: `NamePropertyPage` (diagram name) and the `DescriptionPropertyPage` for C4 model elements (Container, Person). Both currently create ordinary transactions; they should use the `editing` context and also normalise `None` to an empty string when reading values into the UI.

Amend text editing actions into one transaction


**Title:** Property editor for ActivityParameterNode does not manage the parameter’s name

**Description**
When you select an Activity Parameter Node on a diagram, the property editor on the right shows a “Name” field. Today that field appears to be bound to the node’s own `name` attribute, which is typically unused and never changes. As a user, I expect the name field to reflect and control the name of the node’s associated **Parameter** (the UML `Parameter` object). Only the parameter’s name is meaningful in this context, and it’s what I see in the model tree and what I want to edit.

**Acceptance Criteria**
1. **Display** – Selecting an Activity Parameter Node that already has a linked Parameter shows that Parameter’s `name` in the “Name” field. If the Parameter has no name yet, the field is empty.
2. **Write-back** – Typing into the “Name” field and confirming the edit (e.g., pressing Enter or moving focus) updates `parameter.name` on the linked Parameter. The change must be transactional (undo/redo works).
3. **No conflict** – There must be no second “Name” editor on the same property page that tries to edit the node’s own name. The standard named-element property page should not activate for ActivityParameterNodes at all; the new behavior replaces it completely.
4. **Fresh node** – Creating a new Activity Parameter Node (with a new Parameter) and immediately editing its “Name” works without errors.

**Additional context**
This issue only affects `UML.ActivityParameterNode` – other named elements (e.g., classes, actors) should keep their existing property-page behavior. The fix should follow the same property-page registration and builder patterns used for other specialised editors (e.g., the comment editor, the line style editor).

Fix property editor for Parameter node name


supervision_value: 4
difficulty: 3
reasoning: The change teaches a clear pattern migration: replace an ad‑hoc drop mixin with a handler registered on the generic `drop` dispatcher. The agent needs to locate both the existing state dropzone module and the generic drop mechanism, understand how the dispatch works, replicate the grouping logic, and wire the new handler into the UI layer through an import. It is a real multi‑step task that demonstrates investigation, comparison of sibling implementations, and careful removal of dead code while preserving behavior. It is not trivial but not excessively hard, making it a solid P2T candidate.

---

**Implementation request**

> Currently, dropping state items (StateItem, PseudostateItem, TransitionItem) onto a State or StateMachine diagram region uses a special DropZoneMove mixin in `gaphor/UML/states/dropzone.py`. This is inconsistent with how other drops are handled (e.g., partitions no longer use a dropzone custom mixin).
>
> Migrate the drop logic for these state‑diagram items to use the generic `drop` dispatcher from `gaphor.diagram.drop`. The new handler must replicate the existing behavior:
> - Determine the target region via `region_at_point` on the parent (StateItem or StateMachineItem).
> - If the item is already in that region, do nothing.
> - Otherwise, ungroup the item from its old region using `gaphor.diagram.group.ungroup` (if it had a parent), then group it into the target region using `gaphor.diagram.group.group`.
> - Call `grow_parent` and `change_parent` to update the diagram presentation.
>
> The handler should be registered for every combination where the item is a StateItem, PseudostateItem, or TransitionItem and the parent is a StateItem or StateMachineItem. The dispatch module must be loaded (e.g., imported in `gaphor/UML/uicomponents.py`).
>
> Once the new handler is in place, remove the old dropzone mixin completely and delete the corresponding test module. Make sure the existing test coverage for region‑based drop remains passing.


**Title:** Auto‑resize container when an element is dropped outside its current bounds

**Description**
When a user drags a diagram element (e.g., a Component, Class, or any visual element that is an `ElementPresentation`) and drops it onto a container element (such as a Node, Package, or other `ElementPresentation` container), the container currently does **not** resize to enclose the dropped item. If the item lands partially or fully outside the container’s visual bounds, the user must manually resize the container afterward.

This is confusing and breaks the direct‑manipulation feel of the modeling tool. We want the container to automatically grow to fully encompass the dropped element, including a small visual margin.

**Acceptance criteria**

1. **After a successful reparenting** (i.e. after the item’s parent is set to the new container), check whether the container needs to grow.
2. The container should be resized so that its bounding box becomes the union of:
   - its current bounding box (in canvas coordinates), and
   - the dropped item’s bounding box expanded by **20 pixels on all sides** (i.e. `item_bbox.expand(20)`), also in canvas coordinates.
3. **Both corners of the container may move** – the NW (top‑left) handle should shift left/up if the item extends beyond the container on that side, and the SE (bottom‑right) handle should shift right/down as needed. The container should never shrink.
4. Handle positions must be set in **item coordinates**. Convert the new canvas‑extent rectangle back to the container’s local coordinate system using the **inverse of the container’s item‑to‑canvas matrix** (`parent.matrix_i2c.inverse()`).
5. Only apply the resize when **both** the parent container and the dropped item are instances of `ElementPresentation` (regular visual nodes, not lines/connections). If the parent is not an `ElementPresentation`, log a warning and do nothing.
6. The resize should happen **before** the new parent is committed (so that all subsequent model/group updates see the final geometry).
7. No other side‑effects on the diagram or the drag‑and‑drop tool (the existing drop‑zone highlighting, grouping adapter, etc.) should be altered.

**Observable behavior after implementation**
- Drag a component (or any `ElementPresentation`) partially overlapping the boundary of a Node. On drop, the Node visually expands so that the component is fully inside, with a 20‑pixel margin visible.
- Dropping an item completely inside the container leaves the container unchanged.
- Dropping a line onto a container does **not** trigger resizing.
- The change is purely visual; the model and diagram structure remain correct.

Grow parent item when an item is dropped on it


In the text editing for attributes and association ends (the notation `name: Type[mult]`), allow empty brackets `[]` to set the upper multiplicity to `*` (i.e. `0..*`), matching the existing behavior of `[*]`. Currently `[]` is apparently parsed but leaves the multiplicity unchanged, so the shorthand has no effect. Both attributes and association ends should interpret `[]` as upper bound `*` with no explicit lower bound.

Allow `[]` for attributes and association ends


The `search()` function in the tree search module hard‑codes the entire traversal (flattening) of the tree model. That prevents clients from plugging in a different walker—for example a custom ordering, filtering, or a different tree structure. Make the tree walker configurable so that callers supply the sequence of `TreeItem`s to be searched, rather than having `search()` construct it internally. The existing flatten‑and‑sort behaviour should be available as a separate, reusable function that returns a sorted iterable of `TreeItem`s, preserving the current semantics (sorted, depth‑first traversal, with the same `start_tree_item` / `from_current` handling). Update all internal callers (especially `SearchState` in `treecomponent.py`) to use that new function and pass the resulting iterable to `search()`. The search logic itself—case‑insensitive, NFC‑normalised matching on `tree_item.text`, skipping items without an `element`—must remain unchanged.


Please integrate diagram export from the standalone `gaphorconvert` tool into the main `gaphor` CLI as a new `export` subcommand. The export subcommand should reuse the existing export logic but must not clash with the global `--debug` (`-d`) flag. The old `gaphorconvert` script uses `-d` for the output directory; change the output directory short flag to something else (e.g., `-o`) while keeping the `--dir` long flag. Remove the separate `gaphorconvert` entry point from `pyproject.toml`. Ensure that `gaphor export -o <directory> <model>` works correctly and that global flags like `-d` (debug) remain usable when running the export subcommand.


**Bug: Orphaned elements appear at model browser root after creating a profile extension**

When building a UML profile with an extension (stereotype extending a metaclass), the model browser can show spurious top‑level items at the root, outside the profile’s subtree. The profile should remain the only root element; all its contents (metaclass, stereotype, extension) should appear beneath it.

Steps to reproduce:
1. Create a UML Profile package.
2. Add a Class (the metaclass) inside the profile.
3. Add a Stereotype inside the profile.
4. Connect the stereotype to the metaclass with an Extension relationship.

After these steps the model browser sometimes displays an extra root element (e.g., the metaclass or a related item) alongside the profile, even though it still appears correctly inside the profile.

The underlying issue appears to be that when the ownership of an element changes, the browser is not fully removing it from its previous location. Specifically, if an element had both an owner (e.g., `package`) and a `memberNamespace` that differs from `namespace`, the removal logic only cleans up one of those two associations, leaving the element lingering in the root or in incorrect branches.

**Acceptance Criteria**
- After any structural change that moves an element (including extension creation), the model browser’s root level must contain only elements that genuinely have no containing parent within the model.
- For the profile-extension scenario, only the `Profile` node appears at the root; the metaclass, stereotype, and the extension relationship are all children (or descendants) of that profile.
- The browser must clean up an element’s previous position from *both* its former owner and its former `memberNamespace` when they differ, so that no ghost entries remain at any level of the tree.

Remove both owner and memberNamespace in model browser


We need a progress bar during manual merge conflict resolution. Currently when the user selects "manual" resolution from the merge conflict dialog, the app silently loads both the current and incoming models. For large models this feels like a hang.

Add a progress window (the same `StatusWindow` we use for regular file loading) that shows loading progress across the two phases:
- Phase 1: loading the current model (0-50% of the bar)
- Phase 2: loading the incoming model (50-100% of the bar)

After both models are loaded and the in-memory compare is done, destroy the progress window. The models must still be loaded exactly as they are today (current into the main element factory, incoming into a temporary factory, then compare). No other behavioral change.

Show progress bar when loading merge conflict


The tree model currently uses `None` both as the dictionary key for the root-level branch and as the return value of `owner` to mean "has no owner". This conflates two distinct cases: elements that genuinely belong at the top level (e.g., packages without a containing namespace) and elements that should not appear in the tree at all (e.g., comments, instance specifications, occurrence specifications, multiplicity elements, slots). Because the root branch is keyed by `None`, the latter elements incorrectly appear at the root.

We need a clean separation: a dedicated sentinel that means “this element lives at the root” vs. `None` meaning “this element should not be shown anywhere in the tree.” In addition, `ModelBrowser.on_owner_changed` works around the old ambiguity by passing a `former_owner` hint to `remove_element`; with the new sentinel that workaround should become unnecessary – `remove_element` can locate the element’s current branch by scanning the existing branches.

Implement these changes:
- Create a sentinel (e.g., an enum member) to represent the root level, distinct from `None`.
- Update `TreeModel` so its `branches` dictionary uses this sentinel instead of `None` as the root key. The `root` property, `owner_branch_for_element`, `tree_item_for_element`, `remove_branch`, `clear`, and any other internal lookups should treat the sentinel as the root identifier.
- Change the `owner` function and its overloads so that it returns the root sentinel only for elements that logically belong at the top level (their owner/memberNamespace is absent and they are not invisible types). Return `None` for elements that must be hidden: for the generic `Element` dispatch, exclude `UML.MultiplicityElement` and `UML.Slot`; for the `NamedElement` dispatch, additionally exclude `UML.Comment`, `UML.InstanceSpecification`, `UML.OccurrenceSpecification`. For visible elements without an explicit parent, the root sentinel is the fallback.
- Simplify `remove_element` so it no longer accepts a `former_owner` parameter. Instead, find the branch that currently contains the element by checking all branch lists. Remove the element from that branch and clean up child elements recursively as before.
- In `notify_child_model`, handle cases where `tree_item_for_element` returns `None` (meaning the element is not yet placed) by falling back to the root sentinel where appropriate, so parent-notification still works for elements that end up at root level.
- Adjust callers: stop passing `former_owner` in `ModelBrowser.on_owner_changed` and in any other site that calls `remove_element`.

The intended behavior is that elements like comments, instance specs, and occurrences simply never appear in the model tree, while elements without an owner that should be visible appear at the root level, and the internal bookkeeping distinguishes the two cases cleanly.

Introduce a Root item for the tree model


## Request: Containment connector does not register and uses wrong UML association

**Observed behavior**

When a user draws a containment relationship between elements in the diagram editor, two things go wrong:

1. The containment connector does not appear to be registered at all — the tooling/connection logic for containment is not active. This suggests the module that wires up the connector is never imported.
2. When the connect logic does run, it assigns containment by setting `ownedElement` directly on the containing package. According to the UML metamodel, containment should be expressed through the `package` property of the contained element (e.g., `Type.package`, `Package.package`, `Diagram.package`), not by mutating the container's `ownedElement` collection.

The expected behavior is:

- The containment connector is properly registered and available when the classes module is loaded.
- Connecting a containment line between a package and another valid element (Type, Package, or Diagram) sets the `package` reference on the contained element to point to the containing package, in both directions (if the package is at one end, the element at the other end gets its `package` set; if the package is at the other end, the same relationship is established).
- The types of the connected subjects are validated: if one end is a `Package`, the other must be a `Type`, `Package`, or `Diagram`; if neither end is a `Package`, the connection should be rejected.

**Acceptance criteria**

- Containment connection tooling is active when the UML classes subsystem initializes.
- Connecting a containment line between a `Package` and a `Type`, `Package`, or `Diagram` establishes the correct ownership by setting `package` on the non-package element.
- The direction of the connection does not matter — whichever end holds the package becomes the container.
- Invalid combinations are caught with appropriate assertions.

Fix import and tests for containment item


```
Title: Undo does not restore element handle positions, and line tail undo is broken

When a user drags a handle on a shape (any box-like diagram element such as a
Class, Package, etc.) and then invokes Undo, the handle's position is not
reverted. The shape stays resized/moved.  The same operation works correctly
for line head-handle movement, so the undo system should handle element handles
consistently.

Additionally, while lines appear to support undo for handle positions, only the
**head** (first) handle movement is actually recorded; moving the **tail**
(last) handle and undoing leaves the tail in the wrong position.  Both head
and tail handles must be tracked so that undo restores their exact pre-move
positions.

Acceptance criteria:
- Moving **any** handle of a shape element (all four handles of a box)
  and then undoing restores that handle's previous position.
- Moving the **tail** handle of a line and undoing restores its position,
  just as it already does for the head handle.
- Redo re-applies the move correctly in both cases.
```

Add tests for undo behaviour of elements


We need a behavior-first implementation request describing the bug and the desired fix, so that an agent reading only the parent code and this request can produce the patch. The request should refer to observable problems (incorrect undo/redo stacks), mention the need for a transaction context, and point to the public API (Transaction constructor, events, undomanager logic) without prescribing the exact code changes or file locations beyond what's natural.

Below is that request.

---

**Title:** Transaction context for undo/redo/rollback to fix incorrect stack management

**Description:**

The undo system occasionally misbehaves: after rolling back a transaction, the undo stack incorrectly holds an undoable action, and undo/redo operations sometimes push onto the wrong stack or clear stacks they shouldn’t. This stems from a race between the undo manager’s internal state flags (`_undoing`, `_redoing`, `_rolling_back`) and the arrival of commit/rollback events. By the time those events are processed, the flags have often been cleared, so the manager makes wrong decisions about how to manage the undo and redo stacks.

To fix this reliably, the transaction system should carry an explicit context that labels each transaction as part of an *undo*, *redo*, *rollback*, or a normal (no context) operation. The context must be set when the transaction is created and then propagated through `TransactionBegin`, `TransactionCommit`, and `TransactionRollback` events.

Concretely:

- Extend the `Transaction` constructor to accept an optional `context` argument (default `None`) and relay it to the events.
- The `UndoManager` must pass the appropriate context each time it opens a new transaction for undo (`"undo"`), redo (`"redo"`), or rollback (`"rollback"`).
- The undo manager’s commit and rollback handling (`_UndoManagerTransactionCommitted` / `_UndoManagerTransactionRolledBack`) should carry this context instead of relying on the mutable flags. Stack management (where to push transactions, whether to clear the redo stack, whether a rollback must not add to the undo stack) should then be decided based on the context carried by the event.

**Acceptance criteria:**

- After a `Transaction` is explicitly rolled back, the undo stack is empty (i.e., `can_undo()` returns `False`).
- Undo operations push undone transactions onto the redo stack but do **not** clear the redo stack.
- Redo operations push onto the undo stack while preserving existing redo entries.
- Normal transactions continue to behave as before: they push onto the undo stack and clear the redo stack.
- The behaviour is correct regardless of when the commit/rollback events fire relative to the undo manager’s internal flag resets.

Define a transaction context for undo, redo, and rollback


**Title:** Add EPS export option (Encapsulated PostScript) for diagrams

**Description:**
Users should be able to export a diagram as an EPS (Encapsulated PostScript) file via the File → Export menu, alongside the existing PNG, SVG, and PDF options.

**Expected behavior:**
- A new export action “Export as EPS” appears in the export submenu.
- Selecting it opens a save-file dialog defaulting to `.eps` extension and `application/postscript` MIME type.
- The generated file is a valid EPS file that can be imported into other tools (e.g., LaTeX, Inkscape, Scribus).
- The EPS output should include the proper EPS header (e.g., `%!PS-Adobe-3.0 EPSF-3.0`) and a bounding box that matches the diagram content.

**Implementation notes:**
- Cairo supports EPS generation via `cairo.PSSurface` with `set_eps(True)`. Use that surface type when rendering the diagram, similar to how `PDFSurface` is used for PDF export.
- Follow the same pattern used for the existing export functions (`save_png`, `save_svg`, `save_pdf`) – they all wrap `render()` with an appropriate surface factory.
- Ensure the new export function is importable from `gaphor.diagram.export` and hooked into the diagram export plugin’s action definitions (the `DiagramExport` service) like the other formats.


**Feature Request: "Diagram Metadata" General Diagram Item**

**Problem**
There is currently no way to attach metadata (author, website, description, revision, license, creation/update dates) directly to a diagram in a structured, visible form. Users must resort to plain text comments or external documentation.

**Desired Behavior**
A new general diagram item should be available in the diagram toolbox under the "General" section, labeled "Diagram metadata". When placed on a diagram it should display a formatted block with the following labeled fields:

- created by
- website
- description
- revision
- license
- created at
- updated at

The item should behave like other general items (Box, Ellipse, Comment line, etc.) – it has no underlying UML model element, so it does not appear in the model browser, cannot be linked to classifiers, and does not participate in semantic validation.

**Constraints & Edge Cases**
1. The item must be correctly excluded from any mechanism that asserts every diagram item has a model element mapping (it is presentation‑only, like `Box`, `Ellipse`, `CommentLineItem`).
2. The field values should be empty by default and editable through the standard property editor (or scriptable). The rendering must gracefully handle empty values (showing just the label).
3. The layout should use the same styling and separator drawing functions already used for other diagram items (e.g., border, top/left separators).
4. The item should support text‑based localisation for the field labels.

**Impact**
Users will be able to include standard metadata directly inside diagrams, improving traceability and compliance without cluttering the model namespace.


Change the `copy` dispatch function and its registered implementations from returning a single `(id, copy_data)` tuple to being a generator that yields one or more such tuples. This enables individual copy handlers to emit extra related elements (model elements or other presentations) when needed, without changing the existing single-element behavior.

All existing `copy` handlers must be converted to `yield` their result instead of `return`. Callers that currently consume the result as a direct tuple must be updated to treat the function as an iterator – for the common single-value case, wrap the call with `next(copy(...))` to obtain the first yielded tuple. Ensure that the function’s return type annotation is updated to `Iterator[Tuple[Id, ...]]` and that existing behavior is preserved exactly.


**Summary:**
ProxyPortItem embeds a reusable visual pattern (an attached square with a handle, four edge ports, and connection‑aware shape updates) that is also needed for upcoming SysML elements such as Pins and Parameter Nodes. The logic should be factored into a generic base class so it can be shared without duplication, while keeping ProxyPortItem’s specific appearance intact.

**Problem:**
When trying to implement SysML Pins or Parameter Nodes, we discovered that their diagram‑level presentation behaviour is identical to that of ProxyPortItem: a small rectangle that attaches to another element via a single connectable handle, exposes four `LinePort` edges for connections, and updates its shape (visual position of labels/stereotypes) based on which side it is attached to. All of this logic is currently hard‑coded inside `ProxyPortItem`, so the only way to add a new attached element is to copy the class and modify it. This leads to code duplication and makes future maintenance harder.

**Expected Behaviour:**
- There should be a reusable, generic base presentation class that captures the common “attached element” behaviour: handle creation and port arrangement, geometric constraints, shape update cycle (including detection of the connected side), point‑hit testing, drawing, and serialisation (save/load). The class must be parameterised by the subject element type.
- `ProxyPortItem` should become a thin subclass of this base, overriding only what is necessary to produce its specific visual content (the proxy stereotype label and the element name). It must continue to behave exactly as before, including correct serialisation of its position and connection state.
- The base class should be designed so that future attached element types (Pins, Parameter Nodes) can be added by subclassing and overriding the shape definition, without duplicating any of the handle/port/update infrastructure.
- All existing ProxyPortItem behaviour must be preserved, notably the way it restores its connection to a parent block after save/load, and that its four ports are correctly positioned relative to the handle.

**Impact:**
Without this extraction, adding any new attached element requires copying and pasting a substantial amount of presentation code, which is error‑prone and makes it difficult to evolve the shared behaviour later. Providing a clean base will make the SysML diagram code more modular and reduce the effort needed to introduce similar elements.

Extract AttachedPresentation from ProxyPort


The auto-layout plugin (pydot) does not handle `ForkNodeItem` properly. When a diagram contains a fork or join bar, the layout either skips the item entirely or puts it at the wrong coordinates. The issue is that `ForkNodeItem` is not an `ElementPresentation` — its geometry is defined by two handles that mark the corners of a rectangular bar, and the item’s position semantics differ from the center-point convention used for element presentations.

Make the pydot auto-layout plugin understand `ForkNodeItem`:
- Represent it as a rectangular pydot node whose width and height come from the handle positions.
- When the layout computes a placement, apply the position back to the item in a way that respects the item’s own coordinate system (which treats the computed point as the item’s origin, not its center). This also means the y-coordinate should not be flipped and offset by the diagram height+centering like we do for `ElementPresentation`.

The desired outcome is that after invoking auto-layout on a diagram containing a `ForkNodeItem`, the bar appears at a sensible location consistent with the rest of the laid-out graph.


## Summary

When dragging an element in the model browser to change its owner, the drop target can be a descendant of the dragged element. This is currently accepted and creates an ownership cycle, which corrupts the model. Such drops must be silently rejected.

## Expected behavior

- If the element being moved is already an ancestor of the target element (the new parent), the reparenting must be aborted — no change to the model.
- In all other cases, the drop must work as before (e.g., moving to a sibling, a higher-level container, or from root).
- The guard should apply to any element that participates in ownership (Package, Class, Diagram, etc.).

Improve check to avoid cycles in ownership


The `TreeModel` has repeated logic across `tree_item_for_element`, `add_element`, and `remove_element` to resolve the list model that actually contains an element’s tree item. In particular, `UML.Relationship` elements are not placed directly in the owner’s list model; they are grouped under a synthetic `RelationshipItem` branch nested inside the owner’s model. This grouping is currently handled ad‑hoc each time, which is fragile and makes it hard to avoid creating the relationship branch when only querying.

Unify this logic so that there is a single method that, given an element, returns the `Gio.ListStore` where that element’s tree item lives (or should be added), handling the relationship indirection internally. The method should:
- Return the root model when the element is `None`.
- Use the element’s owner to find the containing model via `list_model_for_element`.
- If the element is a `UML.Relationship`, redirect to the relationship branch under that owner’s model. If the branch does not exist yet and the caller does not need to create it, return the owner’s model without altering the branch structure.
- Return `None` when the owner cannot be found.

Update `tree_item_for_element`, `add_element`, and `remove_element` to use this centralised lookup instead of repeating the relationship special‑case. Make sure that adding a relationship still creates the `RelationshipItem` branch when missing, but look‑ups and removals never accidentally create one.

Bring list and relationship code together


**Title:** Full copy of a diagram via its DiagramItem should duplicate the entire diagram contents

**Description:**
When a user copies a `DiagramItem` (the node that represents a diagram on a parent diagram) and uses **Full Paste** (`Ctrl+Shift+V`), only the diagram node itself is pasted— the target diagram does not receive a copy of the elements, relationships, and layout from the source diagram. We need to support a true full copy of a diagram: the source diagram’s complete contents (owned elements, presentations, and their connections) should be deep‑copied, and a new `Diagram` model element should be created that owns all those copied elements. The pasted `DiagramItem` should then point to that new diagram.

This must work across element factories (i.e., copying a diagram from one model to another) and should behave correctly when the source diagram contains further nested diagrams or references to other model elements.

**Expected behavior**

- Selecting a `DiagramItem` and performing a **full paste** should:
  - Create a new `Diagram` in the model.
  - Deep‑copy all elements that are owned by the source diagram (classes, packages, associations, etc.) into that new diagram.
  - Copy the visual layout (presentations) so that the new diagram shows the same arrangement.
  - Make the pasted `DiagramItem`’s `subject` point to the newly created diagram.

- If multiple `DiagramItem`s are copied together, each should produce its own new diagram with the correct contents.

- The new diagram and its contents must be fully integrated into the target model; no dangling references or duplicate identifiers.

- The fix should not change the semantics for non‑presentation copies (e.g., copying a plain `Package` that happens to own a `Diagram`). In that case, the owned diagram should **not** be needlessly duplicated as a separate model element when the package is pasted into a target diagram.

**Implementation notes (for context)**
The copy‑paste pipeline lives in `gaphor/diagram/copypaste.py`. Relevant parts: `copy_full` / `paste_full`, the `CopyData` and `PresentationCopy` named tuples, and the `paste_presentation` dispatch. The core challenge is that currently all pasted presentations unconditionally land on the single destination diagram (`_paste`’s `diagram` parameter). For diagram‑copying we need them to land on the new diagram(s) that were created as part of the deep copy. A likely approach is to record the original diagram id(s) alongside the copied data and, during paste, create a mapping from those original ids to the newly created diagram(s) so that `paste_presentation` can look up the correct target diagram.

This is a feature that several users have requested; the deep‑copy infrastructure (owned element traversal) already exists, so the changes should be scoped to the presentation‑paste logic.


**Title:** UML common property pages lack proper transaction support for type changes

**Background**
`TypedElementPropertyPage` and `ShowTypedElementPropertyPage` (used when selecting or displaying the type of a UML typed element in the property editor) modify model state or diagram item state through callback methods that are decorated with `@transactional`. However, these pages are never given an `event_manager` reference, so the decorator cannot reliably create a transaction—it depends on a global event manager that may not be active when the pages are constructed. This leads to changes (e.g., assigning/clearing a type via the dropdown, or toggling “show type” on a diagram item) that are not wrapped in a proper undoable transaction.

**Request**
Make the two property pages follow the same pattern already used by all other modern property pages in the codebase (e.g., in `gaphor/SysML/propertypages.py` or `gaphor/diagram/propertypages.py`):

- Accept an `event_manager` argument in the constructor and store it.
- Replace the `@transactional` decorator on the state-modifying callbacks (`_on_property_type_changed` and `_on_show_type_change`) with an explicit `with Transaction(self.event_manager):` block around the actual model/item modification.
- Remove `@transactional` from the helper functions `list_view_activated` and `list_view_key_handler` in the same module if they do not perform model changes that require a transaction (they only toggle an editing flag or handle keyboard navigation).

**Acceptance criteria**
- Selecting or clearing the type of a typed element via the property editor results in an undoable transaction.
- Toggling the “show type” checkbox on a diagram item results in an undoable transaction.
- The `@transactional` decorator is no longer relied upon in this module for the described operations; instead the event manager stored on the page is used.
- The change is consistent with other property pages that already accept `event_manager` and use `Transaction` directly.

Fix transaction for UML common property pages


Title: Dependency elements should be owned by the package they are defined in

When loading model files saved with Gaphor releases older than 2.28.0, `Dependency` instances may not have an `owningPackage` set. According to UML semantics, a `Dependency` should be owned by the `Package` where it is defined – in practice, this is the `Package` that contains the diagram on which the dependency is shown.

We need an upgrade step that runs during model loading for files whose saved version is lower than `2.28.0`. For every `Dependency` that has a presentation on a diagram, the upgrade should:

- Walk up the diagram’s owner chain to find the enclosing `Package`.
- Set that `Package` as the Dependency’s `owningPackage` so that the model conforms to the expected ownership structure for later operations.

This ensures that older models remain consistent with the current modeling rules without requiring manual rework.


```
Make diagram items addressable in CSS-like style sheets by their short name
without the trailing "Item" suffix. For example, a `ClassItem` should be
selectable as `class` instead of `classitem`.

To do this, update the styling protocol so that style nodes report a
`name()` method instead of the current `local_name()`. The diagram node
should return `"diagram"`, and each item node should return the lowercased
class name with a trailing `"Item"` stripped (case-sensitive). If the
class name does not end with `"Item"`, just lower-case the full name as
before.

Update the selector compilation to call `name()` rather than `local_name()`.

Additionally, tighten the guard in `Diagram.create_as` so that only items
that inherit from `Presentation` can be added to a diagram; this ensures
the style system can rely on the presence of a `canvas`.
```

-Item stffix is stripped from item names


```markdown
**Title:** Make `matrix_i2c` reactive — remove manual recomputation from update phase and loader

### Context
In Gaphor’s diagram layer, each `Presentation` item has a local `matrix` and a computed `matrix_i2c` (item‑to‑canvas), which is the composition of the item’s own transform with its parent’s `matrix_i2c`.
Right now `matrix_i2c` is not kept up‑to‑date automatically. Instead:

- `Diagram.update_now()` iterates over dirty items and recalculates `matrix_i2c` using `Diagram.get_matrix_i2c()`.
- The storage loader runs an explicit pass after loading a model to set `matrix_i2c` for every item.
- Some tool code (e.g. `connect_opposite_handle`) also calls `get_matrix_i2c()` manually.

This design is fragile: `matrix_i2c` can be stale outside the update cycle, and it forces the update machinery to worry about matrix recomputation order.

### Desired behaviour
We want `matrix_i2c` to **always reflect the correct item‑to‑canvas transform**, updated instantly whenever anything that affects it changes. Specifically:

1. When a `Presentation`’s own local `matrix` changes, its `matrix_i2c` must be recomputed immediately (as `local_matrix × parent.matrix_i2c`).
2. When the item’s **parent** changes (set, unset, or replaced):
   - The item’s **world‑space position must be preserved**. The local matrix should be adjusted so that `local_old × old_parent.matrix_i2c == local_new × new_parent.matrix_i2c`.
   - After the adjustment, `matrix_i2c` is updated accordingly.
3. When a parent’s `matrix_i2c` changes (e.g. because the parent itself moved or was reparented), **all descendants’ `matrix_i2c`** must be updated recursively.
4. After loading a model, no separate pass should be needed — the reactive wiring must be set up so that every item already has the correct `matrix_i2c` and will continue to react to future changes.

### Consequences for existing code
Once the reactivity is in place we should be able to **remove**:

- The `matrix_i2c` recomputation loop inside `Diagram.update_now()`.
- The `Diagram.get_matrix_i2c()` method and the `Diagram._presentation_reparent` watcher that currently handles parent changes.
- The manual `matrix_i2c` assignment in `connect_opposite_handle` (placement.py).
- The explicit `matrix_i2c` setup pass in the storage loader.

### Edge‑cases / safety notes
- Reparenting must be visually stable: an item that changes parent should not jump on screen.
- Unsetting a parent should yield an identity transformation for the former child’s `matrix_i2c` (its own local matrix unchanged).
- When a presentation is **unlinked**, all reactive handlers must be cleaned up to avoid dangling references.
- The mechanism should not introduce performance regressions — it is acceptable to use property change notifications or watchers already available in the element framework to trigger updates.

### Starters
Look at the current `Diagram.get_matrix_i2c()` and the watcher on `ownedPresentation.parent`, as well as the code that sets `matrix_i2c` in `Diagram.update_now()` and in the storage loader. The goal is to move that logic into `Presentation` itself and make it fire on changes to `parent` and `matrix`, plus propagate when a parent’s `matrix_i2c` changes.
```

Presentation now instantly updates `matrix_i2c`


**Title:** Model merge tree omits child elements linked by composite relations (subject, ownedAttribute, ownedPresentation)

**Description:**
When the model merge dialog displays a set of pending changes that add a new diagram containing presentation items and their model elements, the change tree does not show the full hierarchy. In particular, model elements that are linked to a presentation through composite relations such as `subject`, `ownedAttribute`, or `ownedPresentation` are missing from the tree.

**Steps to reproduce:**
Create a change set that adds a new `Diagram`, a `ClassItem` (presentation) owned by that diagram via `ownedPresentation`, a `Class` referenced as the `subject` of that item, and a `Property` owned by the class via `ownedAttribute`. When these changes are loaded in the model merge UI, the tree view may not include the `Property` or the `Class` itself if they are not already present in the target model.

**Expected behavior:**
All elements that are introduced together with their composite parents should appear nested under the appropriate parent node in the merge tree. A diagram addition should show its owned presentation items, each presentation’s subject, and any attributes owned by those subjects, exactly as the final model would be structured.

**Actual behavior:**
Elements that are only referenced through composite properties are omitted from the tree when the parent element has not been persisted in the target model yet. This makes it impossible to review or individually accept/reject these dependent changes.

**Additional context:**
This seems to happen primarily for newly added elements whose parents also do not exist in the model factory yet. If the parent element already existed, the composite children may appear, but for entirely new branches the tree construction appears to skip them. The problem impacts change sets where composite nesting is deep (e.g., diagram → presentation → subject → owned attribute).


**Request:**
When performing a full copy (for full paste), only the directly selected diagram items are serialized. Model elements typically own other elements (e.g., a UML Package owns sub-Packages, a Class owns Operations). Those owned elements should be included recursively in the copy buffer so that a full paste recreates the entire hierarchy.

Concretely:
- Extend `copy_full` to optionally accept a lookup callable that maps element IDs to real model elements.
  When provided, `copy_full` must traverse `ownedElement` recursively for each copied item and serialize those owned elements as well.
  Only include elements whose `owner` is the containing element being copied; do not blindly copy every element only referenced by the owner.
- Update the UI copy service’s `copy` method so that when copying for a full paste, it passes the element factory’s `lookup` to `copy_full`.
- The original shallow behavior (no lookup provided) must still work unchanged, so that callers who don’t need hierarchical copy are not affected.
- Avoid duplication: if an element is already present in the accumulated copy data, it should not be added again.


The containment relationship line does not enforce direction, and its visual notation is attached to the wrong end. In UML, a containment (crossed circle) relationship is directed: the head (the end with the crossed circle) represents the owning package, and the tail represents the owned element. The current implementation draws the crossed circle at the *tail* end, and the connection logic tries to infer which end is the container based on the types of the connected elements, swapping roles if the "wrong" one appears to be a Package. This leads to confusing behavior when both ends are packages, and it allows connections where a non‑package sits at the head end.

Acceptance criteria:

1. **Visual direction**
   The crossed‑circle symbol must appear at the *head* end of the containment line, not the tail.

2. **Directional connection semantics**
   When a containment line is connected (or reconnected) to domain elements, the connector must use the line's head/tail direction to decide roles:
   - The element attached to the *head* handle is the container. It must be a `Package`.
   - The element attached to the *tail* handle is the contained element. It must be a `Type`, `Package`, or `Diagram`.
   - Only when these type constraints are satisfied is the containment relationship applied: `contained.package = container`.

3. **No role swapping**
   The connection logic must never swap container/contained roles based on which element happens to be a `Package`. The head always identifies the container, regardless of the order in which the two ends are connected.

4. **Disconnection safety**
   Disconnecting any end should still cleanly remove the `package` association without leaving dangling references (existing behavior should continue to work; no regressions).

5. **Scope**
   The crossed‑circle drawing function should remain available only for the containment line; it does not need to stay in the generic diagram shape utilities if it is not used elsewhere.