@pipelex/mthds-form 0.29.0 → 0.31.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.
@@ -1,13 +1,14 @@
1
1
  import * as _json_render_core from '@json-render/core';
2
2
  import { Spec, StateStore, StateModel } from '@json-render/core';
3
+ export { Spec, StateModel, StateStore, createStateStore } from '@json-render/core';
3
4
  import * as zod from 'zod';
4
5
  import { z } from 'zod';
5
6
  import { RunField } from '../core/descriptor.js';
7
+ import { d as AppStyleId, B as BrandManifest } from '../styles-BoXPBjF4.js';
8
+ export { o as brandManifestSchema } from '../styles-BoXPBjF4.js';
6
9
  import * as react from 'react';
7
10
  import * as _json_render_react from '@json-render/react';
8
11
  import { Components, Renderer } from '@json-render/react';
9
- import { B as BrandManifest } from '../manifest-DUeAWeqa.js';
10
- export { b as brandManifestSchema } from '../manifest-DUeAWeqa.js';
11
12
  import * as zod_v4_core from 'zod/v4/core';
12
13
  import { F as FieldEnv } from '../field-renderer-Dz03dpig.js';
13
14
  export { seedInputs } from '../core/seed.js';
@@ -16,6 +17,38 @@ import 'mthds/protocol';
16
17
  import '../core/file-formats.js';
17
18
  import '../core/sources.js';
18
19
 
