2525// lives in the dogfood suite, against a real app:
2626// `packages/qa/dogfood/test/org-scoped-sharing-rule-listing.dogfood.test.ts`.
2727
28- import { describe , it , expect , afterEach } from 'vitest' ;
28+ import { describe , it , expect , beforeAll , afterEach } from 'vitest' ;
2929// `.js` extension deliberately: this package resolves NodeNext, so an
3030// extensionless relative import is a TS2835 the type-check-debt ratchet counts
3131// (the sibling test files predate the gate and carry theirs in the ledger — a
3232// NEW one would raise it, which is not something a test file gets to do).
33- import { bootStack , type VerifyStack } from './harness.js' ;
33+ import { bootStack , type BootOptions , type VerifyStack } from './harness.js' ;
34+ import { warmUpBoot } from './boot-warm-up.testkit.js' ;
3435
3536const app = {
3637 manifest : {
@@ -56,6 +57,11 @@ const SYS = { isSystem: true } as const;
5657// Booting the full in-process stack runs well past vitest's 5s default.
5758const BOOT_TIMEOUT = 120_000 ;
5859
60+ // The boot's first load, paid during collection rather than in the first
61+ // boot's clock (see `boot-warm-up.testkit.ts`). The first boot below uses the
62+ // default options.
63+ await warmUpBoot ( ) ;
64+
5965afterEach ( ( ) => {
6066 delete process . env . OS_TENANCY_POSTURE ;
6167} ) ;
@@ -96,7 +102,58 @@ async function sessionOrgId(stack: VerifyStack): Promise<string | null> {
96102 return null ;
97103}
98104
105+ /** What one boot of `app` answered, read while it was live. */
106+ interface BootReading {
107+ posture : TenancyShape ;
108+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
109+ orgs : any [ ] ;
110+ sessionOrgId : string | null ;
111+ /** The roles of the admin's `sys_member` rows in the first organization. */
112+ adminRoles : unknown [ ] ;
113+ }
114+
115+ /**
116+ * Boot `app` with `opts`, read the posture, the organizations, the org id the
117+ * admin's session carries and the admin's membership roles, and stop. Each
118+ * read is one the cases below used to make on a boot of their own with the
119+ * same options.
120+ */
121+ async function bootAndRead ( opts : BootOptions ) : Promise < BootReading > {
122+ const stack = await bootStack ( app , opts ) ;
123+ try {
124+ const shape = await posture ( stack ) ;
125+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
126+ const ql = await stack . kernel . getServiceAsync < any > ( 'objectql' ) ;
127+ const orgs = rowsOf ( await ql . find ( 'sys_organization' , { limit : 10 , context : SYS } ) ) ;
128+ const orgId = await sessionOrgId ( stack ) ;
129+ const users = rowsOf (
130+ await ql . find ( 'sys_user' , { where : { email : 'admin@objectos.ai' } , limit : 1 , context : SYS } ) ,
131+ ) ;
132+ const memberships = rowsOf (
133+ await ql . find ( 'sys_member' , {
134+ where : { user_id : users [ 0 ] ?. id , organization_id : orgs [ 0 ] ?. id } ,
135+ limit : 10 ,
136+ context : SYS ,
137+ } ) ,
138+ ) ;
139+ return { posture : shape , orgs, sessionOrgId : orgId , adminRoles : memberships . map ( ( m ) => m . role ) } ;
140+ } finally {
141+ await stack . stop ( ) ;
142+ }
143+ }
144+
99145describe ( 'bootStack orgContext (#7762)' , ( ) => {
146+ // Two boots for the three cases that read one: the flag off (the default
147+ // boot) and on, in that order, each stopped before the next starts — the
148+ // order the ruling case always booted them in. Every case only reads what a
149+ // boot answered, so no case depends on another's run or on their order.
150+ let off : BootReading ;
151+ let on : BootReading ;
152+ beforeAll ( async ( ) => {
153+ off = await bootAndRead ( { } ) ;
154+ on = await bootAndRead ( { orgContext : true } ) ;
155+ } , BOOT_TIMEOUT * 2 ) ;
156+
100157 it (
101158 'THE RULING: the tenancy posture and `degraded` are IDENTICAL with the flag off vs on' ,
102159 async ( ) => {
@@ -106,21 +163,8 @@ describe('bootStack orgContext (#7762)', () => {
106163 // so binding the admin to an organization must not move it. If this ever
107164 // fails, `orgContext` is making the open core claim a wall it does not
108165 // have and the option must not ship in that shape.
109- const off = await bootStack ( app , { } ) ;
110- let baseline : TenancyShape ;
111- try {
112- baseline = await posture ( off ) ;
113- } finally {
114- await off . stop ( ) ;
115- }
116-
117- const on = await bootStack ( app , { orgContext : true } ) ;
118- let withOrg : TenancyShape ;
119- try {
120- withOrg = await posture ( on ) ;
121- } finally {
122- await on . stop ( ) ;
123- }
166+ const baseline = off . posture ;
167+ const withOrg = on . posture ;
124168
125169 expect ( withOrg ) . toEqual ( baseline ) ;
126170 // Spelled out too, so a future refactor of `posture()` cannot make the
@@ -137,23 +181,16 @@ describe('bootStack orgContext (#7762)', () => {
137181 it (
138182 'binds the admin to a real organization, and their session carries it' ,
139183 async ( ) => {
140- const stack = await bootStack ( app , { orgContext : true } ) ;
141- try {
142- // eslint-disable-next-line @typescript-eslint/no-explicit-any
143- const ql = await stack . kernel . getServiceAsync < any > ( 'objectql' ) ;
144- const orgs = rowsOf ( await ql . find ( 'sys_organization' , { limit : 10 , context : SYS } ) ) ;
145- expect ( orgs . length , 'the default-org bootstrap minted an organization' ) . toBeGreaterThan ( 0 ) ;
146-
147- // `session.activeOrganizationId` is the ONE field `resolveAuthzContext`
148- // reads into `tenantId` → `ExecutionContext`. Without it on the session
149- // row, every org-scoped read downstream is org-less no matter how many
150- // organizations exist in the table.
151- const orgId = await sessionOrgId ( stack ) ;
152- expect ( orgId , "the admin's session carries an active organization" ) . toBeTruthy ( ) ;
153- expect ( orgs . map ( ( o ) => o . id ) ) . toContain ( orgId ) ;
154- } finally {
155- await stack . stop ( ) ;
156- }
184+ const { orgs } = on ;
185+ expect ( orgs . length , 'the default-org bootstrap minted an organization' ) . toBeGreaterThan ( 0 ) ;
186+
187+ // `session.activeOrganizationId` is the ONE field `resolveAuthzContext`
188+ // reads into `tenantId` → `ExecutionContext`. Without it on the session
189+ // row, every org-scoped read downstream is org-less no matter how many
190+ // organizations exist in the table.
191+ const orgId = on . sessionOrgId ;
192+ expect ( orgId , "the admin's session carries an active organization" ) . toBeTruthy ( ) ;
193+ expect ( orgs . map ( ( o ) => o . id ) ) . toContain ( orgId ) ;
157194 } ,
158195 BOOT_TIMEOUT ,
159196 ) ;
@@ -165,32 +202,15 @@ describe('bootStack orgContext (#7762)', () => {
165202 // Default Organization (a boot invariant), and the admin is bound to it
166203 // without asking — the shape `objectstack dev` / `serve` boot. There is
167204 // no org-less `single` boot left to keep a fixture on (ADR-0131 D11).
168- const stack = await bootStack ( app , { } ) ;
169- try {
170- // eslint-disable-next-line @typescript-eslint/no-explicit-any
171- const ql = await stack . kernel . getServiceAsync < any > ( 'objectql' ) ;
172- const orgs = rowsOf ( await ql . find ( 'sys_organization' , { limit : 10 , context : SYS } ) ) ;
173- expect ( orgs . map ( ( o ) => o . slug ) ) . toEqual ( [ 'default' ] ) ;
174- expect ( await sessionOrgId ( stack ) ) . toBe ( orgs [ 0 ] . id ) ;
175- // The harness line this case pins is the owner bind (ADR-0093 D7), on
176- // for every boot: the admin OWNS the Default Organization. The two
177- // assertions above hold without it (the boot invariant creates the
178- // organization and the membership reconciler binds the admin), but as
179- // `member` — which is what an `objectstack dev` admin never is.
180- const users = rowsOf (
181- await ql . find ( 'sys_user' , { where : { email : 'admin@objectos.ai' } , limit : 1 , context : SYS } ) ,
182- ) ;
183- const memberships = rowsOf (
184- await ql . find ( 'sys_member' , {
185- where : { user_id : users [ 0 ] ?. id , organization_id : orgs [ 0 ] . id } ,
186- limit : 10 ,
187- context : SYS ,
188- } ) ,
189- ) ;
190- expect ( memberships . map ( ( m ) => m . role ) ) . toEqual ( [ 'owner' ] ) ;
191- } finally {
192- await stack . stop ( ) ;
193- }
205+ const { orgs } = off ;
206+ expect ( orgs . map ( ( o ) => o . slug ) ) . toEqual ( [ 'default' ] ) ;
207+ expect ( off . sessionOrgId ) . toBe ( orgs [ 0 ] . id ) ;
208+ // The harness line this case pins is the owner bind (ADR-0093 D7), on
209+ // for every boot: the admin OWNS the Default Organization. The two
210+ // assertions above hold without it (the boot invariant creates the
211+ // organization and the membership reconciler binds the admin), but as
212+ // `member` — which is what an `objectstack dev` admin never is.
213+ expect ( off . adminRoles ) . toEqual ( [ 'owner' ] ) ;
194214 } ,
195215 BOOT_TIMEOUT ,
196216 ) ;
0 commit comments