vector-mirror 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,439 @@
1
+ /**
2
+ * claims.js — Claims-Register: die EINE Quelle der Führungs-Wahrheit
3
+ * (RELAIS-SPEC §0, Ein-Leib-Architektur internal design rule).
4
+ *
5
+ * Reiner Daten-Export, kein I/O, keine Logik-Importe. Aus diesem Register
6
+ * speisen sich (a) die VOLLSTÄNDIGEN Tool-Descriptions (tools.js konsumiert
7
+ * DESCRIPTIONS — Eigenheiten via EIGENHEITEN-Projektion, die übrigen 4 Blöcke
8
+ * via BLOCKS; tools.js trägt KEINEN Description-Freitext mehr, P2/S1b),
9
+ * (b) der instructions-Quickstart (server.js, via QUICKSTART-Projektion),
10
+ * (c) das Glossar (Teil des Quickstarts), (d) der Protokoll-Selftest
11
+ * (tests/relais_red/selftest_claims.mjs: S1 Wortidentität · S1b Vollstring-
12
+ * Pin Description==Register-Projektion · S2 Deckung==1.0 · S3 Wahrheit).
13
+ *
14
+ * Form je Claim (Spec §0): id · text (der exakte ausgelieferte Satz,
15
+ * wortidentisch) · targets (analyze|compare|bookmark|inspect|palette|
16
+ * arrange|constraints|status|selftest|instructions) · probe (Pfad relativ
17
+ * zum Projekt-Root ODER 'STATIC' für rein definitorische Sätze) · beleg
18
+ * (Empirie-Anker — Herkunfts-Spur, nicht der Beweis).
19
+ *
20
+ * Claim-IDs erscheinen NICHT im ausgelieferten Text (Ballast-Audit 23);
21
+ * der Selftest prüft Wortidentität per Substring.
22
+ *
23
+ * §5-VERDIKT (probe_mcp_k05.mjs, HEAD aa2ef1c): H1 Kanal-Schatten bestätigt —
24
+ * Prosa ✓ / structured ✗ für analyze UND inspect. C-ANA-E1 nennt daher die
25
+ * Kanal-Wahrheit explizit (Offenlegung NUR im Text-Kanal).
26
+ */
27
+
28
+ export const CLAIMS = [
29
+ // ── GLOSSAR (Spec §3, G1–G6) ──────────────────────────────────────────────
30
+ {
31
+ id: 'C-GLO-01',
32
+ text: 'scene.elements zeigt maximal 7 Elemente, suppressed zählt den Rest; Constraints auf verdeckte Elemente werden trotzdem geprüft; einen Nachlade-Parameter gibt es nicht.',
33
+ targets: ['analyze', 'instructions'],
34
+ probe: 'tests/relais_red/probe_cap_suppressed.mjs',
35
+ beleg: 'K-01/K-02, R9a #5/#8, DR-1 Probe A',
36
+ },
37
+ {
38
+ id: 'C-GLO-02',
39
+ text: 'canvas_validity=lossy heißt: der Sanitizer hat etwas entfernt oder ersetzt — auch render-neutrale Strips (etwa Kommentare) zählen; Verlust-Details stehen nur im Text-Kanal der Antwort.',
40
+ targets: ['inspect', 'instructions'],
41
+ probe: 'tests/relais_red/probe_lossy_textkanal.mjs',
42
+ beleg: 'K-06/K-24, R9a #5, §5-Verdikt H1',
43
+ },
44
+ {
45
+ id: 'C-GLO-03',
46
+ text: 'PARTIAL = unchecked-Constraints oder vom Cap verdeckte Warnungen (meta.truncated_warnings, nur bei Trunkierung); sichtbare Warnungen allein ergeben PASS.',
47
+ targets: ['analyze', 'instructions'],
48
+ probe: 'tests/relais_red/probe_partial_meta.mjs',
49
+ beleg: 'K-10 adjudiziert, K-26, N-4',
50
+ },
51
+ {
52
+ id: 'C-GLO-04',
53
+ text: 'analysisId und Bookmarks leben nur im laufenden Server-Prozess (in-memory) — Ein-Aufruf-Clients können compare/bookmark nicht nutzen.',
54
+ targets: ['analyze', 'compare', 'bookmark', 'instructions'],
55
+ probe: 'tests/relais_red/probe_mcp_session.mjs',
56
+ beleg: 'K-13a, R9a §8 Hürde 2',
57
+ },
58
+ {
59
+ id: 'C-GLO-05',
60
+ // §P7 (Opus): die Diagonale nicht verschweigen — der Abstand ist euklidisch
61
+ // über die AABB-Lücke (distance.js: sqrt(gapX²+gapY²) >= N*cellW).
62
+ text: 'DISTANCE-FROM N verlangt eine Lücke ≥ N Zellbreiten — Abstand euklidisch über die AABB-Lücke (sqrt aus gapX²+gapY², auch diagonal); Zellbreite = Canvas-Breite ÷ Grid-Spalten (Spalten: scene.grid).',
63
+ targets: ['instructions'],
64
+ probe: 'tests/relais_red/probe_einheiten_distance.mjs',
65
+ beleg: 'K-30 (3-Punkt-Formel), distance.js: sqrt(gapX²+gapY²) >= N*cellW',
66
+ },
67
+ {
68
+ id: 'C-GLO-06',
69
+ text: 'Farben erscheinen überall als W3C-Namen, nie als Hex; COLOR vergleicht Namen: #ff0000 besteht als red, #ff6347 nicht.',
70
+ targets: ['analyze', 'palette', 'instructions'],
71
+ probe: 'tests/relais_red/probe_farb_granularitaet.mjs',
72
+ beleg: 'K-07/K-08a, H9-P3-Pin',
73
+ },
74
+
75
+ // ── analyze / inspect (geteilte Sanitizer-Wahrheit, §5-Verdikt H1) ───────
76
+ {
77
+ id: 'C-ANA-E1',
78
+ text: 'Reservierte/kollidierende Autor-ids (etwa "title") ersetzt der Sanitizer durch Auto-IDs; die Original-id steht NUR im Text-Kanal — bei lossy immer auch content[0].text lesen.',
79
+ targets: ['analyze', 'inspect', 'instructions'],
80
+ probe: 'tests/relais_red/probe_mcp_k05.mjs',
81
+ beleg: 'K-05/H9-B1, R9a §4, §5-Verdikt H1 (HEAD aa2ef1c)',
82
+ },
83
+ {
84
+ // §P6 (Opus, MCP-Rand-Probe): analysisId ist KEIN Top-Level-Output-Key —
85
+ // er wohnt unter iteration.analysisId. Block 3 der analyze-Description ist
86
+ // damit Claim (Probe pinnt die echten Top-Level-Keys), nicht Freitext.
87
+ id: 'C-ANA-OUT',
88
+ text: 'Output: status PASS/FAIL/PARTIAL, corrections (fix), unchecked, diff; analysisId unter iteration.',
89
+ targets: ['analyze'],
90
+ probe: 'tests/relais_red/probe_partial_meta.mjs',
91
+ beleg: 'Opus P6 2026-06-11 (MCP-Rand), schema.js analyzeOutput Top-Level',
92
+ },
93
+
94
+ // ── compare ───────────────────────────────────────────────────────────────
95
+ {
96
+ id: 'C-CMP-ERR',
97
+ text: 'Ohne Baseline in diesem Prozess: isError:true und error {code: NO_BASELINE, hint} in structured, derselbe Hint im Text-Kanal — zuerst analyze ausführen.',
98
+ targets: ['compare'],
99
+ probe: 'tests/relais_red/probe_mcp_errorchannel.mjs',
100
+ beleg: 'R9a #13/#14, §6 Fehler-Kanal, K-13bc',
101
+ },
102
+ {
103
+ id: 'C-CMP-VOC',
104
+ text: 'Diff-Vokabular deutsch und endlich: VERSCHOBEN, FARBÄNDERUNG, FORMÄNDERUNG, NEU, ENTFERNT.',
105
+ targets: ['compare'],
106
+ probe: 'tests/relais_red/probe_compare_diff.mjs',
107
+ beleg: 'R9a #10, core/diff.js (5 Typen)',
108
+ },
109
+ {
110
+ id: 'C-CMP-GRAN',
111
+ text: 'Das Diff sieht Farben auf Namens-Ebene: Hex-Drift unterhalb der Namens-Grenze bleibt unsichtbar, Namens-Sprünge erscheinen als FARBÄNDERUNG.',
112
+ targets: ['compare'],
113
+ probe: 'tests/relais_red/probe_compare_diff.mjs',
114
+ beleg: 'K-07/K-12-Umfeld, opus_guided S12',
115
+ },
116
+
117
+ // ── bookmark ──────────────────────────────────────────────────────────────
118
+ {
119
+ id: 'C-BKM-ERR',
120
+ text: 'Unbekannte/verdrängte analysisId: isError:true und error {code: ANALYSIS_NOT_FOUND, hint}; maximal 10 Bookmarks, das älteste wird verdrängt (LRU).',
121
+ targets: ['bookmark'],
122
+ probe: 'tests/relais_red/probe_mcp_errorchannel.mjs',
123
+ beleg: '§6 Fehler-Kanal, pipeline.js MAX_BOOKMARKS=10',
124
+ },
125
+
126
+ // ── inspect ───────────────────────────────────────────────────────────────
127
+ {
128
+ id: 'C-INS-CAP',
129
+ text: 'Derselbe 7-Elemente-Cap wie analyze — inspect umgeht ihn nicht; suppressed zählt verdeckte Elemente.',
130
+ targets: ['inspect'],
131
+ probe: 'tests/relais_red/probe_cap_suppressed.mjs',
132
+ beleg: 'K-02 (teuerste R8-Fehlbehauptung), DR-1 Probe A',
133
+ },
134
+ {
135
+ id: 'C-INS-STRUCT',
136
+ text: 'structuredContent trägt nur scene (plus meta bei Trunkierung) — kein status, keine corrections; canvas_validity und suppressed stehen in scene.',
137
+ targets: ['inspect'],
138
+ probe: 'tests/relais_red/probe_cap_suppressed.mjs',
139
+ beleg: 'K-28',
140
+ },
141
+
142
+ // ── palette ───────────────────────────────────────────────────────────────
143
+ {
144
+ id: 'C-PAL-CAP',
145
+ text: 'Maximal 7 Einträge in colors, ohne Zähler — weitere Elemente nennt nur die Text-Zeile (N weitere).',
146
+ targets: ['palette'],
147
+ probe: 'tests/relais_red/probe_cap_suppressed.mjs',
148
+ beleg: 'R9a #6 (Probe-Pflicht eingelöst)',
149
+ },
150
+
151
+ // ── arrange ───────────────────────────────────────────────────────────────
152
+ {
153
+ id: 'C-ARR-SEQ',
154
+ text: 'Constraints wirken sequentiell — jede sieht das Ergebnis der vorigen, die Reihenfolge ändert das Layout.',
155
+ targets: ['arrange'],
156
+ probe: 'tests/relais_red/probe_arrange.mjs',
157
+ beleg: 'IST-Description (bleibt), pipeline.js arrange',
158
+ },
159
+ {
160
+ id: 'C-ARR-TYP',
161
+ text: 'FILL ist arrange-only (in analyze landet es als unchecked); COLOR hat hier keine Wirkung und wird ohne Warnung übersprungen.',
162
+ targets: ['arrange'],
163
+ probe: 'tests/relais_red/probe_arrange.mjs',
164
+ beleg: 'K-16, fill.js (check ⇒ pass:null), color.js (kein arrange)',
165
+ },
166
+ {
167
+ id: 'C-ARR-PROP',
168
+ text: 'Attribute sind Rechen-Vorschläge ohne Canvas-Wächter — auch Positionen außerhalb des Canvas kommen ohne Warnung zurück; mit analyze verifizieren.',
169
+ targets: ['arrange'],
170
+ probe: 'tests/relais_red/probe_arrange.mjs',
171
+ beleg: 'K-14-Analogie (Probe-Pflicht eingelöst)',
172
+ },
173
+ {
174
+ id: 'C-ARR-P5',
175
+ text: 'Liste unvollständig — nicht Umsetzbares landet als Klartext in warnings; arrange-fähige Typen zeigt vector_mirror_constraints (hasArrange).',
176
+ targets: ['arrange'],
177
+ probe: 'tests/relais_red/probe_arrange.mjs',
178
+ beleg: 'DR-1 P5, pipeline.js arrange warnings[]',
179
+ },
180
+
181
+ // ── constraints ───────────────────────────────────────────────────────────
182
+ {
183
+ id: 'C-CON-VOC',
184
+ text: 'Das Vokabular ist abschließend — was hier nicht steht, existiert nicht; RIGHT-OF/BELOW existieren nicht: LEFT-OF/ABOVE mit getauschten Operanden nutzen.',
185
+ targets: ['constraints'],
186
+ probe: 'tests/relais_red/probe_constraints_vokabular.mjs',
187
+ beleg: 'K-17, P6-Negativrand',
188
+ },
189
+ {
190
+ id: 'C-CON-UNK',
191
+ text: 'Unbekannte Typen werden nie geraten: analyze liefert unchecked mit reasonCode CONSTRAINT_TYPE_UNKNOWN und Hint, bei nahen Tippfehlern mit Korrektur-Vorschlag.',
192
+ targets: ['constraints'],
193
+ probe: 'tests/relais_red/probe_constraints_vokabular.mjs',
194
+ beleg: 'R9a #12 (Fehlerpfad A vorbildlich), arbitrate.js',
195
+ },
196
+
197
+ // ── status ────────────────────────────────────────────────────────────────
198
+ {
199
+ id: 'C-STA-CAL',
200
+ text: 'calibration=PENDING: der Auto-Selftest vom Serverstart läuft noch oder scheiterte — nicht defekt; der Browser startet lazy beim ersten Mess-Aufruf.',
201
+ targets: ['status'],
202
+ probe: 'tests/relais_red/probe_status.mjs',
203
+ beleg: 'server.js Fire-and-forget, pipeline.js markCalibrationPending',
204
+ },
205
+ {
206
+ id: 'C-STA-LAST',
207
+ text: 'lastAnalysis zeigt Baseline-Existenz nur für diesen Prozess.',
208
+ targets: ['status'],
209
+ probe: 'tests/relais_red/probe_status.mjs',
210
+ beleg: 'K-13a',
211
+ },
212
+
213
+ // ── selftest ──────────────────────────────────────────────────────────────
214
+ {
215
+ id: 'C-SEL-ANTI',
216
+ text: 'Misst die 5 Eichkörper gegen spec-abgeleitete expected-Werte, nie gegen gespeicherten eigenen Output — Anti-Zirkularität als Vertrauensanker.',
217
+ targets: ['selftest'],
218
+ probe: 'tests/relais_red/probe_selftest_antizirk.mjs',
219
+ beleg: 'R9a #11, REGEL-2, pipeline.js __checkEk (PARTIAL-Match)',
220
+ },
221
+
222
+ // ── P5-Zeilen (Spec §1.3 — Unvollständigkeits-Ehrlichkeit) ───────────────
223
+ {
224
+ id: 'C-P5-MESS',
225
+ text: 'Liste unvollständig — bei Unerwartetem canvas_validity prüfen, Verlust-Details im Text-Kanal lesen; Glossar: Server-Quickstart.',
226
+ targets: ['analyze', 'compare', 'inspect', 'palette'],
227
+ probe: 'STATIC',
228
+ beleg: 'DR-1 P5 (rein definitorischer Diagnoseweg)',
229
+ },
230
+ {
231
+ id: 'C-P5-STATE',
232
+ text: 'Liste unvollständig — Session-Begriffe (analysisId, Bookmarks) erklärt das Glossar im Server-Quickstart.',
233
+ targets: ['bookmark'],
234
+ probe: 'STATIC',
235
+ beleg: 'DR-1 P5 (rein definitorischer Diagnoseweg)',
236
+ },
237
+ {
238
+ id: 'C-P5-META',
239
+ text: 'Liste unvollständig — Feld-Bedeutungen erklärt das Glossar im Server-Quickstart; bei selftest-FAIL nennt failures die exakte Spec-Abweichung je Eichkörper.',
240
+ targets: ['status', 'selftest'],
241
+ probe: 'STATIC',
242
+ beleg: 'DR-1 P5 + IST-Description selftest (bleibt)',
243
+ },
244
+ {
245
+ // §P3 (Codex): constraints trug als einziges Tool keine P5-Zeile —
246
+ // Spec-§1.3-Wortlaut; der Verhaltens-Teil (unbekannter Typ ⇒ unchecked
247
+ // mit reasonCode+Hint) ist probe-gedeckt (keine STATIC-Quote-Belastung).
248
+ id: 'C-P5-VOC',
249
+ text: 'Liste unvollständig — unbekannter Typ ⇒ unchecked mit reasonCode + Hint; vollständiges Vokabular: vector_mirror_constraints.',
250
+ targets: ['constraints'],
251
+ probe: 'tests/relais_red/probe_constraints_vokabular.mjs',
252
+ beleg: 'DR-1 P5, Spec §1.3, R9a #12 (Fehlerpfad A)',
253
+ },
254
+
255
+ // ── Quickstart (Spec §4) ──────────────────────────────────────────────────
256
+ {
257
+ id: 'C-QS-ORI',
258
+ text: 'Vector Mirror ist ein deterministisches SVG-Mess-Auge: es rendert headless, misst Geometrie und Farben und prüft räumliche Constraints — es liefert nie ein Bild zurück (kein Render-Tool) und erfindet keine Werte.',
259
+ targets: ['instructions'],
260
+ probe: 'tests/relais_red/probe_mcp_instructions.mjs',
261
+ beleg: 'VISION, R9a §3 (Render-Beweis fehlt = P6-Negativrand)',
262
+ },
263
+ {
264
+ id: 'C-QS-WORKFLOW',
265
+ text: 'vector_mirror_inspect (Layout sehen) → vector_mirror_constraints (Vokabular) → vector_mirror_analyze (prüfen) → Fixes laut corrections → analyze mit previousIssueCount bis PASS; Regressionen: vector_mirror_bookmark → vector_mirror_compare; Vertrauen: vector_mirror_selftest.',
266
+ targets: ['instructions'],
267
+ probe: 'tests/relais_red/probe_mcp_instructions.mjs',
268
+ beleg: 'R9a §2 (Workflow-Kette rekonstruierbar), §6 Entwurf',
269
+ },
270
+ {
271
+ id: 'C-QS-GRAMMAR',
272
+ text: 'Constraint-Grammatik: "#subject TYP #reference [wert]" — Beispiel: "#logo CENTERED-IN #frame"; vollständige Typen-Liste: vector_mirror_constraints.',
273
+ targets: ['instructions'],
274
+ probe: 'tests/relais_red/probe_constraints_vokabular.mjs',
275
+ beleg: 'R9a #2/#4 (Grammatik erstklassig dokumentiert)',
276
+ },
277
+ {
278
+ id: 'C-QS-STOP',
279
+ text: 'Fertig = status PASS und corrections == [] und unchecked == [] und canvas_validity == valid; PARTIAL akzeptieren ist eine dokumentierte Entscheidung, kein Default; canvas_validity lossy: verstanden+akzeptiert ist eine dokumentierte Entscheidung (Verlust-Detail im Text-Kanal prüfen), kein automatisches Unfertig.',
280
+ targets: ['instructions'],
281
+ probe: 'STATIC',
282
+ beleg: 'DR-1 P8 + maintainer rule A2 (K-06-Policy offen)',
283
+ },
284
+ ];
285
+
286
+ // ── Hilfs-Index ──────────────────────────────────────────────────────────────
287
+ const byId = new Map(CLAIMS.map((c) => [c.id, c]));
288
+
289
+ /** Liefert den exakten Claim-Text (wirft bei unbekannter id — Projektions-
290
+ * Fehler sollen laut beim Import knallen, nie still leere Blöcke bauen). */
291
+ function t(id) {
292
+ const c = byId.get(id);
293
+ if (!c) throw new Error(`claims.js: unbekannte Claim-id '${id}'`);
294
+ return c.text;
295
+ }
296
+
297
+ // ── PROJEKTION 1: Eigenheiten-Blöcke je Tool (Spec §1.1 Block 4) ────────────
298
+ // Reihung = P7 Erstkontakt-Salienz (Spec §1.2); Separator ' | ' ist die
299
+ // S2-Splitgrenze (Claim-Texte enthalten kein '|'); letzte Position = P5-Zeile.
300
+ const ORDER = {
301
+ // Salienz-Auswahl (Spec §1.1: ≤6 + P5; Rest trägt der Quickstart): C-GLO-05
302
+ // (Einheiten) lebt im Quickstart-Stolperstein, nicht im analyze-Block —
303
+ // das 1300-Zeichen-Budget erzwingt die Auswahl, das Register bleibt voll.
304
+ analyze: [
305
+ 'C-ANA-E1',
306
+ 'C-GLO-01',
307
+ 'C-GLO-03',
308
+ 'C-GLO-06',
309
+ 'C-GLO-04',
310
+ 'C-P5-MESS',
311
+ ],
312
+ compare: ['C-GLO-04', 'C-CMP-ERR', 'C-CMP-VOC', 'C-CMP-GRAN', 'C-P5-MESS'],
313
+ bookmark: ['C-GLO-04', 'C-BKM-ERR', 'C-P5-STATE'],
314
+ inspect: ['C-ANA-E1', 'C-INS-CAP', 'C-INS-STRUCT', 'C-GLO-02', 'C-P5-MESS'],
315
+ palette: ['C-GLO-06', 'C-PAL-CAP', 'C-P5-MESS'],
316
+ arrange: ['C-ARR-SEQ', 'C-ARR-TYP', 'C-ARR-PROP', 'C-ARR-P5'],
317
+ constraints: ['C-CON-VOC', 'C-CON-UNK', 'C-P5-VOC'],
318
+ status: ['C-STA-CAL', 'C-STA-LAST', 'C-P5-META'],
319
+ selftest: ['C-SEL-ANTI', 'C-P5-META'],
320
+ };
321
+
322
+ export const EIGENHEITEN_MARKER = 'Eigenheiten (verifiziert): ';
323
+
324
+ export const EIGENHEITEN = Object.fromEntries(
325
+ Object.entries(ORDER).map(([tool, ids]) => [
326
+ tool,
327
+ EIGENHEITEN_MARKER + ids.map(t).join(' | '),
328
+ ]),
329
+ );
330
+
331
+ // ── PROJEKTION 1b: vollständige Descriptions (Spec §1.1, P2/S1b Ein-Leib) ───
332
+ // Die NICHT-Eigenheiten-Blöcke (1 Orientierung · 2 Input-Grammatik ·
333
+ // 3 Output-Kernfelder · 5 Next step) wohnen HIER im Register — tools.js
334
+ // konsumiert nur noch DESCRIPTIONS und trägt keinen Freitext mehr. Jede
335
+ // Freitext-Mutation außerhalb des Registers macht der Selftest S1b rot
336
+ // (Wortidentitäts-Pin Auslieferung == Register-Projektion). Block 3 von
337
+ // analyze IST ein Claim (C-ANA-OUT, probe-gepinnt — P6: analysisId wohnt
338
+ // unter iteration, nicht top-level).
339
+ const BLOCKS = {
340
+ analyze: {
341
+ orientierung:
342
+ 'Analyzes an SVG against spatial constraints, returns a Spotter-Report.',
343
+ input:
344
+ 'Input: SVG + Constraints "#subject TYPE #reference [value]", z.B. "#logo CENTERED-IN #frame"; Typen: vector_mirror_constraints; previousIssueCount → Konvergenz.',
345
+ output: t('C-ANA-OUT'),
346
+ next: 'Next step: fix per corrections, then analyze until PASS.',
347
+ },
348
+ compare: {
349
+ orientierung:
350
+ 'Compares an SVG with a stored baseline and reports what changed.',
351
+ input:
352
+ 'Input: SVG + analysisId (UUID aus analyze) ODER Bookmark-Name; optionale constraints für Re-Check.',
353
+ output: 'Output: analyzeOutput-Form mit diff.',
354
+ next: 'Next step: review diff, adjust SVG, then analyze or compare again.',
355
+ },
356
+ bookmark: {
357
+ orientierung:
358
+ 'Saves a previous analyze result as a named baseline for the Sniper-Loop: pin a state, edit the SVG, then compare against the name instead of the UUID.',
359
+ input: 'Input: name (kein UUID-Format) + analysisId (UUID aus analyze).',
360
+ output: 'Output: name, analysisId, stored, bookmarkCount.',
361
+ next: 'Next step: compare(svg, [], name) against this baseline.',
362
+ },
363
+ inspect: {
364
+ orientierung:
365
+ 'Inspects an SVG and returns element positions, sizes, colors and grid mapping without checking constraints.',
366
+ input: 'Input: SVG string.',
367
+ output:
368
+ 'Output: scene mit id, tag, Grid-Zelle (Ortssprache, z.B. C4), color je Element.',
369
+ next: 'Next step: define constraints based on the layout, then call analyze.',
370
+ },
371
+ palette: {
372
+ orientierung:
373
+ 'Extracts fill and stroke colors from all SVG elements — review the color scheme before applying COLOR constraints.',
374
+ input: 'Input: SVG string.',
375
+ output: 'Output: colors [{id, fill, stroke}].',
376
+ next: 'Next step: use COLOR constraints in analyze to enforce specific colors.',
377
+ },
378
+ arrange: {
379
+ orientierung:
380
+ 'Computes SVG attributes (x, y, width, height, cx, cy) from canvas dimensions, element definitions, and spatial constraints — layout from scratch, no browser.',
381
+ input:
382
+ 'Input: canvas {width, height}, elements [{id, tag, r?, width?, height?, content?}], constraints (string[]).',
383
+ output:
384
+ 'Output: attributes per element (ready to apply to SVG) + warnings.',
385
+ next: 'Next step: use the returned attributes to construct or update the SVG, then call analyze to verify.',
386
+ },
387
+ constraints: {
388
+ orientierung:
389
+ 'Lists all available constraint types with their syntax and capabilities.',
390
+ input: 'Input: none.',
391
+ output: 'Output: types [{type, syntax, hasArrange}].',
392
+ next: 'Next step: use the constraint syntax in vector_mirror_analyze.',
393
+ },
394
+ status: {
395
+ orientierung: 'Returns Vector Mirror server health.',
396
+ input: 'Input: none.',
397
+ output:
398
+ 'Output: version, browser (running/stopped), lastAnalysis, constraintTypes, breaker, calibration.',
399
+ next: 'Next step: if browser is stopped, any analyze/inspect/palette call will auto-start it.',
400
+ },
401
+ selftest: {
402
+ orientierung:
403
+ 'Runs the 5 calibration fixtures (EK-1 color, EK-2 grid, EK-3 constraint, EK-4 3D-suppression, EK-5 frozen animation) and verifies Vector Mirror against the spec-derived truth.',
404
+ input:
405
+ 'Input: optional full (boolean) — adds an N=10 mini determinism check.',
406
+ output: 'Output: status (PASS/FAIL), calibrated, total, failures.',
407
+ next: 'Next step: PASS = trust the measurements; FAIL = fix per failures, then re-run.',
408
+ },
409
+ };
410
+
411
+ /** Die EINE komponierte Auslieferungs-Form je Tool (5-Block-Reihenfolge,
412
+ * Budget je Description ≤1300 Zeichen — S1b wacht numerisch). */
413
+ export const DESCRIPTIONS = Object.fromEntries(
414
+ Object.entries(BLOCKS).map(([tool, b]) => [
415
+ tool,
416
+ `${b.orientierung} ${b.input} ${b.output} ${EIGENHEITEN[tool]} ${b.next}`,
417
+ ]),
418
+ );
419
+
420
+ // ── PROJEKTION 2: instructions-Quickstart (Spec §4, ≤2500 Z. / ≤35 Zeilen) ──
421
+ // Vollständig aus dem Register projiziert; G4–G6 erscheinen als Stolperstein-
422
+ // Zeilen (eine Wahrheit, ein Ort — die Glossar-Zeile verweist statt zu kopieren).
423
+ export const QUICKSTART = [
424
+ 'VECTOR MIRROR — QUICKSTART',
425
+ t('C-QS-ORI'),
426
+ `WORKFLOW: ${t('C-QS-WORKFLOW')}`,
427
+ `GRAMMATIK: ${t('C-QS-GRAMMAR')}`,
428
+ 'STOLPERSTEINE (verifiziert):',
429
+ `- ${t('C-ANA-E1')}`,
430
+ `- ${t('C-GLO-06')}`,
431
+ `- ${t('C-GLO-04')}`,
432
+ `- ${t('C-GLO-05')}`,
433
+ 'GLOSSAR:',
434
+ `- suppressed: ${t('C-GLO-01')}`,
435
+ `- canvas_validity: ${t('C-GLO-02')}`,
436
+ `- PARTIAL: ${t('C-GLO-03')}`,
437
+ '- analysisId/Bookmarks, Farb-Granularität, Einheiten: siehe Stolpersteine 3, 2, 4.',
438
+ `STOP-CONDITION: ${t('C-QS-STOP')}`,
439
+ ].join('\n');