20
+ /**
21
+ * The frames a layout is written for, and the vocabulary each adds.
22
+ *
23
+ * `page` is a whole product page of its own, the frame every layout had
24
+ * before a host drew one around it. `composer` and `result` are the two
25
+ * moments of a host's compose-then-result app: the inputs before a run, in a
26
+ * centred column whose host draws the band above it and the action row's
27
+ * mechanics, and the result after one, under the host's bar restating the
28
+ * request. The two moments carry their own components, found by measuring the
29
+ * designer against hand-drawn screens of three methods: the composer's frame
30
+ * (`Composer`, with the page's h1, the panel and the host's action row) and a
31
+ * group of inputs inside it, and a result's header, a proportion bar, colour
32
+ * swatches, a picture, a fact, a labelled detail, a date in words and a list
33
+ * of short texts. A date range, chips for a list of texts and compact rows
34
+ * for a list of structures were found too, and went to the kernel's own
35
+ * controls instead, since they improve the plain form as much as a designed
36
+ * one: a composer delegates those inputs to `MthdsField`.
37
+ *
38
+ * Zod only, importable from node: `designerCatalog()` renders these into the
39
+ * data the designer method takes. Each description says what the component IS
40
+ * and how it renders, never where a page must put it.
41
+ */
42
+ /** The frame a layout is written for: a whole product page, or one of the two moments of a host's compose-then-result app. */
43
+ declare const FRAMES: readonly ["page", "composer", "result"];
44
+ type Frame = (typeof FRAMES)[number];
45
+ /** The components the composer frame adds to the catalog. */
46
+ declare const COMPOSER_COMPONENTS: readonly ["Composer", "FieldGroup"];
47
+ /** The components the result frame adds to the catalog. */
48
+ declare const RESULT_COMPONENTS: readonly ["ResultHeader", "ProportionBar", "Swatches", "Picture", "Fact", "Detail", "DateText", "TextList"];
49
+ /** Every component a frame adds, which the `page` frame's vocabulary leaves out. */
50
+ declare const FRAME_COMPONENTS: readonly ["Composer", "FieldGroup", "ResultHeader", "ProportionBar", "Swatches", "Picture", "Fact", "Detail", "DateText", "TextList"];
51
+
19
52
  /**
20
53
  * Whether a spec is one this catalog can render - the check every source
21
54
  * passes, whoever wrote it.
@@ -178,6 +211,184 @@ declare const catalog: _json_render_core.Catalog<{
178
211
  }>;
179
212
  }, {
180
213
  components: {
214
+ Composer: {
215
+ props: z.ZodObject<{
216
+ headline: z.ZodString;
217
+ lede: z.ZodNullable<z.ZodString>;
218
+ runLabel: z.ZodString;
219
+ columns: z.ZodNullable<z.ZodEnum<{
220
+ 1: "1";
221
+ 2: "2";
222
+ }>>;
223
+ notes: z.ZodNullable<z.ZodArray<z.ZodString>>;
224
+ }, z.core.$strip>;
225
+ slots: string[];
226
+ events: string[];
227
+ description: string;
228
+ example: {
229
+ headline: string;
230
+ lede: string;
231
+ runLabel: string;
232
+ columns: string;
233
+ };
234
+ };
235
+ FieldGroup: {
236
+ props: z.ZodObject<{
237
+ title: z.ZodNullable<z.ZodString>;
238
+ }, z.core.$strip>;
239
+ slots: string[];
240
+ description: string;
241
+ example: {
242
+ title: string;
243
+ };
244
+ };
245
+ ResultHeader: {
246
+ props: z.ZodObject<{
247
+ eyebrow: z.ZodNullable<z.ZodString>;
248
+ title: z.ZodString;
249
+ subtitle: z.ZodNullable<z.ZodString>;
250
+ }, z.core.$strip>;
251
+ slots: never[];
252
+ description: string;
253
+ example: {
254
+ eyebrow: string;
255
+ title: {
256
+ $state: string;
257
+ };
258
+ subtitle: {
259
+ $template: string;
260
+ };
261
+ };
262
+ };
263
+ ProportionBar: {
264
+ props: z.ZodObject<{
265
+ label: z.ZodString;
266
+ total: z.ZodNullable<z.ZodNumber>;
267
+ of: z.ZodNullable<z.ZodNumber>;
268
+ unit: z.ZodNullable<z.ZodString>;
269
+ items: z.ZodNullable<z.ZodArray<z.ZodAny>>;
270
+ labelKey: z.ZodString;
271
+ valueKey: z.ZodString;
272
+ }, z.core.$strip>;
273
+ slots: never[];
274
+ description: string;
275
+ example: {
276
+ label: string;
277
+ total: {
278
+ $state: string;
279
+ };
280
+ unit: {
281
+ $state: string;
282
+ };
283
+ items: {
284
+ $state: string;
285
+ };
286
+ labelKey: string;
287
+ valueKey: string;
288
+ };
289
+ };
290
+ Swatches: {
291
+ props: z.ZodObject<{
292
+ colors: z.ZodArray<z.ZodString>;
293
+ }, z.core.$strip>;
294
+ slots: never[];
295
+ description: string;
296
+ example: {
297
+ colors: {
298
+ $item: string;
299
+ }[];
300
+ };
301
+ };
302
+ Picture: {
303
+ props: z.ZodObject<{
304
+ path: z.ZodString;
305
+ alt: z.ZodNullable<z.ZodString>;
306
+ aspect: z.ZodNullable<z.ZodEnum<{
307
+ "1:1": "1:1";
308
+ "16:9": "16:9";
309
+ "4:3": "4:3";
310
+ auto: "auto";
311
+ }>>;
312
+ }, z.core.$strip>;
313
+ slots: never[];
314
+ description: string;
315
+ example: {
316
+ path: string;
317
+ alt: string;
318
+ aspect: string;
319
+ };
320
+ };
321
+ Fact: {
322
+ props: z.ZodObject<{
323
+ label: z.ZodString;
324
+ value: z.ZodAny;
325
+ detail: z.ZodNullable<z.ZodString>;
326
+ }, z.core.$strip>;
327
+ slots: never[];
328
+ description: string;
329
+ example: {
330
+ label: string;
331
+ value: {
332
+ $state: string;
333
+ };
334
+ };
335
+ };
336
+ DateText: {
337
+ props: z.ZodObject<{
338
+ value: z.ZodNullable<z.ZodString>;
339
+ style: z.ZodNullable<z.ZodEnum<{
340
+ long: "long";
341
+ short: "short";
342
+ weekday: "weekday";
343
+ }>>;
344
+ tone: z.ZodNullable<z.ZodEnum<{
345
+ default: "default";
346
+ muted: "muted";
347
+ accent: "accent";
348
+ }>>;
349
+ }, z.core.$strip>;
350
+ slots: never[];
351
+ description: string;
352
+ example: {
353
+ value: {
354
+ $item: string;
355
+ };
356
+ style: string;
357
+ tone: string;
358
+ };
359
+ };
360
+ TextList: {
361
+ props: z.ZodObject<{
362
+ items: z.ZodNullable<z.ZodArray<z.ZodString>>;
363
+ marker: z.ZodNullable<z.ZodEnum<{
364
+ number: "number";
365
+ check: "check";
366
+ bullet: "bullet";
367
+ }>>;
368
+ }, z.core.$strip>;
369
+ slots: never[];
370
+ description: string;
371
+ example: {
372
+ items: {
373
+ $state: string;
374
+ };
375
+ marker: string;
376
+ };
377
+ };
378
+ Detail: {
379
+ props: z.ZodObject<{
380
+ label: z.ZodString;
381
+ value: z.ZodAny;
382
+ }, z.core.$strip>;
383
+ slots: never[];
384
+ description: string;
385
+ example: {
386
+ label: string;
387
+ value: {
388
+ $item: string;
389
+ };
390
+ };
391
+ };
181
392
  AppBar: {
182
393
  props: z.ZodObject<{
183
394
  app: z.ZodString;
@@ -782,6 +993,8 @@ declare const catalog: _json_render_core.Catalog<{
782
993
  MthdsField: {
783
994
  props: z.ZodObject<{
784
995
  path: z.ZodString;
996
+ label: z.ZodNullable<z.ZodString>;
997
+ hint: z.ZodNullable<z.ZodString>;
785
998
  }, z.core.$strip>;
786
999
  slots: never[];
787
1000
  description: string;
@@ -806,6 +1019,11 @@ declare const catalog: _json_render_core.Catalog<{
806
1019
  columns: z.ZodArray<z.ZodObject<{
807
1020
  path: z.ZodString;
808
1021
  label: z.ZodString;
1022
+ format: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
1023
+ number: "number";
1024
+ date: "date";
1025
+ text: "text";
1026
+ }>>>;
809
1027
  }, z.core.$strip>>;
810
1028
  caption: z.ZodNullable<z.ZodString>;
811
1029
  }, z.core.$strip>;
@@ -863,6 +1081,16 @@ type GenerativeSpec = typeof catalog._specType;
863
1081
  * prose, in `methods/layout-design.mthds`.
864
1082
  */
