Repository navigation
An object whose text dictionary holds its properties beside its class is saved as read, in every class - #145
Merged
Merged
Conversation
… beside its class as it was read
A text dictionary can hold an object's properties beside its class, with
no _elements: {"_array_class": "Simulink.Signal", "DataType": "single",
...}. MATLAB never writes this shape. #136 made a Parameter, the buses and
the enumeration type save it as it was read, refuse every edit but a
rename, and refuse its XML. The same shape in a Signal (and an
mpt.Signal), AliasType, NumericType, LookupTable, ValueType, Breakpoint or
ConfigSet did not throw, but:
- every save, and a copy of the entry, wrote a made-up
"_elements": [{"_properties": {...}}] beside the properties as read,
holding what the node overrides (an AliasType's BaseType "", a
ConfigSet's Name), so an untouched save of the file was not the file;
- an edit (Description, Min, BaseType, Storage Class, ...) was accepted
and saved into that made-up element;
- the table and the Property Inspector offered editors for it.
The made-up element came from DataNode._serializeSimulinkObject, the text
writer of SimulinkObjectNode and SignalNode, so the fix is there and
reaches every class it serves. That includes the variant classes,
ConfigSetRef, VariantConfigurationData and CustomObject, which had the
same defect. This follows group F's ruling for SER-TE, option (a), as
agenda follow-up 2 extends it:
- _serializeSimulinkObject returns the value as it was read when
DataNode._inlineObjectBag() is true.
- SimulinkObjectNode gains a setProperty that asks _refuseInlineBagEdit
first. So do the overrides that answer before it: SignalNode,
ValueTypeNode, LookupTableNode, BreakpointNode, VariantControlNode,
VariantBankNode and VariantBankCoderInfoNode. Every edit but a rename
is therefore refused with #136's message. That includes a LookupTable's
or a Breakpoint's Description, which got MATLAB's "Unrecognized
property" before.
- SimulinkObjectNode and SignalNode offer no editor for any property but
the name (getPropInfo through _inlineBagPropInfo, valueEditable,
descriptionEditable).
- The XML refusal (#136) is unchanged.
Not changed: an unregistered class (ObjectNode) already saves this shape
as read. It still accepts a Description edit and drops it, as any
childless object does. That is F2-4's ObjectNode half, which is still the
maintainer's call.
Tests: test/inlineObjectBag.test.ts gains a block with its own synthetic
dictionary (sparse_text.sldd plus one entry per class; no corpus file),
53 cases. An untouched save is byte-identical, and no entry offers an
editor but its name. For each class: the copy is the value as read; a
rename saves under the new name with the value as read; every edit tried
is refused with the message, and the save is unchanged. All 53 fail
before the change: a made-up _elements, an edit accepted (or refused in
other words), an editor offered. The existing cases are unchanged. One
comment above the existing InlineSignal case said a Signal's text save
"is left as it was", and now points to the new block.
The previous commit made every SimulinkObjectNode and SignalNode class save an object holding its properties beside its class as it was read, refuse every edit but a rename, and offer no editor but its name. Its tests used only the spelling with no _elements key. The other spelling, _elements: null, which a hand edit can leave, is the same shape: DataNode._inlineObjectBag covers it, and #136's NullElements case pins it for a Parameter. No test held it for these classes, so narrowing any of the four new guards to "_elements is undefined" left the whole suite green while the old behaviour came back for the null spelling: - DataNode._serializeSimulinkObject: an untouched save wrote a made-up element over the null (a Signal's and a CustomObject's [{"_properties":{}}], an AliasType's {"BaseType":""}, a VariantControl's {"Value":""}); - SimulinkObjectNode.valueEditable: a VariantControl offered a Value editor; - SimulinkObjectNode.descriptionEditable and SignalNode.descriptionEditable: an AliasType and a Signal offered a Description editor. test/inlineObjectBag.test.ts adds four _elements: null entries to the other classes' synthetic dictionary: a Signal, an AliasType, a VariantControl and a CustomObject. Each runs the block's existing cases (copy, rename, refused edits), and the whole-file cases (an untouched save is the bytes read; no editor but the name) now cover them too. That is 12 new cases. With src at 71378b5 all 12 fail: the copy and the rename carry the made-up element in place of the null, and the Description edit is accepted (or, for the VariantControl, refused in other words). Each of the four narrowed guards fails at least one of them. No src change, and dist is unchanged.
…emselves ValueType, VariantBank, VariantBankCoderInfo, Breakpoint and LookupTable ask _refuseInlineBagEdit in their own setProperty, ahead of SimulinkObjectNode's. No test spelled their inline bag as `_elements: null`, so each of those call sites could be narrowed to skip that spelling with the suite still green. For a ValueType the edit was then accepted and dropped on save; for the other four it was refused with the wrong message (the encoded-stream text, or "Unrecognized property"). Add an `_elements: null` entry for each of the five to OTHER_CASES, with the edits its `_elements`-less twin already makes. That is 15 new cases. With src at 71378b5 all 15 fail: copy and rename write a made-up element over the null, the ValueType Description edit is accepted, and the other four refuse it in other words. Each narrowed call site now fails its own class's refused-edit case. No src change; dist is unchanged.
This was referenced Oct 18, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One item in three commits on main
71378b5:4415e5a(the fix), thencdb3442and9cc2373(tests only, for the_elements: nullspelling), and a merge of main (6ae067a: the 1.41.0 bump and #146, no conflicts).G2-INLINEBAG: the inline property bag in the other Simulink object classes
Ruling. The agenda's follow-ups from group F's reviews, item 2:
The maintainer answered "2. yes, yes" (group G, 2026-10-18). Items 1-4 are built under the rulings they already fall under. For this item that is group F's SER-TE ruling, option (a): "when
_elementsis absent, ... replayserial._rawVal". Theme 1 adds: "a save the writer cannot spell is refused rather than written wrong."What was wrong. Take an entry
{"_array_class":"Simulink.Signal","_array_type":"object","DataType":"single","Description":"d"}, with no_elements. It opens with every property at its default, and that part is unchanged. But then:"_elements":[{"_properties":{...}}]beside the keys as read, so an untouched save differed from the file. AliasType addedBaseType:""and ConfigSet addedName.This applied to the seven classes named, to mpt.Signal, and to every class that shares the writer: VariantExpression, VariantControl, VariantVariable, VariantBank, VariantBankCoderInfo, ConfigSetRef, VariantConfigurationData/VariantConfigurations and CustomObject. The XML save was already refused (#136).
Root cause.
DataNode._serializeSimulinkObject(src/datamodel/node/DataNode.ts) always wroteresult._elements = [element]with the merged overrides. It is the text writer ofSimulinkObjectNode.serializeValueandSignalNode.serializeValue, and those are its only two callers.DataNode._refuseInlineBagEdit, soDataNode.setPropertyaccepted the edit.getPropInfo,valueEditableanddescriptionEditablenever asked_inlineObjectBag.Fix.
_serializeSimulinkObjectreturns{...rawVal}when_inlineObjectBag(). This is one change at the root, so it covers every class above.setProperty:_refuseInlineBagEdit ?? super, like BaseBusNode and EnumTypeNode, without their_isUnchangedCommitcheck, which cannot pass here (it needsgetPropInfo().editable, which is false for every property of an inline bag but Name);getPropInfo, through_inlineBagPropInfo;valueEditableanddescriptionEditable, which are false for an inline bag._refuseInlineBagEdittoo:descriptionEditableandgetPropInfo, as ParameterNode has.MATLAB truth. Not needed. MATLAB never writes this shape, and option (a) is already the ruling.
Tests.
test/inlineObjectBag.test.tsgains a block of 80 cases (53 in4415e5a, 27 for the_elements: nullspelling in the two review commits; 17 classes in 26 entries). It runs on its own synthetic dictionary,sparse_text.slddwith one inline-bag entry appended per class (17 classes). No corpus file is used.getPropInfo().editable,valueEditable,descriptionEditableandrow._descriptionEditableare all false.ingest,serializeandsetPropertypaths:71378b5):_elements;Existing tests. No existing test assertion changed. One comment above the InlineSignal case said a Signal's text save "is left as it was". It now points to the new block.
Left out, and why.
Namekey is saved as read, with its old text. No reader reads that key, and this is option (a) as ruled.SlddNode.parse, which other work shares.A behaviour change, inline shape only. These edits were refused before, each with its own reason, and now get the inline-bag message, in both spellings: LookupTable's and Breakpoint's Description (was "Unrecognized property"); VariantControl's Description; VariantBank's Description, BankName and Value; VariantBankCoderInfo's Description, HeaderFile, DefinitionFile and Value. The element form is unchanged.
vscode. No change is needed; the pin bump brings this in.
SetPropertyResultrefusal, which vscode already shows.Gates at
4415e5a(superseded; see the gates at the head below)rm -rf dist && npm run buildleaves the tree clean, and dist is in the commit.npm run verify(typecheck, build, smoke, test, check:pack, check:leak, check:browser): rc 0. 288 test files passed and 1 skipped; 9835 tests passed and 27 skipped.DEX_READBACKS_CORPUS=<corpus>/parity npx vitest run test/parity/readbacks.truth.test.ts: 6 of 6 passed.DEX_MATLAB_CMD="mw -using Bmain matlab": the livetest/parity/matlab/writeback.live.test.tspassed 32 of 32, and the offlinetest/valueTypeValueProps.test.ts(it namesDEX_MATLAB_CMDonly in a comment) passed 36 of 36; 68 in all, rc 0. Only repo fixtures were opened.Review rounds: the
_elements: nullspelling (cdb3442,9cc2373)_inlineObjectBagtreats_elements: nullthe same as no_elements, and #136's NullElements case pins that for a Parameter. In4415e5aevery new case spelled the shape without the key, so the null spelling was unpinned at each guard:cdb3442adds NullBagSignal, NullBagAliasType, NullBagVariantControl and NullBagCustomObject (12 cases). It pins four guards:_serializeSimulinkObject(narrowed, it fails 30 cases), SONvalueEditable, and SON's and SignalNode'sdescriptionEditable(1 each). With4415e5a's test file, all four narrowings pass the whole suite.9cc2373adds NullBagValueType (Min, Max), NullBagVariantBank, NullBagVariantBankCoderInfo, NullBagBreakpoint and NullBagLookupTable (15 cases). These five classes ask_refuseInlineBagEditin their ownsetProperty, ahead of SimulinkObjectNode's. Withcdb3442's file, a call site narrowed to skip the null spelling still passed. For a ValueType the review found the full suite green (9847): Min/Max was accepted, then dropped on save, and the entry's lastmod was restamped. In the other four the edit was refused with the wrong message. Now each narrowed call site fails its own class's refused-edit case, and 114 of 115 pass. The same holds for SignalNode and VariantControlNode.71378b5), all 27 null cases fail:[{"_properties":{}}], holdingBaseType: ""for an AliasType andValue: ""for a VariantControl.Gates at the head (
6ae067a)6ae067amerges mainb8d7b59(the 1.41.0 bump and A complex value with a -0 imaginary part shows +0i, and cell literals take signs and imaginary-first members as MATLAB does #146) with no conflicts; dist rebuilt from the merged src leaves the tree clean.npm run verify: rc 0. 290 test files passed and 1 skipped; 10,045 tests passed and 27 skipped (main's 9,965 plus this PR's 80). Readbacks withDEX_READBACKS_CORPUSset: 6 of 6.9cc2373, before the merge: verify 9,862 passed and 27 skipped; CI all green.writeback.live(32/32) andfidelitySmoke(2/2) pass. vscodemain(202dc3f) with this core passes verify (3,476) and integration (228 passing).No existing assertion changed in any of the three commits.
Implements the maintainer's 2026-10-18 rulings (group G).