# MSet Instruction Author 02 - Command composition

Status: **canonical-development**
Branch: **MSet 64-bit**
Current product: **MSet 2026 by GRAPHICO**
Format covered: **MSet 2026 native instruction format 2026.1 plus legacy-readable packages**

## Purpose

This is the second required module for an LLM that will read, explain, create, or modify an MSet 64-bit instruction.

After this module, the model should understand exactly how MSet 2026 builds the source command for a selected `Feature`, how that differs from `Instruction` and `Page` lifecycle commands, how command-fragment boundaries are represented, and how the composition-control macros `$C` and `$X` behave in the current runtime.

This module does **not** yet teach standard scale substitution, exact scale-sensitive key-in syntax, Bentley key-in catalogues, or Annotation Scale behavior. `$M(...)` remains outside canonical MSet 2026 authoring guidance.

## Source authority

For this module, current MSet 2026 implementation and contract tests are authoritative. The MSet 10 manual and the runtime-verified `MSet_Polohopis` package are supporting evidence where they agree with current behavior.

Do not import MSet 32-bit/V8i behavior into this module.

## 1. Three command scopes must stay separate

MSet 2026 has three relevant command scopes:

1. `Instruction` direct command text,
2. `Page` direct command text,
3. the effective command of a selected `Feature`.

They do not form one inherited chain.

### `Instruction` command

Direct command text on the root `Instruction` is a lifecycle command. MSet executes it when that instruction becomes active.

It is **not** inherited by a `Feature`.

### `Page` command

Direct command text on a `Page` is a lifecycle command. MSet executes it when that Page becomes active, including the initially active first Page when an instruction is activated.

It is **not** inherited by a `Feature`.

### `Feature` effective command

A selected `Feature` receives command fragments only from:

```text
highest ancestor Group
-> nested Group(s), in hierarchy order
-> selected Feature
```

`Instruction` and `Page` command fragments are deliberately excluded.

## 2. Command fragments are local to their XML node

For `Instruction`, `Page`, `Group`, and `Feature`, the parser reads the node's direct text/CDATA as that node's local `CommandFragment`.

Text belonging to nested child elements is not automatically merged into the parent's local fragment.

DTD/entity expansion happens while the XML document is loaded. Therefore an entity can supply:

- command text that becomes part of a local fragment, or
- complete XML nodes that become part of the instruction hierarchy.

When editing a package, trace entity/include sources before changing what appears to be a local command.

## 3. Canonical Feature composition algorithm

For a selected `Feature`, current MSet 2026 composes the source command as follows:

1. walk from the Feature's parent Group toward the root and collect all ancestor Groups,
2. reverse that ancestry so the highest Group comes first,
3. append each non-empty Group `CommandFragment`,
4. append the Feature's non-empty `CommandFragment`,
5. append a semicolon after every contributing fragment.

Schematic example. The resource-like names and numeric state values below (for example `Roads`, `co=7`, `wt=2`) are illustrative placeholders only; they are not a resource contract and must not be copied into real authoring without evidence:

```xml
<Group Cpt="A">co=7
    <Group Cpt="B">lv=Roads
        <Feature Cpt="Draw">wt=2;place smartline</Feature>
    </Group>
</Group>
```

Raw composed source:

```text
co=7;lv=Roads;wt=2;place smartline;
```

The order is significant. Do not reorder ancestor Group fragments during an edit unless the intended runtime behavior is also being changed.

## 4. Empty fragments are skipped

A `Group` or `Feature` may have an empty/whitespace local command fragment.

The composer skips empty fragments.

Therefore this is valid:

```xml
<Group Cpt="Draw settings">co=2;wt=1
    <Feature Cpt="Use inherited settings"></Feature>
</Group>
```

The Feature has no local command, but its effective source command is still inherited from the Group.

Do not automatically delete an empty Feature only because its local command is empty. It may be intentionally executable through inheritance, or intentionally present as UI structure.

## 5. Semicolons: authored separators vs. composition boundaries

Inside one local command fragment, authors use `;` to separate individual Bentley/application key-ins.

A hand-authored trailing semicolon is not required.

Separately, the MSet 2026 composer appends `;` after every contributing Group/Feature fragment. This means the **raw composed source** can temporarily contain repeated semicolons when an authored fragment already ends with `;`.

Example:

```text
Group fragment:   co=7;
Feature fragment: place line
Raw composition:  co=7;;place line;
```

This is not automatically an error. The next processing stage normalizes repeated semicolons.

### Current normalization relevant to composition

Before macro processing, MSet normalizes the compound text by:

- replacing line breaks/tabs with spaces,
- removing whitespace around `;`,
- reducing repeated semicolons to one,
- reducing repeated whitespace,
- trimming the whole string.

After later processing, the final compound command is split on `;` into individual dispatch steps.

Do not confuse the raw composed source with the final key-ins sent to Bentley.

## 6. `$C` - continue one command across a fragment boundary

`$C` suppresses the semicolon that MSet normally inserts immediately after the fragment containing `$C`.

Current processing is text-based:

1. composition has already appended the fragment delimiter,
2. normalization has already run,
3. `$C` is removed,
4. if the character immediately after `$C` is `;`, that semicolon is removed too.

This joins the current fragment with the next inherited fragment.

Example:

```xml
<Group Cpt="Text">place text $C
    <Feature Cpt="Above">above;Hello</Feature>
</Group>
```

Raw composition:

```text
place text $C;above;Hello;
```

After `$C` processing:

```text
place text above;Hello;
```

The first dispatched key-in can therefore become:

```text
place text above
```

### Important whitespace rule

Current MSet 2026 does **not** invent a space when `$C` is removed.

