Repository navigation
Damaged MAT input warns and shows what was read, instead of shifting values, overflowing the stack or opening as editable text - #126
Merged
Conversation
… decoded, not shifted
MATLAB writes every field of every element of a struct array as a matrix, so
a slot that is anything else only comes from a damaged file. The reader
stepped over such a slot and left no hole in that field's list, so the
elements after it moved up one in that field and not in the others: in a 1x3
whose element 2's a is not a matrix, element 3's a showed as element 2's, and
the file said only that two elements were read.
Such an array is now recorded as not decoded, as one whose field names lie
past its end already is: it shows as <1x3 struct, not decoded>, with no rows
and no editor, and a .mat says why ("s" was not decoded: element 2's field a
is not a matrix (a data element of type 9).). The file still opens, and every
other variable in it reads as before.
Two cases keep today's reading. A field tag cut by the end of the bytes is a
cut, so the elements before it are kept and the file says how many of the
declared elements could be read. A 1x1 struct with such a slot only leaves
that field out, since nothing can shift there; that is still pinned by "skips
a field slot whose element is not a matrix".
dist is rebuilt from src.
… not a refused file
The MAT reader recursed into every struct field and cell element with no
bound but the call stack. A 1x1 cell nested about 1,600 deep (a 77 KB file)
threw "Maximum call stack size exceeded" out of parseMat, so the whole .mat
was refused, the variables beside it included. A dictionary value or a model
workspace holding such a value failed to decode as a whole: a text
dictionary showed the entry as its cdata text (<1x320033 char>), and the
model's Model Workspace section came up empty. Where the stack ran out moved
with the engine and the stack size.
The reader now reads 128 levels (MAX_NESTING, the number dex-core uses). The
value at level 129 is read as far as its class, size and name, and is
recorded as not decoded: "nested more than 128 levels deep, so it was not
read". It keeps the bytes it was read from, as every value the reader does
not decode does, and nothing under it is read. The rest of the file reads as
before. A .mat says which value it stopped at ("deep{1}...{1}" was not
decoded: ...). A model workspace says nothing, per the C-232 ruling. An
untouched dictionary save writes the value back byte for byte.
The deepest variable in the corpus is 6 levels, so no real file reads
differently. In a model workspace the workspace struct is itself level 1, so
a variable there is read to its own level 127.
dist is rebuilt from src.
…ecoded, and a .mat says why A numeric or logical MAT value whose bytes end after its name, before its real part's tag, declares elements and holds none. MATLAB writes no such value, so only a damaged file holds one. The reader leaves its value null, which means no payload was there at all. The node layer took that null for the value: a 1x1 showed null, a 2x3 [null], a 1x1 logical false, and each offered an editor for a value nothing read. A complex one did the same, since #116 built it as the real one cut at the same point. Nothing said so. The maintainer's ruling of 2026-10-16 (group E, theme 1: warn and show what was read) makes it what every value the reader did not decode already is. It is one row, <2x3 double, not decoded>, with no editor and no element rows: its class (logical for a logical) and its size are what was read. This holds in a .mat, in a struct field or a cell element, in a model workspace, and in a text or binary dictionary value. A .mat file now says why: "x" declares 6 element(s) and holds no data, so its value was not read. A model workspace stays silent, as the C-232 ruling says. When the record holding the value is the one the file cuts short, the record's own "read short" warning already names it, so that one loss is reported once. Change: MatlabVariableNode._createFromMatNumeric builds the not-decoded node for a null value that declares at least one element, of any class the reader models. It spells the placeholder with MatParser's undecodedValue, now exported from the module (not from the barrel). MatParser.collectUndecoded adds the warning, and parseMat passes it the variables a record warning already names. The parser's own reading (value null) is unchanged, as matParser.test.ts pins it. A class the reader does not model ('unknown') is left as it was. That is the CLASS-255 item, and lifting the exclusion fails the two dictionary tests that pin it. An empty value (0x0) with no payload is still [ ]. Test: test/matNoPayload.test.ts, 7 cases, written first. Before the fix, 6 failed. The rows showed null, [null] or false, editable, in a .mat, a struct field, a cell element, a cut record, a synthetic model workspace, #116's 31 cut windows of complex_ws.slx's z, and a text and a binary dictionary value. The 7th, the parser's null, passes before and after. With the node change alone, the 2 warning cases failed with no warning. Mutants of the node arm's and the warning's > 0 bound, and dropping the dedupe, are each caught. No existing test changed. dist is rebuilt from src.
…xt is display-only C-014, under the maintainer's group E ruling of 2026-10-16 on damaged input: warn and show what was read, never refuse the file. parseCdata already showed a cdata value whose stream does not decode as the char of its six-bit text, and an untouched save already wrote the text back. But it said nothing, where a binary dictionary's hex of the same damaged bytes warns, and the char took edits, where every other value a text dictionary holds as a MAT stream is display-only (the C-012 ruling of 2026-10-15). An edit would have saved what was typed in place of the stream. parseCdata's two failure arms (a stream decodeMatStream refuses, and a throw from the node builders) now go through _createUndecodableCdata. It records the failure through the per-entry harvest a hex value's failure already uses (EncodedValue.recordDecodeFailure, which SlddNode.parse collects around each entry), so no second warnings channel is added. It also marks the char _readFromStream, so the char is display-only. Its reason is the clause the hex path uses: decodeMatStream's reason, or "its MAT stream did not decode (...)". recordDecodeFailure now also takes how the value is shown. The default is "not decoded", the hex placeholder's wording, so the hex message is unchanged. The cdata passes "its encoded text": "c" holds a value stored encoded that could not be read, because its MAT stream did not decode (...); it is shown as its encoded text and saved unchanged. The write-back is unchanged: _rawInput is still replayed, and an untouched save is byte for byte the file read. New test/cdataDecodeFailure.test.ts, 10 cases, built from MATLAB's own streams in sparse_text.sldd and nd_text.sldd: - An overwritten flags word in a cell element or a whole entry gives one part-unreadable warning for that entry. The value is the char of its text, display-only, and its entry can still be renamed. The JSON element beside it stays editable, and the untouched save is byte-identical. - matStreamSites' two refused preambles, endian mark and reserved word, warn with that reason when the dictionary is opened. - Guards: a hex value's message is unchanged. A damaged stream parsed outside an open is not reported against the next open. None of the 23 intact text dictionaries in test/fixtures (99 streams) warns. Six of these failed before the change, because there was no warning and the value took edits. No existing test changed. dist rebuilt (rm -rf dist && npm run build).
…d, and its file opens A model-workspace or .mat variable whose array-flags word is overwritten names a class the reader does not model (255, say, or 18), so MatParser reads it as class 'unknown' with no value. The flags byte can still say complex, and then the node builders read .re of its null value. The throw refused the whole file: a model whose workspace part held one variable like that (0xFFFFFFFF over complex_ws.slx's z, for example), and a .mat holding one, at the top or inside a cell or a struct. #116 left this open, since it is damage and not a cut. The maintainer's group E ruling of 2026-10-16 puts this item under theme 1: warn and show what was read, never refuse the file and never crash. It takes the item's recommendation and catches the failure per variable. The variable is shown as what was read of it: its name, its class and its size, as one row, <1x2 unknown, not decoded>, with no editor and no rows. A binary dictionary already shows the same bytes that way. The rest of the file opens as it would have. ModelSectionNode.addWorkspaceEntry catches a builder throw and adds the not-decoded row. It does not warn: the C-232 ruling says a model workspace does not report a value it did not decode. MatNode.fromParsed does the same for each variable of a .mat. A .mat says why once. MatParser already warns about a value of a class it does not model, wherever it stands ("z", "c{1}", "s.a"), so a variable that warning names, or names a piece of, gets no second warning. A variable nothing names, for example in a host's own parse handed to addMatSourceParsed, gets one: "z" could not be read (...), so it is shown as not decoded. MatlabVariableNode.createNotDecoded builds the row. The no-data arm that C-068 added now uses it too, with no change in behaviour. Left as it was: _createFromMatNumeric's 'unknown' exclusion. Lifting it fails the two dictionary tests that pin a damaged stream as not decoded, with a warning. Also unchanged: a real (not complex) value of an unmodelled class still opens as null, editable, class unknown. That is a display question, not a refusal. Test: test/unmodelledClassVariable.test.ts, 18 cases, written first. Before the fix, all 18 failed, each on the TypeError "Cannot read properties of null (reading 're')". The cases are: - complex_ws.slx z, cases.slx cplxScalar and cplxVec, and sparse_ws.slx dComplex, each with its flags word (found by parsing) set to 0xFFFFFFFF, 0x000008FF and 0x00000812. Each is a not-decoded row. Every other workspace row and every other section equals the intact file's, and there are no warnings. - A synthetic workspace with the damaged value inside a cell and a struct. - A .mat with each of the three words. The only warning is the reader's own. - A .mat with the damaged value nested in a cell and a struct. The only warnings are the c{1} and s.a ones. - A host's parse with no warning for the variable. It gets one. Mutants of the dedupe are each caught: an exact-name match only, a bare prefix match, no dedupe, and no fallback warning. No existing test changed. dist is rebuilt from src.
…ictionary formats C-210, under the maintainer's group E ruling of 2026-10-16 on damaged input: warn and show what was read, never refuse the file. A dictionary's System Composer catalog lists each definition with the type that models it, and that type is the only thing that tells a struct type from a data interface (both are a Simulink.Bus). A definition whose record lost its type was recorded as the empty string and its entry took its Kind from its class, so a struct type read as a Data Interface. Nothing said so, in either the text or the binary format. test/slddNode.test.ts pinned that silence. What was read is still shown: the definition is still listed with an empty type, and the Kind is still the class's. What is new is one part-unreadable warning for each such definition, naming it: The System Composer definition "StructType" has no type, so its Kind is taken from its Simulink class and may be wrong (a struct type reads as a Data Interface). The warning is raised in one place, SlddNode.parse, right after the catalog is read, and it covers both formats. The binary reader hands its catalog over on __scCatalog, and the text reader's comes from _parseSystemComposer. So the same damage says the same thing however the dictionary was saved. ScCatalog.untypedDefinitions lists the names: own keys of either bag whose type is empty or not a string, interfaces first, each once. The text reader now records a type that is not a string (a number, say) as the empty string, as it records a missing one. Before, it kept the number in the catalog as it was. Unchanged: an absent or empty catalog stays silent (the MATLAB-measured note in ScCatalog.ts), a nameless record is still skipped, and a type that is there but not one the reader maps stays silent too, since it may be a newer release's. No real dictionary is expected to warn: the scoping measured 0 typeless definitions of 29,200, in the 10 catalog-bearing dictionaries among 225 .sldd files. Tests, written first: - test/slddNode.test.ts: the existing test for a lost type now expects two part-unreadable warnings, for DataInterface and StructType, in place of none. That is the one existing assertion changed, because it pinned exactly the silence the ruling removes. Its Kind and empty-type assertions are kept. New: a type that is a number is recorded as '' and warns once. Controls: an unmapped type string, and the pristine arch.sldd, give no warnings. - test/scCatalog.test.ts: arch_binary.sldd with the StructDataType type attribute cut from StructType's definition tag (the cut is asserted to land once) warns once, part StructType. StructType's Kind is Data Interface and every other Kind is as in the intact file. The same cut in its text twin, arch_binary_as_text.sldd, gives an equal warning list, an equal catalog and equal Kinds. Control: both intact forms give no warnings. Before the change, the 4 new or changed warning tests failed on their assertions (0 warnings, and 42 kept in the catalog), and the 3 controls passed. Mutants: dropping the text reader's string check, scanning only modeledDataTypes, warning for one format only (either way round), and warning on any unmapped type each fail at least one of them. dist rebuilt from clean (rm -rf dist && npm run build).
This was referenced Oct 16, 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.
Implements the maintainer's 2026-10-16 group E ruling.
This PR covers six theme 1 items from the backlog, one commit each. The ruling for theme 1 (damaged input) says: "warn and show what was read; never refuse the file and never crash." The maintainer agreed each item's recommendation ("Agree your suggestions ... Add unit tests to lock down the fix."). Each recommendation is quoted below.
All six follow the same pattern. A damaged value is shown as a
<RxC class, not decoded>row with no editor and no child rows, and the rest of the file reads as before:.matfile warns withpart-unreadable, through the existingcollectUndecoded/parsed.warningspath.#122's warnings sink (
recordPartialDecode) is for values that decoded in part, so no item here uses it, and no second sink is added.src/index.tsis unchanged. Every test was written first, and each one runs the real reader or session. Each commit includes its own rebuiltdist/, andnpm run verifywas green at each commit.Gate
f4150a9):rm -rf dist && npm run buildleaves the tree clean.npm run verifyreturns rc 0. Test files: 246 passed / 1 skipped. Tests: 8131 passed / 26 skipped, 53 of them new. The smoke, pack, leak and browser checks pass. CI's dist step (rm -rf dist, build, porcelain on dist) prints nothing.641fca9): main has taken LookupTable, Breakpoint, VariantBank and Signal properties follow MATLAB #124 and addEntry refuses a name MATLAB cannot use, and a paste of an mpt entry MATLAB already wrote is admitted #125 since this branch was cut fromc3dee1a. No file is changed on both sides, andgit merge-treereports no conflict. In the merged tree, the committeddist/is byte-identical to a fresh build. Verify there: 250 files / 8246 passed / 26 skipped, with typecheck, smoke, pack, leak and browser all OK.C-069: a struct array field slot that is not a matrix (
c5850a7)Recommendation: "(a): only damaged files reach it, it reuses the arm's existing damaged-struct refusal, and it keeps the change inside parseMatrix." Option (a) is: "Record the whole struct array as undecoded ('element k's field f is not a matrix'), as pastItsEnd does."
What was wrong: in a
.matstruct array, if one element's field slot held a data element that is not a matrix, the slot was skipped and left no gap. That field's later values moved onto earlier elements, with no warning. Example: in a 1x3 array, element 3'sa(5) was shown as element 2's.Root cause:
parseMatrix's struct-array field loop only adds a value when the slot isMI_MATRIX, then steps past the slot. So the field's list gets shorter, andstructElementsHeldsizes the rows to the longest list.Fix (
MatParser.ts): a new branch in that loop. If the array has more than one element and the slot's tag is complete, the whole array is recorded as not decoded, with the reasonelement K's field F is not a matrix (a data element of type T). This matches the existingpastItsEndbranch. A 1x1 struct, and a tag cut short by the end of the bytes, are read as before. The node layer already builds the not-decoded row.Tests:
matParser.test.ts"records a struct ARRAY with a field slot that is not a matrix as not decoded, and shifts no element onto another". It covers a 1x3 with a miDOUBLE slot (checking the exact variable, the exact warning, and that the next variable is unchanged), a miINT32 slot in a 2x2, and the nested pathst.fandc{2}.valuewas null, there was noundecoded, and the field lists werea:[1,5],b:[2,4,6].matStructArray.test.tsruns the same case throughcreateSession().addMatSource. The row is now<1x3 struct, not decoded>with 0 rows, and there is exactly one warning.<1x3 struct>with 3 rows.Existing tests changed: none.
Left out: a 1x1 struct with a non-matrix slot still drops that field silently. Nothing can shift in that case, and the existing test pins it. This could be a follow-up. dex-core's G75 ports the old shift.
C-231: nesting with no depth limit (
00e209f)Recommendation: "(a), with a cap well under the measured ~1,200-level ceiling and checked against the node layer's own recursion depth." Option (a) is: "Thread a depth through parseMatrix. Past a cap, record the subtree as undecoded with a reason, which collectUndecoded already reports, and keep the rest of the file."
What was wrong: a value nested about 1,500 levels deep made the whole open fail with
RangeError: Maximum call stack size exceeded. In a model workspace the section came out empty, and in a text dictionary the entry showed as<1x320033 char>.Root cause:
parseMatrixrecurses into struct fields and cell elements with no limit, and the record walk does not catch the error.Fix (
MatParser.ts):MAX_NESTING = 128. It is exported from the module only, not from the package. 128 is dex-core's cap.parseMatrix(..., depth = 0). The struct-field and cell-element calls passdepth + 1.nested more than 128 levels deep, so it was not read. The value's bytes are kept.mcosTypedNode.ts, the comment that said "a struct nested a few thousand deep is a legal file" is corrected.Tests (new
test/matNesting.test.ts, 9 cases; chains are built byte by byte): all 9 failed before, each for the reason given here.double 7.addMatSource, every row down to level 129 is present, and the last one is not decoded and not editable.toRowandserializeValuedo not throw. Before: RangeError.decodeMatStream, a text dictionary (sparse_text.slddentry c) and a binary one (sparse_binary.slddentry c) open to the cap, and an untouched save writes the value back unchanged. Before:ok:false/<1x320033 char>.cases.slx, synthetic workspace): both variables are shown, with no warning. Before: the section was empty.depth + 1by 5, and dropping the struct one by 4.Existing tests changed: none.
Left out:
unknown. It should follow this reader.C-068: a numeric value whose bytes end before its data (
7c9b670)Recommendation: "(b), ruled together with the agenda's 'Short values in the node layer' bullet." Option (b) is: "The node layer builds a not-decoded node (_createUndecoded with a reason such as 'its payload is missing') whenever a numeric variable declares elements and has value null, real or complex."
What was wrong: a numeric variable (real, complex, logical or integer) that declares elements but whose bytes end before its data was shown as
null/[null], editable, with no warning. Before #116, the complex case threw and lost the whole file. #116 stopped the throw by building the value as a real one.Root cause: the parser keeps
value: nullwith noundecodedmark, and its tests pin that. Neither_createFromMatNumericnorcollectUndecodedhandled this case.Fix:
MatlabVariableNode._createFromMatNumericbuilds the not-decoded node when the value is null, more than 0 elements are declared, and the class is notunknown. A model whose workspace part is cut short opens even when the cut lands in a complex variable #116's guard is kept for 0 elements or negative dims.MatParser: a newholdsNoDatacheck gives"P" declares N element(s) and holds no data, so its value was not read.A variable already named by a "read short" warning is skipped, so a cut record warns once.value: nullis unchanged.Tests (new
test/matNoPayload.test.ts, 7 cases):<RxC cls, not decoded>, read-only with 0 rows. A 0x0 variable still shows[ ]. There are exactly 6 warnings.s.aandc{1}cases.complex_ws.slxz at all 31 lengths of A model whose workspace part is cut short opens even when the cut lands in a complex variable #116's window.Before the fix, 6 of the 7 failed on the row (
null,[null], editable). With only the node half applied, cases 1 and 2 still failed becausewarningswas undefined, so the warning half fails for its own reason too. Mutation checks: dropping the dedupe fails only case 3.>= 0in either bound fails case 1. Dropping theunknownexclusion fails exactly the two dictionary tests that pin a damaged class-unknownstream, so the exclusion stays.Existing tests changed: none.
Left out:
null..slxmodelworkspace.matpath passes on parseMat's warnings, so there this value warns. That path already warns for every other undecoded reason.C-014: a text dictionary's MAT stream that does not decode (
f8719f2)Recommendation: "(c). It mirrors the existing reportUndecoded harvest and needs no change to the NodeClassType interface. Use a dedicated flag rather than _undecoded, so the char node's write-back is unchanged."
What was wrong: when a text dictionary's cdata failed to decode, it was shown as an ordinary char holding the encoded text. It was editable and raised no warning.
Root cause: a silent
catch (_e)inMatlabVariableNode.parseCdata.NodeClassType.parsehas no warnings channel.Fix:
_undecodedis not used.recordDecodeFailure/takeDecodeFailures, drained bySlddNode.parsefor each entry). Option (c)'s "post-build walk" would have been a second harvest in the same loop. Both arms ofparseCdatanow record the reason withshownAs = 'its encoded text', then build the same char as before._readFromStream = true, which is the dedicated flag, so it is display-only under the C-012 ruling._rawInputis replayed.MatlabVariable.mddocuments this.Message:
"c" holds a value stored encoded that could not be read, because its MAT stream did not decode (...); it is shown as its encoded text and saved unchanged.Tests (new
test/cdataDecodeFailure.test.ts, 10 cases):sparse_text.slddc{1}gives exactly one warning, and every other entry is as in the intact file.c{1}is display-only andsetProperty('Value')refuses it, whilec{2}stays editable.nd_text.slddA) warns and is display-only.Before the fix, 6 failed (
warningsundefined,valueEditabletrue) and the 4 guards passed. Mutation checks: no record call fails 5 tests, no display-only flag fails 4, and hard-coding "not decoded" fails 5.Existing tests changed: none.
Left out:
The class-255 workspace variable: a flags word that is overwritten (
7091bba)Recommendation (agenda, group C): "(a) catch it per variable and leave that variable out, as #114 does for a struct array with no element read (the reviewer's suggestion: catch in
addWorkspaceEntry) ... Recommendation: (a), which matches the ruling's 'no refusal'."What was wrong: a variable whose flags word was overwritten (for example with
0xFFFFFFFFovercomplex_ws.slx's z) threwTypeError: Cannot read properties of null (reading 're'). That refused the whole model, or the whole.mat.Root cause: the class is
unknownwith the complex bit set. That reaches_createFromMatNumeric's complex branch with a null value, and C-068's branch deliberately excludesunknown.Fix:
ModelSectionNode.addWorkspaceEntry(no warning, per C-232) and inMatNode.fromParsed.MatNode.fromParsedwarns"z" could not be read (<reason>), so it is shown as not decoded.It skips that warning when an existing warning already names the variable or a part of it (z,z.,z(,z{).MatlabVariableNode.createNotDecodedbuilds the row, and C-068's branch now uses it.One departure from the recommendation: the caught variable is not left out. It is shown as a
<1x1 unknown, not decoded>row that keeps its bytes. That follows the theme 1 ruling's "show what was read", and it matches how a dictionary already shows a damaged class-unknownstream.Tests (new
test/unmodelledClassVariable.test.ts, 18 cases):complex_ws.slxz,cases.slxcplxScalar and cplxVec,sparse_ws.slxdComplex), each with its parsed flags word (asserted to be class 6, complex) set to 3 values. Every other row and section equals the intact file's, with no warnings..matfiles, where the only warning is the reader's own..matcases, which give exactly one warning per element.zzwarning, which catches a bare prefix match.Before the fix, all 18 failed on the TypeError and none on an assertion. Mutation checks: an exact-name-only match fails only case 17, a bare prefix match only case 18, no dedupe cases 14-17, and no fallback warning only case 18.
Existing tests changed: none. The two dictionary tests that pin a damaged class-
unknownstream pass unchanged.Left out:
null, classunknown. That is a display question, not a refusal.c, not onlyc{1}), as in the binary dictionary.C-210: a System Composer definition with no type (
f4150a9)Recommendation: "(b), at low priority. A present-but-typeless record is damage, not absence, and the test's own comment calls the result 'a wrong answer that looks exactly like a right one'." Option (b) is: "Warn part-unreadable, naming the definition, from both the text and the binary catalog reader."
What was wrong: if a catalog definition lost its
type, a StructType was shown as a Data Interface (its Simulink class), with no warning.Root cause: both readers recorded a missing type as
''and stayed silent:SlddNode._parseSystemComposerfor text, andScCatalog.scanScXmlfor binary.Fix:
ScCatalog.untypedDefinitions(catalog).SlddNode.parseadds onepart-unreadableper untyped definition, at the one place both formats pass through:The System Composer definition "X" has no type, so its Kind is taken from its Simulink class and may be wrong (a struct type reads as a Data Interface).''.Tests:
slddNode.test.ts, new: a numeric type is recorded as''with one warning. Controls: aFutureTypestring gives no warning, and pristinearch.slddgives none.scCatalog.test.ts, new:arch_binary.sldd's tag, which gives exactly one warning for StructType.arch_binary_as_text.slddgives an identical warning list, catalog and Kinds.Existing test changed:
slddNode.test.ts"degrades a definition whose record lost its type to the entry's raw Simulink class". Itsexpect(warnings).toEqual([])now expects twopart-unreadablewarnings, namingDataInterfaceandStructType. The test pinned exactly the silence this ruling removes; its own comment said "pinned rather than fixed". Its Kind and''assertions are kept, and its comment and the file header are reworded.Left out: the corpus was not re-measured. The scope found 0 untyped definitions out of 29,200 at
8e33408, and string types are read as before. vscode needs no change, since it shows warnings in the generic banner.