865
1083
  declare const COMPONENT_NAMES: readonly string[];
1084
+ /** The component names a layout written for `frame` may use, in the order the designer method lists them. */
1085
+ declare function componentNamesFor(frame: Frame): readonly string[];
1086
+ /**
1087
+ * The catalog a layout written for `frame` is validated against: the same
1088
+ * definitions and renderings as `catalog`, held to the frame's vocabulary. A
1089
+ * composer that names an `AppBar` is refused here as an unknown component,
1090
+ * though the entry's registry could render one, because the host's frame
1091
+ * already draws what it stands for.
1092
+ */
1093
+ declare function frameCatalog(frame: Frame): ValidationCatalog;
866
1094
 
867
1095
  /** The shadcn subset, by name. The order is the order the prompt lists them. */
868
1096
  declare const PICKED_SHADCN: readonly ["Card", "Stack", "Grid", "Separator", "Heading", "Text", "Badge", "Alert", "Collapsible", "Progress", "Avatar", "Input", "Textarea", "Select", "Radio", "Checkbox", "Switch", "Button"];
@@ -914,6 +1142,16 @@ declare const BriefSchema: z.ZodObject<{
914
1142
  item_laid_out: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
915
1143
  }, z.core.$strip>>>;
916
1144
  run_control: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1145
+ returns: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
1146
+ frame: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
1147
+ page: "page";
1148
+ composer: "composer";
1149
+ result: "result";
1150
+ }>>>;
1151
+ style: z.ZodOptional<z.ZodNullable<z.ZodLazy<z.ZodObject<{
1152
+ name: z.ZodString;
1153
+ direction: z.ZodString;
1154
+ }, z.core.$strip>>>>;
917
1155
  sample_state: z.ZodOptional<z.ZodNullable<z.ZodString>>;
918
1156
  }, z.core.$strip>;
919
1157
  type Brief = z.infer<typeof BriefSchema>;
@@ -979,6 +1217,12 @@ declare const PathEntrySchema: z.ZodObject<{
979
1217
  item_laid_out: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
980
1218
  }, z.core.$strip>;
981
1219
  type PathEntry = z.infer<typeof PathEntrySchema>;
1220
+ /** An app style: a named look the components draw - faces, weights, radii, panels and rhythm - and the one sentence that says what it is, which the composition follows. */
1221
+ declare const StyleSchema: z.ZodObject<{
1222
+ name: z.ZodString;
1223
+ direction: z.ZodString;
1224
+ }, z.core.$strip>;
1225
+ type Style = z.infer<typeof StyleSchema>;
982
1226
 
983
1227
  /**
984
1228
  * The catalog as the designer method's `catalog` input: the vocabulary as
@@ -1009,18 +1253,39 @@ type DesignerComponent = Component;
1009
1253
  type DesignerAction = Action;
1010
1254
  /** The concept a run request names for the `catalog` input: the method's own, domain-qualified. */
1011
1255
  declare const DESIGNER_CATALOG_CONCEPT = "generative.Catalog";
1012
- declare function designerCatalog(): DesignerCatalog;
1256
+ /** What a catalog is built for. */
1257
+ interface DesignerCatalogOptions {
1258
+ /**
1259
+ * The frame the layout is written for: `page` (the default), a whole
1260
+ * product page; `composer` or `result`, a moment of a host's
1261
+ * compose-then-result app, whose vocabulary leaves out what that host draws
1262
+ * and adds the frame's own components (`componentNamesFor`).
1263
+ */
1264
+ frame?: Frame;
1265
+ }
1266
+ /**
1267
+ * The catalog as the designer method's `catalog` input, for one frame. The
1268
+ * same frame's `frameCatalog` is what the layout it produces is validated
1269
+ * against, so the vocabulary a model was shown and the one it is held to are
1270
+ * one list.
1271
+ */
1272
+ declare function designerCatalog({ frame }?: DesignerCatalogOptions): DesignerCatalog;
1013
1273
 
