@@ -105,7 +105,12 @@ function matches(row: Row, where: Record<string, unknown> = {}): boolean {
105105 } ) ;
106106}
107107
108- function makeProtocol ( ) {
108+ /**
109+ * `pairInstalled: false` boots the base with no pair yet: a fresh install,
110+ * before anything ensured `<base>.custom` (the ensure door, or the ceremony's
111+ * step 1, creates it on the first write that needs it).
112+ */
113+ function makeProtocol ( { pairInstalled = true } : { pairInstalled ?: boolean } = { } ) {
109114 const tables = new Map < string , Row [ ] > ( ) ;
110115 const table = ( n : string ) => {
111116 if ( ! tables . has ( n ) ) tables . set ( n , [ ] ) ;
@@ -116,7 +121,8 @@ function makeProtocol() {
116121 const hit = SHIPPED . find ( ( i ) => i . type === type && i . name === name ) ;
117122 return hit ? { ...ITEMS . find ( ( i ) => i . type === type && i . name === name ) ?. body ( PACKAGED ) , name, label : PACKAGED , _packageId : hit . pkg , _provenance : 'package' } : undefined ;
118123 } ;
119- const packageRecord = ( id : string ) => ( MANIFESTS [ id ] ? { manifest : { id, ...MANIFESTS [ id ] } } : undefined ) ;
124+ const installed = ( id : string ) => MANIFESTS [ id ] !== undefined && ( pairInstalled || id !== PAIR ) ;
125+ const packageRecord = ( id : string ) => ( installed ( id ) ? { manifest : { id, ...MANIFESTS [ id ] } } : undefined ) ;
120126 const engine : any = {
121127 // A booted code package is read-only (`isWritablePackage` reads `manifests` first).
122128 manifests : new Map ( [ [ BASE , { } ] , [ NO_PAIR_BASE , { } ] , [ NO_PAIR_ID_BASE , { } ] , [ NO_VERSION_BASE , { } ] ] ) ,
@@ -161,7 +167,7 @@ function makeProtocol() {
161167 getItem : ( type : string , name : string ) => artifact ( type , name ) ,
162168 getObject : ( ) => undefined ,
163169 getPackage : packageRecord ,
164- getAllPackages : ( ) => Object . keys ( MANIFESTS ) . map ( packageRecord ) ,
170+ getAllPackages : ( ) => Object . keys ( MANIFESTS ) . filter ( installed ) . map ( packageRecord ) ,
165171 isPackageDisabled : ( ) => false ,
166172 getArtifactItem : artifact ,
167173 applyNavContributions : ( a : unknown ) => a ,
@@ -433,6 +439,45 @@ describe('CONTROLS: every step the fix takes, failing, leaves the write naming t
433439 } ) ;
434440} ) ;
435441
442+ describe ( 'a fresh install, the pair not yet ensured: an email template at a locale the base does not ship stays open (ADR-0146 D11)' , ( ) => {
443+ // The close asks the override write gate about the declared body written
444+ // into the pair. Before the pair exists, that question is the one the
445+ // ensured pair would meet (its closure: the base and what the base
446+ // reaches), never "no such package, not concerned" read as "admitted".
447+ const email = ITEMS . find ( ( i ) => i . type === 'email_template' ) ! ;
448+ const unshipped = ( label : string ) => ( { ...email . body ( label ) , locale : 'fr-FR' } ) ;
449+
450+ it ( 'the package-less save is accepted and served as the environment\'s own member' , async ( ) => {
451+ const { protocol, rows } = makeProtocol ( { pairInstalled : false } ) ;
452+
453+ const saved = await protocol . saveMetaItem ( { type : email . type , name : email . name , item : unshipped ( 'Bienvenue' ) } ) ;
454+
455+ expect ( saved ) . toMatchObject ( { success : true } ) ;
456+ expect ( rows ( email . type , email . name ) ) . toEqual ( [ { package_id : null , state : 'active' , label : 'Bienvenue' } ] ) ;
457+ } ) ;
458+
459+ it ( 'the save naming the base is accepted, as it is with the pair installed' , async ( ) => {
460+ const { protocol, rows } = makeProtocol ( { pairInstalled : false } ) ;
461+
462+ const saved = await protocol . saveMetaItem ( { type : email . type , name : email . name , item : unshipped ( 'Bienvenue' ) , packageId : BASE } ) ;
463+
464+ expect ( saved ) . toMatchObject ( { success : true } ) ;
465+ expect ( rows ( email . type , email . name ) ) . toEqual ( [ { package_id : BASE , state : 'active' , label : 'Bienvenue' } ] ) ;
466+ } ) ;
467+
468+ it ( 'CONTROL: a member the base ships is still closed onto the pair, naming it, with the pair not yet ensured' , async ( ) => {
469+ const { protocol, rows } = makeProtocol ( { pairInstalled : false } ) ;
470+
471+ const packageless = await thrown ( ( ) => protocol . saveMetaItem ( { type : email . type , name : email . name , item : email . body ( 'Mine' ) } ) ) ;
472+ const namedBase = await thrown ( ( ) => protocol . saveMetaItem ( { type : email . type , name : email . name , item : email . body ( 'Mine' ) , packageId : BASE } ) ) ;
473+
474+ expect ( resolveThrownHttpError ( packageless ) ) . toMatchObject ( { status : 403 , code : 'NOT_OVERRIDABLE' } ) ;
475+ expect ( String ( packageless . message ) ) . toContain ( `'${ PAIR } ' (?package=${ PAIR } )` ) ;
476+ expectClosed ( namedBase , email . type , email . name , 'save' ) ;
477+ expect ( rows ( email . type , email . name ) ) . toEqual ( [ ] ) ;
478+ } ) ;
479+ } ) ;
480+
436481describe ( 'the commit doors: restoring a row bound to the base is closed, removing one stays open (#29390)' , ( ) => {
437482 /** Each commit a second apart, so the package rollback's "strictly newer" reads an order. */
438483 let clock = Date . parse ( '2026-11-02T00:00:00.000Z' ) ;
0 commit comments