synthesisui 0.16.354 → 0.16.355

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.
@@ -185,6 +185,7 @@ declared) {
185
185
  seenFiles: new Set(),
186
186
  withTheirTokens: 0,
187
187
  formTally: new Map(),
188
+ distinctTexts: new Set(),
188
189
  };
189
190
  group.uses += 1;
190
191
  group.seenFiles.add(f.file);
@@ -218,30 +219,57 @@ declared) {
218
219
  /**
219
220
  * SÓ O QUE UM LEITOR ALCANÇA, E SÓ TEXTO DISTINTO - as duas restrições vieram de medir.
220
221
  *
221
- * `value-not-read` diz que a forma FOI lida e o valor está fora das escalas deles - texto não
222
- * ensina nada a leitor nenhum. `computed` é montado em runtime e não existe na fonte.
223
- * `component-not-admitted` é o portão, não a leitura. Sobram os dois de `A_READER_REACHES`.
222
+ * SOBRA O QUE `A_READER_REACHES` NOMEIA, e o que ele nomeia mudou duas vezes - este comentário
223
+ * ficou parado na primeira. Ele dizia *"`value-not-read` … texto não ensina nada a leitor
224
+ * nenhum … `component-not-admitted` é o portão, não a leitura. Sobram os DOIS"*, e os dois
225
+ * excluídos ali entraram no conjunto depois (11/08 e 24/08), somando quatro. Quem lesse isto
226
+ * concluiria que o maior grupo de todos - 96% do volume não interpretado - não carrega texto,
227
+ * quando ele carrega. O conjunto é a fonte única; esta frase não repete os nomes de propósito.
228
+ *
229
+ * `computed` continua fora, e por uma razão que não envelhece: é montado em runtime e não
230
+ * existe na fonte, então não há texto para guardar.
224
231
  *
225
232
  * E TEXTO DISTINTO, porque a primeira versão disto reprovou no spec do repo vivo: guardar todo
226
233
  * fragmento deu 723 215 bytes no dashboard dele, contra um teto de 65 536. Oito mil cópias da
227
234
  * mesma string não ensinam mais que uma - o que um leitor precisa é da variedade de FORMAS.
228
235
  *
229
- * O TETO SUBIU PARA 4096 EM 24/08, e o número saiu de uma medição e não de um palpite: a
230
- * variedade real do `frontend-hub` é de ~1 500 textos distintos sobre 10 825 usos, então 4096
231
- * cabe a população inteira daquele repositório com folga e continua sendo um teto de verdade
232
- * para um caso patológico.
236
+ * O TETO SUBIU PARA 4096 EM 24/08 sobre uma medição que EXTRAPOLOU: *"a variedade real do
237
+ * `frontend-hub` é de ~1 500 textos distintos sobre 10 825 usos"*, contada nos 400 primeiros
238
+ * arquivos de module. Remedida em 03/09 no repositório inteiro, com o teto solto, ela é 6 394 -
239
+ * quatro vezes o estimado. O teto corta, e corta a maior parte:
240
+ *
241
+ * web-subscribe css/component-not-admitted 9 722 distintos, 4 096 viajam
242
+ * web-subscribe css/shape-not-read 8 016 distintos, 4 096 viajam
243
+ * frontend-hub/dashboard css/component-not-admitted 6 394 distintos, 4 096 viajam
233
244
  *
234
- * `uses` continua contando tudo, então a diferença entre o contado e o que viajou permanece
235
- * visível em vez de silenciosa - e é ela que a tela mostra quando o teto corta.
245
+ * A FRASE QUE ESTAVA AQUI DIZIA QUE ISSO ERA VISÍVEL: *"`uses` continua contando tudo, então a
246
+ * diferença entre o contado e o que viajou permanece visível em vez de silenciosa"*. Não é.
247
+ * `uses` conta ocorrências e `unreadable` guarda distintos, então aquela diferença existe
248
+ * sempre, por repetição, e não muda de forma quando o teto entra. Quem paga é a
249
+ * re-interpretação, que roda sobre o censo guardado prometendo alcançar quem já importou sem
250
+ * re-medir: ela processa 4 096 de 9 722 e relata sucesso.
251
+ *
252
+ * QUEM DECLARA O CORTE AGORA É `distinct`, escrito na linha de baixo e sempre presente. ESTE
253
+ * NÚMERO NÃO É O CONSERTO DO TETO - subir 4096 é uma decisão de tamanho de censo, medida e
254
+ * entregue à parte. Declarar vem primeiro; ampliar vem depois, e as duas são separadas porque
255
+ * uma é honestidade e a outra é custo.
236
256
  */
237
- if (A_READER_REACHES.has(reason) &&
238
- group.unreadable.length < DISTINCT_CAP &&
239
- !group.unreadable.some((u) => u.text === f.text))
240
- group.unreadable.push({
241
- file: f.file,
242
- line: f.line,
243
- text: f.text.replace(/\s+/g, " ").trim().slice(0, 400),
244
- });
257
+ if (A_READER_REACHES.has(reason) && !group.distinctTexts.has(f.text)) {
258
+ /**
259
+ * CONTAR VEM ANTES DE CABER, e essa ordem é a correção inteira.
260
+ *
261
+ * O texto entra no conjunto mesmo quando o teto já fechou: é assim que `distinct` sabe
262
+ * dizer 9 722 enquanto `unreadable` carrega 4 096, e é a única diferença entre um teto
263
+ * declarado e um teto silencioso. Inverter as duas linhas devolve o defeito.
264
+ */
265
+ group.distinctTexts.add(f.text);
266
+ if (group.unreadable.length < DISTINCT_CAP)
267
+ group.unreadable.push({
268
+ file: f.file,
269
+ line: f.line,
270
+ text: f.text.replace(/\s+/g, " ").trim().slice(0, 400),
271
+ });
272
+ }
245
273
  groups.set(key, group);
246
274
  }