1014
1274
  /**
1015
1275
  * The hash that pairs a captured layout with the prompt it was produced
1016
1276
  * against: the first twelve hex digits of the SHA-256 of `promptHashSubject`,
1017
- * which is the designer method's text and the catalog it was handed.
1277
+ * which is the designer method's text and the catalog of every frame.
1018
1278
  *
1019
1279
  * The prompt is no longer one string this package renders: it is the method
1020
1280
  * (`methods/layout-design.mthds`, every paragraph as prose) applied to
1021
- * the catalog as data (`designerCatalog()`). Both are what a run was actually
1022
- * given, so both are hashed - a reworded rule and a renamed prop each move
1023
- * the pin, exactly as they did when the prompt was rendered here. The model
1281
+ * the catalog as data (`designerCatalog({ frame })`). Both are what a run was
1282
+ * actually given, so both are hashed - a reworded rule and a renamed prop each
1283
+ * move the pin, exactly as they did when the prompt was rendered here. A run
1284
+ * is given the catalog of one frame, and the hash covers all three in a fixed
1285
+ * order: one pin a host compares every stored layout with, whichever frame it
1286
+ * was written for, and which any frame's vocabulary moving moves. The frame a
1287
+ * layout was written for is its own provenance, beside the hash. The brief is
1288
+ * not hashed: it is the per-method half, recorded with each layout. The model
1024
1289
  * pin in the method file moves it too, since the file is hashed whole; a
1025
1290
  * fixture records its model on its own, so that costs a regeneration, never a
1026
1291
  * misread.
@@ -1037,7 +1302,117 @@ declare function designerCatalog(): DesignerCatalog;
1037
1302
  * back to the kernel's own form - because the vocabulary it was written in is
1038
1303
  * no longer the vocabulary this entry renders.
1039
1304
  */
1040
- declare const PROMPT_HASH = "2b2325fd1231";
1305
+ declare const PROMPT_HASH = "30cf9bc059f6";
1306
+ /**
1307
+ * What the hash is computed over: the method's text as shipped, then the
1308
+ * catalog of each frame as a run request carries it, in `FRAMES` order. The
1309
+ * one recipe the test, the fixture pass and a host's producer share, so the
1310
+ * pin they check and the stamp they write agree: a producer that runs the
1311
+ * method off a checkout hashes this string (SHA-256, the first twelve hex
1312
+ * digits) and compares it with `PROMPT_HASH` before it spends anything. It is
1313
+ * a string rather than the hash so the entry stays free of a hashing
1314
+ * dependency and importable from a browser.
1315
+ */
1316
+ declare function promptHashSubject(method: string): string;
1317
+
1318
+ /**
1319
+ * Whether a stored layout still fits the descriptor it will be rendered over.
1320
+ *
1321
+ * A layout is produced once per method version and stored; a descriptor is
1322
+ * derived from the method every time it is read. Those two can part company -
1323
+ * a method's input is renamed, a structure loses a member - and when they do,
1324
+ * a delegated path resolves to nothing and a bound path writes into a corner of
1325
+ * the state the run never reads. Neither fails loudly on its own, so the host
1326
+ * asks this before it renders and falls back to the kernel's own form when the
1327
+ * answer is no.
1328
+ *
1329
+ * Two directions, and the second is the one a corpus cannot notice. The first
1330
+ * is staleness: every path the layout MENTIONS is a path the descriptor still
1331
+ * has, which is the corpus test's check lifted out of the test and into the
1332
+ * product. The second is coverage: every path the descriptor REQUIRES is one
1333
+ * the layout offers somewhere. A layout that simply omits an input is not
1334
+ * stale and validates perfectly - it renders a page with no field for a
1335
+ * required input, the run gate then refuses the run for that input, and the
1336
+ * person has nowhere to type it. A page you cannot complete is worse than the
1337
+ * plain form, which is what the fallback is for.
1338
+ *
1339
+ * It answers with problems, not exceptions, and that is a promise rather than
1340
+ * a habit: a host calls this to decide whether it is safe to render, so a
1341
+ * throw leaves it with no verdict at the one moment it needs one. A layout is
1342
+ * model-produced and may be malformed in ways the walk below trips on
1343
+ * (`children: 5`, a null element, no `elements` map at all), and the other
1344
+ * gate, which refuses those shapes outright, is exported separately - so
1345
+ * neither may assume the other ran first.
1346
+ *
1347
+ * A third check sits between the two and is about KIND rather than presence:
1348
+ * a path a layout shows as a value must be a scalar, and a path it reads into
1349
+ * a prop that takes a list must be a list. A `SummaryRow` whose `value` reads
1350
+ * `/inputs/document`, a structure of a url and a filename, is not stale - the
1351
+ * path exists - and it validates perfectly; it renders `[object Object]`,
1352
+ * because the renderer stringifies what it is handed and nothing anywhere said
1353
+ * the path was not a value. An `AppBar` whose `links` read that same structure
1354
+ * is the mirror image: its renderer maps over what it is handed, renders
1355
+ * nothing for a structure and throws for a text. Only the descriptor knows
1356
+ * what kind a path is, so this is where that is said.
1357
+ *
1358
+ * What is NOT checked here is whether the layout validates against the catalog
1359
+ * - that is `validateAgainstCatalog`, and a host runs both.
1360
+ */
1361
+ interface LayoutDescriptor {
1362
+ /** The input page's top-level fields, for `/inputs/...` paths. */
1363
+ inputs?: readonly RunField[];
1364
+ /** The result page's descriptor, for `/result/...` paths. */
1365
+ result?: RunField;
1366
+ }
1367
+ /**
1368
+ * Every way this layout no longer fits, in the words a host can count by:
1369
+ * one line per element or path, empty when it fits.
1370
+ *
1371
+ * The checks live in `collectLayoutProblems`; this is the boundary that keeps
1372
+ * the promise in the header around them. A malformed spec is one line, naming
1373
+ * what the walk tripped on, which is a verdict the fallback can act on where a
1374
+ * throw was not.
1375
+ */
1376
+ declare function layoutProblems(descriptor: LayoutDescriptor, spec: Spec): string[];
1377
+ /** The predicate: `layoutProblems` is empty. */
1378
+ declare function layoutFits(descriptor: LayoutDescriptor, spec: Spec): boolean;
1379
+
1380
+ /**
1381
+ * What a producer of layouts needs beside the method, the catalog and the
1382
+ * brief: the line a creative seed travels as, the checks a produced layout is
1383
+ * held to, and how many times a refused one goes back to the method's repair
1384
+ * pass. Nothing here calls a model; the producer is the host's, on the far
1385
+ * side of this seam (docs/generative-ui.md, "Producing a layout").
1386
+ */
1387
+ /**
1388
+ * The one line a creative seed reaches the designer method as, under its
1389
+ * `seed` input. The planner's seed procedure was written against this line,
1390
+ * so a host that hands the method a seed sends it, rather than restating it.
1391
+ */
1392
+ declare function seedLine(seed: string): string;
1393
+ /**
1394
+ * How many times a producer hands a refused layout to the method's
1395
+ * `repair_layout` pass before it gives up and the host keeps the plain form.
1396
+ * The refusals the designer makes are slips of one prop or one heading, which
1397
+ * one pass told what it broke fixes; a second covers a fix that broke a rule
1398
+ * of its own, and a third would be paying for a page that is not converging.
1399
+ */
1400
+ declare const REPAIR_ATTEMPTS = 2;
1401
+ /** What a layout is checked against: the frame it was written for and the descriptor it binds. */
1402
+ interface LayoutCheck {
1403
+ frame: Frame;
1404
+ descriptor: LayoutDescriptor;
1405
+ }
1406
+ /**
1407
+ * Everything the host's two checks find wrong with a layout written for
1408
+ * `frame`, one problem a line, in the words the repair pass reads: first the
1409
+ * catalog's verdict against the frame's own vocabulary (`frameCatalog`), then
1410
+ * whether it fits the descriptor (`layoutProblems`). Empty means the layout
1411
+ * may render. A producer feeds the lines, joined, to `repair_layout` as its
1412
+ * `problems`; a host deciding whether a stored layout renders needs only
1413
+ * whether the list is empty.
1414
+ */
1415
+ declare function layoutCheckProblems(spec: Spec, { frame, descriptor }: LayoutCheck): string[];
1041
1416
 
