4040 * - CONTROL: a single-package config (no `packages[]`) is unchanged and has
4141 * no residual on either door.
4242 *
43- * ⚠️ What this file does NOT pin: the data door for a residual OBJECT. Both
44- * doors list it on `/meta/object` and answer `404` on `/data/<name>` — the
45- * residual rule registers metadata, and no engine registration follows. That
46- * is the artifact door's answer this card makes the config boot match, not a
47- * behaviour to freeze.
43+ * The DATA door is read beside the metadata door (#22615): every `acme_*`
44+ * object `/meta/object` lists is read back on `/data/<name>`. A residual object
45+ * is listed under the stack's `manifest.id` AND served under it — the engine's
46+ * `manifest` service registers the residual rule's own objects
47+ * (`unclaimedTopLevel`), so both doors give one answer through both boots.
48+ * Before that, both boots listed `acme_note` and answered `404` on
49+ * `/data/acme_note`. The bodies' own objects are the control: `200` before and
50+ * after, on every row.
4851 *
4952 * ⚠️ Pedigree, not counts: every doc page carries a marker written into exactly
5053 * one source, read back from the served doc.
@@ -325,6 +328,8 @@ interface Reading {
325328 /** `name@owner`, sorted. */
326329 objects : string [ ] ;
327330 views : string [ ] ;
331+ /** `name:status` of `GET /data/<name>` for every object `objects` lists, sorted. */
332+ data : string [ ] ;
328333 /** The count each residual line reports — one entry per line printed. */
329334 residual : number [ ] ;
330335}
@@ -364,14 +369,23 @@ async function read(dir: string, args: string[]): Promise<Reading> {
364369 marker : / M A R K E R - 2 2 5 2 1 - [ \w - ] + / . exec ( JSON . stringify ( one . body ) ) ?. [ 0 ] ,
365370 } ;
366371 }
367- const objects = owned ( await list ( 'object' ) ) ;
372+ const listedObjects = await list ( 'object' ) ;
373+ const objects = owned ( listedObjects ) ;
368374 const views = owned ( await list ( 'view' ) ) ;
375+ // The data door, for exactly the objects the metadata door listed: one
376+ // answer per object across the two doors (#22615).
377+ const data : string [ ] = [ ] ;
378+ for ( const item of listedObjects ) {
379+ const rows = await request ( serve , `the data read of ${ item . name } ` , `${ base } /data/${ item . name } ` , { headers } ) ;
380+ data . push ( `${ item . name } :${ rows . status } ` ) ;
381+ }
382+ data . sort ( ) ;
369383 const residual = serve . output ( )
370384 . split ( '\n' )
371385 . map ( ( line ) => RESIDUAL_LINE . exec ( line ) ?. [ 1 ] )
372386 . filter ( ( count ) : count is string => count !== undefined )
373387 . map ( Number ) ;
374- return { docs, objects, views, residual } ;
388+ return { docs, objects, views, data , residual } ;
375389 } finally {
376390 await stop ( serve . child ) ;
377391 }
@@ -455,6 +469,8 @@ describe('#22521 row 2: flat src/docs with a manifest.id naming no package', ()
455469 acme_faq : { packageId : RELEASE_ID , marker : 'MARKER-22521-flat-faq' } ,
456470 } ) ;
457471 expect ( artifact . residual ) . toEqual ( [ 2 ] ) ;
472+ // The control for #22615's data-door reading: the bodies' own objects.
473+ expect ( artifact . data , JSON . stringify ( artifact ) ) . toEqual ( [ 'acme_account:200' , 'acme_case:200' ] ) ;
458474 } ) ;
459475
460476 it ( 'the config boot gives the artifact boot\'s answer, without --dev' , ( ) => {
@@ -493,6 +509,12 @@ describe('#22521 row 4: a top-level object and view no package owns', () => {
493509 // Before the fix: neither acme_note nor its view listed, no residual line.
494510 expect ( configDev ) . toEqual ( artifact ) ;
495511 } ) ;
512+
513+ it ( 'the data door serves the residual object the metadata door lists, through both boots (#22615)' , ( ) => {
514+ // Before #22615, on both boots: `acme_note:404` beside the listing above.
515+ expect ( artifact . data , JSON . stringify ( artifact ) ) . toEqual ( [ 'acme_account:200' , 'acme_case:200' , 'acme_note:200' ] ) ;
516+ expect ( configDev . data , JSON . stringify ( configDev ) ) . toEqual ( artifact . data ) ;
517+ } ) ;
496518} ) ;
497519
498520describe ( '#22521 row 3: inline docs spread on a composed stack\'s top level' , ( ) => {
@@ -519,6 +541,7 @@ describe('#22521 row 3: inline docs spread on a composed stack\'s top level', ()
519541 acme_inline : { packageId : APP_ID , marker : 'MARKER-22521-inline' } ,
520542 } ) ;
521543 expect ( configDev . residual ) . toEqual ( [ 1 ] ) ;
544+ expect ( configDev . data , JSON . stringify ( configDev ) ) . toEqual ( [ 'acme_account:200' , 'acme_case:200' ] ) ;
522545 } ) ;
523546} ) ;
524547
@@ -540,6 +563,7 @@ describe('#22521 control: a single-package config has no residual on either door
540563 } ) ;
541564 expect ( artifact . objects ) . toEqual ( [ `acme_account@${ APP_ID } ` , `acme_note@${ APP_ID } ` ] ) ;
542565 expect ( artifact . views ) . toEqual ( [ `acme_note.default@${ APP_ID } ` ] ) ;
566+ expect ( artifact . data ) . toEqual ( [ 'acme_account:200' , 'acme_note:200' ] ) ;
543567 expect ( artifact . residual ) . toEqual ( [ ] ) ;
544568 } ) ;
545569
0 commit comments