@@ -193,6 +193,8 @@ export interface DashboardWindowMeasureResult {
193193 excludedKind ?: DashboardWindowExclusion ;
194194 /** The fixture days written (UTC calendar days). */
195195 days ?: string [ ] ;
196+ /** `smallest` — the required fields only; `every-field` — the seed door refused that, so every field the CRUD derivation synthesizes. */
197+ fixture ?: 'smallest' | 'every-field' ;
196198 /** The control leg: the widget with no window must count every fixture row. */
197199 unwindowed ?: { expected : number ; answered ?: number ; answer ?: DashboardWindowAnswer } ;
198200 presets : DashboardWindowPresetProbe [ ] ;
@@ -515,18 +517,19 @@ function uniqueFields(objectDef: any): Set<string> {
515517}
516518
517519/**
518- * The smallest record the CRUD derivation can offer (the shape the sibling
519- * families use): its values for the fields the object REQUIRES, so every
520- * optional field takes the app's own default; each `date` / `datetime` one day
521- * after the one declared before it, and each unique-constrained value made
522- * distinct by `n`.
520+ * A record the CRUD derivation can offer: by default the smallest (the shape
521+ * the sibling families use) — its values for the fields the object REQUIRES,
522+ * so every optional field takes the app's own default; with `full`, every
523+ * field it synthesizes (what a rule that requires a field only in some state
524+ * asks for). Each `date` / `datetime` is one day after the one declared before
525+ * it, and each unique-constrained value is made distinct by `n`.
523526 */
524- function fixtureBody ( body : Record < string , unknown > , objectDef : any , n : number ) : Record < string , unknown > {
527+ function fixtureBody ( body : Record < string , unknown > , objectDef : any , n : number , full = false ) : Record < string , unknown > {
525528 const unique = uniqueFields ( objectDef ) ;
526529 const out : Record < string , unknown > = { } ;
527530 let dates = 0 ;
528531 for ( const [ name , def ] of Object . entries < any > ( objectDef ?. fields ?? { } ) ) {
529- if ( def ?. required !== true || ! ( name in body ) ) continue ;
532+ if ( ( ! full && def ?. required !== true ) || ! ( name in body ) ) continue ;
530533 let value = body [ name ] ;
531534 if ( ( def ?. type === 'date' || def ?. type === 'datetime' ) && typeof value === 'string' ) value = laterBy ( value , dates ++ ) ;
532535 if ( unique . has ( name ) && ( typeof value === 'string' || typeof value === 'number' ) ) value = vary ( value , n ) ;
@@ -860,24 +863,40 @@ export async function runDashboardWindowProofs(
860863 const days = fixtureDays ( presets , day0 ) ;
861864 const stamp = ( day : string ) => ( fieldType === 'date' ? day : `${ day } T12:00:00.000Z` ) ;
862865 const written : Array < { day : string ; id : string } > = [ ] ;
866+ // The smallest record first; if the seed door refuses it (an app rule that
867+ // requires a field in the state the held columns put the row in), every
868+ // field the CRUD derivation synthesizes, and that shape for the rest.
869+ let full = false ;
863870 for ( const day of days ) {
864- const row : Record < string , unknown > = {
865- ...fixtureBody ( body , objectDefs . get ( c . object ! ) , ++ counter ) ,
871+ const row = ( wide : boolean ) : Record < string , unknown > => ( {
872+ ...fixtureBody ( body , objectDefs . get ( c . object ! ) , ++ counter , wide ) ,
866873 ...( ownerColumn ? { owner_id : principal } : { } ) ,
867874 ...Object . fromEntries ( held ) ,
868875 [ c . field ! ] : stamp ( day ) ,
876+ } ) ;
877+ const seedOne = async ( wide : boolean ) : Promise < string > => {
878+ const [ made ] = await stack . seed ( c . object ! , [ row ( wide ) ] ) ;
879+ if ( made ?. id == null ) throw new Error ( `the seed of ${ c . object } returned no id` ) ;
880+ return String ( made . id ) ;
869881 } ;
870882 try {
871- const [ made ] = await stack . seed ( c . object ! , [ row ] ) ;
872- if ( made ?. id == null ) throw new Error ( `the seed of ${ c . object } returned no id` ) ;
873- written . push ( { day, id : String ( made . id ) } ) ;
883+ let id : string ;
884+ try {
885+ id = await seedOne ( full ) ;
886+ } catch ( first ) {
887+ if ( full || written . length > 0 ) throw first ;
888+ full = true ;
889+ id = await seedOne ( true ) ;
890+ }
891+ written . push ( { day, id } ) ;
874892 } catch ( e ) {
875893 r . days = days ;
876894 notRun ( `the fixture row for ${ day } was refused by the seed door: ${ clip ( ( e as Error ) ?. message , 160 ) } ` ) ;
877895 return ;
878896 }
879897 }
880898 r . days = days ;
899+ r . fixture = full ? 'every-field' : 'smallest' ;
881900 // Read back: the stamp and every held column must read as written.
882901 for ( const { day, id } of written ) {
883902 const [ got ] = await stack . rows ( c . object ! , { id } ) ;
0 commit comments