1042
1417
  /**
1043
1418
  * The brief: the model's view of the descriptor, as DATA.
@@ -1072,6 +1447,8 @@ declare const PROMPT_HASH = "2b2325fd1231";
1072
1447
  type DesignerBrief = Brief;
1073
1448
  /** One path of the brief: where it is, what it holds, what constrains it, whether the kernel keeps it. */
1074
1449
  type DesignerPathEntry = PathEntry;
1450
+ /** The style a brief carries: its name and its direction, as `APP_STYLES` states them. */
1451
+ type DesignerStyle = Style;
1075
1452
  /** The concept a run request names for the `brief` input: the method's own, domain-qualified. */
1076
1453
  declare const DESIGNER_BRIEF_CONCEPT = "generative.Brief";
1077
1454
  interface BriefSubject {
@@ -1105,74 +1482,38 @@ declare function isDelegatedInput(field: RunField): boolean;
1105
1482
  * predicates refuse a `list` node, because a list of dates is a list and not a
1106
1483
  * date, but no catalog component reads a date's `{date, time}` either, so the
1107
1484
  * kernel renders the list whole - one value per line, as the result view does.
1108
- */
1109
- declare function isDelegatedResult(field: RunField): boolean;
1110
- /** The brief for an INPUT page: the form a run is started from. */
1111
- declare function inputBrief(subject: BriefSubject, fields: readonly RunField[]): DesignerBrief;
1112
- /** The brief for a RESULT page: what one run produced, laid out. */
1113
- declare function resultBrief(subject: BriefSubject, field: RunField, state: unknown): DesignerBrief;
1114
-
1115
- /**
1116
- * Whether a stored layout still fits the descriptor it will be rendered over.
1117
1485
  *
1118
- * A layout is produced once per method version and stored; a descriptor is
1119
- * derived from the method every time it is read. Those two can part company -
1120
- * a method's input is renamed, a structure loses a member - and when they do,
1121
- * a delegated path resolves to nothing and a bound path writes into a corner of
1122
- * the state the run never reads. Neither fails loudly on its own, so the host
1123
- * asks this before it renders and falls back to the kernel's own form when the
1124
- * answer is no.
1125
- *
1126
- * Two directions, and the second is the one a corpus cannot notice. The first
1127
- * is staleness: every path the layout MENTIONS is a path the descriptor still
1128
- * has, which is the corpus test's check lifted out of the test and into the
1129
- * product. The second is coverage: every path the descriptor REQUIRES is one
1130
- * the layout offers somewhere. A layout that simply omits an input is not
1131
- * stale and validates perfectly - it renders a page with no field for a
1132
- * required input, the run gate then refuses the run for that input, and the
1133
- * person has nowhere to type it. A page you cannot complete is worse than the
1134
- * plain form, which is what the fallback is for.
1135
- *
1136
- * It answers with problems, not exceptions, and that is a promise rather than
1137
- * a habit: a host calls this to decide whether it is safe to render, so a
1138
- * throw leaves it with no verdict at the one moment it needs one. A layout is
1139
- * model-produced and may be malformed in ways the walk below trips on
1140
- * (`children: 5`, a null element, no `elements` map at all), and the other
1141
- * gate, which refuses those shapes outright, is exported separately - so
1142
- * neither may assume the other ran first.
1143
- *
1144
- * A third check sits between the two and is about KIND rather than presence:
1145
- * a path a layout shows as a value must be a scalar, and a path it reads into
1146
- * a prop that takes a list must be a list. A `SummaryRow` whose `value` reads
1147
- * `/inputs/document`, a structure of a url and a filename, is not stale - the
1148
- * path exists - and it validates perfectly; it renders `[object Object]`,
1149
- * because the renderer stringifies what it is handed and nothing anywhere said
1150
- * the path was not a value. An `AppBar` whose `links` read that same structure
1151
- * is the mirror image: its renderer maps over what it is handed, renders
1152
- * nothing for a structure and throws for a text. Only the descriptor knows
1153
- * what kind a path is, so this is where that is said.
1154
- *
1155
- * What is NOT checked here is whether the layout validates against the catalog
1156
- * - that is `validateAgainstCatalog`, and a host runs both.
1486
+ * The result frame's vocabulary shows two of them itself: a picture
1487
+ * (`Picture`) and a date in words (`DateText`), so on a result page written
1488
+ * for that frame neither is delegated. A date with a time stays delegated:
1489
+ * `DateText` writes the day alone, and the kernel's result shows the time.
1157
1490
  */
1158
- interface LayoutDescriptor {
1159
- /** The input page's top-level fields, for `/inputs/...` paths. */
1160
- inputs?: readonly RunField[];
1161
- /** The result page's descriptor, for `/result/...` paths. */
1491
+ declare function isDelegatedResult(field: RunField, frame?: Frame): boolean;
1492
+ /** How an input page's brief is built: the frame it is written for, the team's style, and what a run returns. */
1493
+ interface InputBriefOptions {
1494
+ /** `page` (the default), a whole product page; `composer`, the inputs of a host's compose-then-result app. */
1495
+ frame?: Extract<Frame, 'page' | 'composer'>;
1496
+ /**
1497
+ * The style the team's apps wear. The brief carries its name and its
1498
+ * direction, which the composition follows; its faces, radii and panels are
1499
+ * the components' to draw and never reach the brief. Absent, the brief
1500
+ * names no style.
1501
+ */
1502
+ style?: AppStyleId;
1503
+ /** The result's descriptor, from which a composer's brief says what one run gives back. */
1162
1504
  result?: RunField;
1163
1505
  }
1164
- /**
1165
- * Every way this layout no longer fits, in the words a host can count by:
1166
- * one line per element or path, empty when it fits.
1167
- *
1168
- * The checks live in `collectLayoutProblems`; this is the boundary that keeps
1169
- * the promise in the header around them. A malformed spec is one line, naming
1170
- * what the walk tripped on, which is a verdict the fallback can act on where a
1171
- * throw was not.
1172
- */
1173
- declare function layoutProblems(descriptor: LayoutDescriptor, spec: Spec): string[];
1174
- /** The predicate: `layoutProblems` is empty. */
1175
- declare function layoutFits(descriptor: LayoutDescriptor, spec: Spec): boolean;
1506
+ /** How a result page's brief is built: the frame it is written for and the team's style. */
1507
+ interface ResultBriefOptions {
1508
+ /** `page` (the default), a whole product page; `result`, the result page of a host's compose-then-result app. */
1509
+ frame?: Extract<Frame, 'page' | 'result'>;
1510
+ /** The style the team's apps wear (see `InputBriefOptions.style`). */
1511
+ style?: AppStyleId;
1512
+ }
1513
+ /** The brief for an INPUT page: the form a run is started from. */
1514
+ declare function inputBrief(subject: BriefSubject, fields: readonly RunField[], { frame, style, result }?: InputBriefOptions): DesignerBrief;
1515
+ /** The brief for a RESULT page: what one run produced, laid out. */
1516
+ declare function resultBrief(subject: BriefSubject, field: RunField, state: unknown, { frame, style }?: ResultBriefOptions): DesignerBrief;
1176
1517
 
1177
1518
  /**
1178
1519
  * A spec as JSONL patches, and back.
@@ -1248,6 +1589,12 @@ declare function DescriptorProvider({ scope, children, }: {
1248
1589
  scope: DescriptorScope;
1249
1590
  children: react.ReactNode;
1250
1591
  }): react.JSX.Element;
1592
+ /**
1593
+ * Exported for the round-trip test only, not from the entry's index: the pair
1594
+ * is only correct together, so a test that could see just one half of it would
1595
+ * be no guard at all.
1596
+ */
1597
+ declare function domIdFor(prefix: string | undefined, path: string): string;
1251
1598
  /**
1252
1599
  * The inverse of `domIdFor`, for a host's upload seam: the kernel reports a
1253
1600
  * drop by the DOM id of the field it landed on, which for a nested one is the
@@ -1793,6 +2140,8 @@ declare const generativeRenderers: Components<_json_render_core.Catalog<{
1793
2140
  MthdsField: {
1794
2141
  props: zod.ZodObject<{
1795
2142
  path: zod.ZodString;
2143
+ label: zod.ZodNullable<zod.ZodString>;
2144
+ hint: zod.ZodNullable<zod.ZodString>;
1796
2145
  }, zod_v4_core.$strip>;
1797
2146
  slots: never[];
1798
2147
  description: string;
@@ -1817,6 +2166,11 @@ declare const generativeRenderers: Components<_json_render_core.Catalog<{
1817
2166
  columns: zod.ZodArray<zod.ZodObject<{
1818
2167
  path: zod.ZodString;
1819
2168
  label: zod.ZodString;
2169
+ format: zod.ZodOptional<zod.ZodNullable<zod.ZodEnum<{
2170
+ number: "number";
2171
+ date: "date";
2172
+ text: "text";
2173
+ }>>>;
1820
2174
  }, zod_v4_core.$strip>>;
1821
2175
  caption: zod.ZodNullable<zod.ZodString>;
1822
2176
  }, zod_v4_core.$strip>;
@@ -1873,8 +2227,12 @@ interface GenerativePageProps {
1873
2227
  store: StateStore;
1874
2228
  /** The descriptor the escape hatches resolve paths against. */
1875
2229
  scope: DescriptorScope;
1876
- /** What `run` does. Receives the state at the moment the call to action was pressed. */
1877
- onRun?: (state: StateModel) => void;
2230
+ /**
2231
+ * What `run` does. Receives the state at the moment the call to action was
2232
+ * pressed. Return the run's promise and a press while it is pending starts
2233
+ * nothing.
2234
+ */
2235
+ onRun?: (state: StateModel) => void | Promise<unknown>;
1878
2236
  /** Whether a stream is still arriving. */
1879
2237
  loading?: boolean;
1880
2238
  /** A registry over a catalog that extends this entry's, when a host has one. */
@@ -1946,6 +2304,31 @@ declare function BrandProvider({ manifest, children, }: {
1946
2304
  }): react.JSX.Element;
1947
2305
  declare function useBrand(): BrandManifest;
1948
2306
 
2307
+ /**
2308
+ * What a host's compose-then-result frame tells the frame components of a
2309
+ * layout - the facts no descriptor carries.
2310
+ *
2311
+ * A layout written for the `composer` frame places the host's action row
2312
+ * through `Composer`, and one written for the `result` frame places the
2313
+ * host's actions through `ResultHeader`. What those rows SAY beyond the
2314
+ * layout's own words is the host's knowledge: how long a run usually takes,
2315
+ * what the result's actions are called and what they do. The layout names
2316
+ * where they go; the host fills them.
2317
+ */
2318
+ interface FrameHost {
2319
+ /** How long a run usually takes, from the app's past runs: "Takes about 30 seconds". */
2320
+ eta?: string;
2321
+ /** The result's actions, primary first: "Download PDF", "Share". */
2322
+ actions?: readonly string[];
2323
+ /** What an action does, by its label. */
2324
+ onAction?: (label: string) => void;
2325
+ }
2326
+ declare function FrameHostProvider({ host, children, }: {
2327
+ host: FrameHost;
2328
+ children: react.ReactNode;
2329
+ }): react.JSX.Element;
2330
+ declare function useFrameHost(): FrameHost;
2331
+
1949
2332
  /**
1950
2333
  * The two state trees, and how a path into either maps back onto the
1951
2334
  * descriptor.
@@ -2051,6 +2434,15 @@ interface SpecFixture {
2051
2434
  seed?: string;
2052
2435
  /** The critic loop the producer ran, when one did. */
2053
2436
  critic?: CriticLoop;
2437
+ /** The frame it was written for, when not a whole product page: `composer` or `result`. */
2438
+ frame?: Exclude<Frame, 'page'>;
2439
+ /** The style the brief carried, when it carried one. */
2440
+ style?: AppStyleId;
2441
+ /**
2442
+ * How many times the method's repair pass re-emitted it before it passed
2443
+ * the checks, when it needed any: the page as stored is the last pass's.
2444
+ */
2445
+ repairs?: number;
2054
2446
  /** The first twelve hex digits of the SHA-256 of the catalog prompt at the time. */
2055
2447
  promptHash: string;
2056
2448
  /** The day it was produced, `YYYY-MM-DD`. */
@@ -2070,17 +2462,20 @@ interface SpecFixture {
2070
2462
  */
2071
2463
  plan?: PagePlan;
2072
2464
  }
2465
+ type Provenance = Pick<SpecFixture, 'producer' | 'model' | 'seed' | 'critic' | 'frame' | 'style'>;
2073
2466
  /**
2074
- * The id a story and a screenshot are keyed by: producer, model and the two
2075
- * procedures that change what a run is. `pipelex-method--gpt-5.5--seeded`.
2467
+ * The id a story and a screenshot are keyed by: producer, model, the frame and
2468
+ * the style it was written for, and the two procedures that change what a run
2469
+ * is. `pipelex-method--gpt-5.5--seeded`,
2470
+ * `pipelex-method--gpt-6.1-sol--composer--soft--seeded`.
2076
2471
  */
2077
- declare function fixtureId(fixture: Pick<SpecFixture, 'producer' | 'model' | 'seed' | 'critic'>): string;
2472
+ declare function fixtureId(fixture: Provenance): string;
2078
2473
  /**
2079
2474
  * The honest title: what made the page. `Pipelex method · gpt-5.5 · with a
2080
2475
  * seed`, never a role ("authored", "generated").
2081
2476
  */
2082
- declare function fixtureLabel(fixture: Pick<SpecFixture, 'producer' | 'model' | 'seed' | 'critic'>): string;
2477
+ declare function fixtureLabel(fixture: Provenance & Pick<SpecFixture, 'repairs'>): string;
2083
2478
  /** The fixture a story asks for, or a loud failure: a story must never render a page it did not name. */
2084
2479
  declare function findFixture(fixtures: readonly SpecFixture[], pipeRef: string, id: string): SpecFixture;
2085
2480
 
2086
- export { BrandManifest, BrandProvider, type BriefSubject, COMPONENT_NAMES, COMPONENT_RENDERINGS, CUSTOM_COMPONENTS, type ComponentRendering, type CriticLoop, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, DescriptorProvider, type DescriptorScope, type DesignerAction, type DesignerBrief, type DesignerCatalog, type DesignerComponent, type DesignerPathEntry, GenerativePage, type GenerativePageProps, type GenerativeSpec, ICON_NAMES, INPUTS_ROOT, type LayoutDescriptor, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, type PageRegistry, type Producer, type ProductComponentName, RESULT_ROOT, type ResultSlot, ResultSlotProvider, type SpecFixture, type SpecProblem, type SpecVerdict, type ValidationCatalog, absoluteHatchPath, catalog, designerCatalog, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, generativeRegistry, generativeRenderers, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutFits, layoutProblems, pathFromDomId, payloadToState, repeatBasePathOf, resultBrief, resultFieldAtPath, segmentsUnder, specFromJsonl, specToJsonl, useBrand, useDescriptorScope, useResultSlot, useStoreSnapshot, validateAgainstCatalog };
2481
+ export { BrandManifest, BrandProvider, type BriefSubject, COMPONENT_NAMES, COMPONENT_RENDERINGS, COMPOSER_COMPONENTS, CUSTOM_COMPONENTS, type ComponentRendering, type CriticLoop, DESIGNER_BRIEF_CONCEPT, DESIGNER_CATALOG_CONCEPT, DescriptorProvider, type DescriptorScope, type DesignerAction, type DesignerBrief, type DesignerCatalog, type DesignerCatalogOptions, type DesignerComponent, type DesignerPathEntry, type DesignerStyle, FRAMES, FRAME_COMPONENTS, type Frame, type FrameHost, FrameHostProvider, GenerativePage, type GenerativePageProps, type GenerativeSpec, ICON_NAMES, INPUTS_ROOT, type InputBriefOptions, type LayoutCheck, type LayoutDescriptor, METRIC_FORMATS, PICKED_SHADCN, PRODUCT_COMPONENTS, PROMPT_HASH, type PageRegistry, type Producer, type ProductComponentName, REPAIR_ATTEMPTS, RESULT_COMPONENTS, RESULT_ROOT, type ResultBriefOptions, type ResultSlot, ResultSlotProvider, type SpecFixture, type SpecProblem, type SpecVerdict, type ValidationCatalog, absoluteHatchPath, catalog, componentNamesFor, designerCatalog, domIdFor, fieldAtSegments, findFixture, fixtureId, fixtureLabel, formatProblems, frameCatalog, generativeRegistry, generativeRenderers, inputBrief, inputFieldAtPath, isDelegatedInput, isDelegatedResult, joinPath, jsonlLines, layoutCheckProblems, layoutFits, layoutProblems, pathFromDomId, payloadToState, promptHashSubject, repeatBasePathOf, resultBrief, resultFieldAtPath, seedLine, segmentsUnder, specFromJsonl, specToJsonl, useBrand, useDescriptorScope, useFrameHost, useResultSlot, useStoreSnapshot, validateAgainstCatalog };