If the continued key-in needs a space between the two authored pieces, that space must be present in the text before `$C`, as in:

```text
place text $C
```

Do not rewrite it as `place text$C` unless concatenation without a space is intentionally required.

### Runtime-verified real-package pattern

`MSet_Polohopis` uses this pattern in Groups such as `Hotové texty`, where a Group starts `place text $C` and the selected child Feature completes the command with text-placement arguments/content.

## 7. `$X` - discard the accumulated command prefix

`$X` resets the already composed command prefix.

Current MSet 2026 behavior is precise:

- macro processing searches the fully composed/normalized string,
- the **last** `$X` occurrence wins,
- everything before that last `$X` is discarded,
- `$X` itself is removed,
- leading semicolons remaining after the reset are removed.

Example:

```xml
<Group Cpt="Inherited">lv=Roads;co=2;place smartline
    <Feature Cpt="Edit text">$X;edit text</Feature>
</Group>
```

Raw composition before macro processing:

```text
lv=Roads;co=2;place smartline;$X;edit text;
```

After `$X` processing:

```text
edit text;
```

The inherited Group prefix is intentionally gone.

### `$X` can appear in a Group

Because `$X` acts on the fully composed text, a Group can reset commands inherited from higher Groups while still allowing its descendant Groups/Features to contribute after the reset.

Schematic example:

```xml
<Group Cpt="Outer">lv=Outer
    <Group Cpt="Reset">$X;co=3
        <Feature Cpt="Draw">place line</Feature>
    </Group>
</Group>
```

Result after `$X` processing:

```text
co=3;place line;
```

### Runtime-verified real-package patterns

Current `MSet_Polohopis` contains real forms such as:

```text
$X;edit text
$X;active angle pt2
$Xizolované potrubie
```

The last form is also valid current behavior: `$X` is removed and the following text becomes the retained command/text tail.

## 8. `$C` and `$X` operate after ancestry composition

This order matters.

Conceptually, the relevant current pipeline is:

```text
Group ancestry + Feature
        |
        v
raw compound source
        |
        v
Normalize
        |
        v
Macro processing ($C, $X, and other macros)
        |
        v
later substitution rules
        |
        v
split on semicolons
        |
        v
final dispatch steps
```

Within the current macro rule, `$C` is processed before `$X`.

This module teaches `$C` and `$X` only. `$S(...)` and scale-sensitive substitutions belong to the next module.

## 9. Current contract-test evidence: `orná pôda`

The runtime-verified `MSet_Polohopis` package contains this structural path:

```text
Page "Kreslenie"
-> Group "100 Polohopis"
-> Group "101 Terénne tvary a kultúry"
-> Group "Značky"
-> Feature "orná pôda"
```

Relevant fragments are effectively:

```text
Group "100 Polohopis":                    co=bylevel;lc=bylevel;wt=bylevel;
Group "101 Terénne tvary a kultúry":     lv=101_Terén_a_kultúry
Group "Značky":                          aa=0;place cel rel
Feature "orná pôda":                     ac=3.019_
```

The current MSet 2026 parser/composer contract test expects the exact **raw effective source command**:

```text
co=bylevel;lc=bylevel;wt=bylevel;;lv=101_Terén_a_kultúry;aa=0;place cel rel;ac=3.019_;
```

The doubled `;;` is expected at this raw stage because the first fragment already ends in `;` and the composer appends another boundary delimiter. Normalization later reduces it.

The Page command is not present in this effective Feature command.

## 10. Editing rules for command composition

When modifying an MSet 2026 instruction:

- preserve Group ancestry order,
- do not copy `Instruction` or `Page` lifecycle commands into Feature inheritance,
- treat each Group/Feature command as a local fragment,
- preserve intentional empty fragments,
- use `;` between separate key-ins inside one fragment,
- do not treat a raw doubled semicolon as proof of an invalid package without considering composition/normalization,
- use `$C` only when one logical key-in must continue into a descendant fragment,
- preserve the whitespace required around a `$C` continuation,
- remember that `$X` discards the entire accumulated prefix before the last `$X`,
- trace entities/includes before editing a fragment that may be shared,
- do not invent or validate Bentley key-in semantics from composition rules alone.

## 11. What is deliberately not taught yet

Do not infer these from this module:

- `$S(...)` scale arithmetic,
- `Scales` runtime scale-factor calculation beyond structural rules from module 01,
- exact current scale-sensitive syntax for cells/text/terminators/line styles,
- Bentley/MicroStation/OpenRail/OpenRoads key-in validity,
- Annotation Scale behavior,
- historical `$M(...)` control-macro semantics as current MSet 2026 authoring guidance.

These belong to later modules/reference material.

## Completion check

Before proceeding to the next Instruction Author module, the model should be able to answer all of these correctly:

1. Are `Instruction` and `Page` commands inherited into a Feature? **No.**
2. What contributes to a Feature effective command? **Ancestor Groups from highest to nearest, then the Feature.**
3. Are empty local Group/Feature fragments allowed? **Yes.**
4. Does the composer append a delimiter after each contributing fragment? **Yes, `;`.**
5. Can raw composition temporarily contain `;;`? **Yes.**
6. What does `$C` do? **Removes itself and the immediately following composition separator so the command continues into the next fragment.**
7. Does `$C` automatically insert a space? **No.**
8. What does `$X` do? **Discards everything before the last `$X` in the composed command and retains the tail after it.**
9. Can `$X` in a Group reset commands inherited from higher Groups? **Yes.**
10. Does this module prove that an arbitrary Bentley key-in is valid? **No.**

Next planned module: `03-scale-and-substitutions.md`.
