fix: Task 3 review round 1 - strip control chars before the sanitizer (S32a), S34 minors

Control characters now go on the raw value in AttrWriter::cleanNode and
VariableRef::setting; after the sanitizer only rejection remains ('<' + VT/FF
no longer turns into a tag). VALUE_KEY anchored with D, exact column-width
fractions, nested rows in columns, specialty columns refused, fullwidth by
catalog category, preset ambiguity in DesignSystem::modulePresetId().

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 14:26:18 +02:00
co-authored by Claude Opus 5.5
parent 4b72c2bb42
commit 8688a02402
13 changed files with 278 additions and 104 deletions
@@ -28,6 +28,18 @@ final class StructureRulesTest extends TestCase
'anything in a specialty section' => [$section('specialty'), 'divi/row', 'Spezialabschnitte'],
'column in a row' => [Block::create('divi/row'), 'divi/column', 'Spalten entstehen mit der Zeile'],
'module in a column' => [Block::create('divi/column'), 'divi/button', null],
'row in a column (nestable)' => [Block::create('divi/column'), 'divi/row', null],
'row in a group' => [Block::create('divi/group'), 'divi/row', 'passt nicht'],
'module in a specialty column' => [
Block::create('divi/column', ['module' => ['advanced' => ['specialtyColumns' => ['desktop' => ['value' => '2']]]]]),
'divi/text',
'Spezial',
],
'module in a column holding inner rows' => [
Block::create('divi/column', [], [Block::create('divi/row-inner')]),
'divi/text',
'Spezial',
],
'group in a column' => [Block::create('divi/column'), 'divi/group', null],
'module in a group' => [Block::create('divi/group'), 'divi/text', null],
'fullwidth module in a column' => [Block::create('divi/column'), 'divi/fullwidth-header', 'passt nicht'],