247
275
  return {
@@ -250,18 +278,36 @@ declared) {
250
278
  counted,
251
279
  interpreted,
252
280
  unread: [...groups.values()]
253
- .map(({ seenFiles, withTheirTokens, formTally, ...group }) => ({
281
+ .map(({ seenFiles, withTheirTokens, formTally, distinctTexts, ...group }) => ({
254
282
  ...group,
255
283
  files: seenFiles.size,
284
+ /**
285
+ * QUANTOS TEXTOS DISTINTOS EXISTEM - incondicional, e é isso que o torna legível.
286
+ *
287
+ * Os outros campos deste objeto somem quando são zero, porque um zero repetido em todo
288
+ * grupo é ruído. Este não pode: quem lê precisa separar "o censo mediu e deu zero" de "o
289
+ * censo é anterior a este campo", e um campo que desaparece funde os dois casos. O tipo o
290
+ * declara opcional pela segunda razão, nunca pela primeira.
291
+ */
292
+ distinct: distinctTexts.size,
256
293
  /** Ausente quando é zero: um campo zerado em todo grupo é ruído em cada relatório. */
257
- ...(withTheirTokens && withTheirTokens > 0 ? { withTheirTokens } : {}),
294
+ ...(withTheirTokens && withTheirTokens > 0
295
+ ? { withTheirTokens }
296
+ : {}),
258
297
  /**
259
298
  * AS FORMAS DESTE GRUPO, com os usos de cada uma - ver `form-identity.ts` (item 12).
260
- * Ordenadas por uso: a primeira é a pergunta que mais vale a pena fazer. O teto corta o
261
- * patológico, e `uses` do grupo continua contando tudo - o corte fica visível.
299
+ * Ordenadas por uso: a primeira é a pergunta que mais vale a pena fazer.
300
+ *
301
+ * `formsTotal` existe pela MESMA razão que `distinct`, e o comentário que estava aqui
302
+ * afirmava o contrário: *"o teto corta o patológico, e `uses` do grupo continua contando
303
+ * tudo - o corte fica visível"*. `uses` conta OCORRÊNCIAS e o teto corta FORMAS, então
304
+ * `uses` alto convive com qualquer número de formas e não denuncia corte nenhum. Medido em
305
+ * 03/09: cinco grupos em três populações relatam exatamente 64 formas, que é o teto - e
306
+ * nenhum deles diz quantas ficaram de fora.
262
307
  */
263
308
  ...(formTally.size > 0
264
309
  ? {
310
+ formsTotal: formTally.size,
265
311
  forms: [...formTally.entries()]
266
312
  .sort((a, b) => b[1] - a[1])
267
313
  .slice(0, FORM_CAP)
@@ -328,6 +374,22 @@ values) {
328
374
  ? ` — and ${g.withTheirTokens} of them already wear a token you declare, so their value is in the system`
329
375
  : "";
330
376
  lines.push(` ${g.uses} ${g.shape}${g.uses === 1 ? "" : "s"} in ${g.files} file${g.files === 1 ? "" : "s"} - ${g.because}${theirs}`);
377
+ /**
378
+ * A TERCEIRA FRASE, QUANDO O TETO CORTOU - e ela existe para não deixar o cliente descobrir
379
+ * sozinho (lei 8: lacuna declarada é confiança, lacuna calada é bug).
380
+ *
381
+ * Ela só aparece quando corta, ao contrário do campo `distinct`, e a assimetria é de propósito:
382
+ * um campo ausente no censo é ambíguo para quem lê JSON e precisa do valor incondicional; uma
383
+ * linha a mais em TODO grupo de um relatório de 108 linhas é ruído que treina a pessoa a rolar
384
+ * sem ler (dono, 09/08).
385
+ *
386
+ * O QUE ELA NÃO FAZ é prometer o desfecho - mesma correção que `shape-not-read` recebeu em
387
+ * 24/08. Ela diz quantos textos viajam e o que isso significa para um leitor que a gente
388
+ * publique depois; para onde vai o resto depende de uma decisão de tamanho de censo que não é
389
+ * do cliente e ainda não foi tomada.
390
+ */
391
+ if (g.distinct !== undefined && g.distinct > g.unreadable.length)
392
+ lines.push(` of ${g.distinct} distinct texts here, ${g.unreadable.length} travel with the census - a reader we publish later reaches those without you re-measuring, and the remaining ${g.distinct - g.unreadable.length} need this scan run again`);
331
393
  for (const e of g.examples)
332
394
  lines.push(` ${e.file}:${e.line} ${e.text.slice(0, 80)}`);
333
395
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synthesisui",
3
- "version": "0.16.354",
3
+ "version": "0.16.355",
4
4
  "description": "Bring SynthesisUI design systems into any project - tokens, typed components, whole pages and an agent-ready CLAUDE.md manifest.",
5
5
  "type": "module",
6
6
  "bin": {