2020 * Fix by taking the surface fact (a cursor's route identity, a wire shape) as input from
2121 * the adapter.
2222 *
23- * 3. The organization surface's seam points one way. `apps/sim/platform/embedded/lib` never imports
24- * `@/platform/embedded/app` or `@/app/o`, not even for a type: views depend on the data layer, routes
25- * depend on both, and a data file that reached back into either could not be read or tested
26- * without it. Fix by moving what both need under `platform/embedded/lib`, or under `lib/` when a surface
27- * the design system may not reach (the extension, `/workspace`) shares it.
23+ * 3. The organization surface's seam points one way, in both data layers. `apps/sim/platform/embedded/lib`
24+ * never imports `@/platform/embedded/app` or `@/app/o`, not even for a type, and
25+ * `apps/sim/platform/lib` never imports `@/app/o`, not even for a type, or `@/platform/app` at
26+ * runtime: views depend on the data layer, routes depend on both, and a data file that reached
27+ * back into either could not be read or tested without it. Fix by moving what both need under
28+ * the data layer, or under `lib/` when a surface the design system may not reach (the extension,
29+ * `/workspace`) shares it.
2830 * 4. Views (`apps/sim/platform/embedded/app`) read data through `platform/embedded/lib/data`, so a read gets one
2931 * adaptation and one place to fix it: no runtime edge to a data hook, in `@/hooks/queries` or
3032 * a `hooks` folder under `@/ee`. Domain primitives elsewhere in `@/ee` (`lib`, constants,
4446 * the host app, so an edge from the zone would pull the host into a separate build, and an edge
4547 * the other way would make the zone part of what every organization ships.
4648 *
47- * Rules 1 to 3 and 7 have no allowlist. Rules 4 to 6 predate their enforcement, so their existing edges
49+ * 8. Views (`apps/sim/platform/embedded/app`) do not import `@/app/workspace`, not even for a type: each
50+ * edge is legacy code that a design-system view cannot be restyled without. Fix by moving the
51+ * shared part under `lib/` or `hooks/`.
52+ * 9. `apps/sim/platform/lib` takes the view models it fills from the views, by type. That makes rule 3
53+ * hold only at runtime for this layer. Fix by moving the model under `platform/lib/data`.
54+ *
55+ * Rules 1 to 3 and 7 have no allowlist. Rules 4 to 6, 8 and 9 predate their enforcement, so their existing edges
4856 * are counted per file in `scripts/check-monorepo-boundaries.baseline.json`, one section per rule. A
4957 * file above its count fails, and so does one below it until the baseline is rewritten, so the
5058 * baseline only shrinks. Regenerate after removing edges with `--update`, which refuses to raise a
@@ -61,6 +69,7 @@ const ROOT = path.resolve(import.meta.dir, '..')
6169const PACKAGES_DIR = path . join ( ROOT , 'packages' )
6270const SIM_DIR = path . join ( ROOT , 'apps/sim' )
6371const PLATFORM_DIR = path . join ( SIM_DIR , 'platform' )
72+ const ZONE_LIB_DIR = path . join ( PLATFORM_DIR , 'lib' )
6473const PLATFORM_LIB_DIR = path . join ( PLATFORM_DIR , 'embedded/lib' )
6574const PLATFORM_VIEWS_DIR = path . join ( SIM_DIR , 'platform/embedded/app' )
6675const EMBEDDED_DIR = path . join ( PLATFORM_DIR , 'embedded' )
@@ -121,7 +130,7 @@ function applicationViolation(
121130function viewSeamViolation ( specifier : string , bindings : readonly string [ ] | 'all' ) : string | null {
122131 if ( bindings !== 'all' && bindings . length === 0 ) return null
123132 if ( matchesModule ( specifier , '@/hooks/queries' ) || EE_DATA_HOOK . test ( specifier ) ) {
124- return `view reads a data hook around platform/lib/data: ${ specifier } `
133+ return `view reads a data hook around platform/embedded/ lib/data: ${ specifier } `
125134 }
126135 return null
127136}
@@ -276,7 +285,13 @@ async function sourceFiles(dir: string): Promise<string[]> {
276285 return ( await allFiles ( dir ) ) . filter ( ( file ) => ! TEST_FILE . test ( file ) )
277286}
278287
279- const SEAM_RATCHETS = [ 'viewDataHooks' , 'platformToRoutes' , 'platformLibToWorkspace' ] as const
288+ const SEAM_RATCHETS = [
289+ 'viewDataHooks' ,
290+ 'platformToRoutes' ,
291+ 'platformLibToWorkspace' ,
292+ 'viewsToWorkspace' ,
293+ 'zoneLibToViewTypes' ,
294+ ] as const
280295
281296type SeamRatchet = ( typeof SEAM_RATCHETS ) [ number ]
282297type SeamCounts = Record < string , number >
@@ -381,6 +396,8 @@ async function main() {
381396 viewDataHooks : [ ] ,
382397 platformToRoutes : [ ] ,
383398 platformLibToWorkspace : [ ] ,
399+ viewsToWorkspace : [ ] ,
400+ zoneLibToViewTypes : [ ] ,
384401 }
385402
386403 const platformLibFiles = await sourceFiles ( PLATFORM_LIB_DIR )
@@ -407,6 +424,29 @@ async function main() {
407424 )
408425 }
409426
427+ const zoneLibFiles = await sourceFiles ( ZONE_LIB_DIR )
428+ for ( const file of zoneLibFiles ) {
429+ offenders . push (
430+ ...( await scanImports ( file , ( { module, bindings } ) => {
431+ const specifier = aliasedSpecifier ( file , module . text )
432+ if ( matchesModule ( specifier , '@/app/o' ) ) return `platform/lib imports a route: ${ specifier } `
433+ const runtime = bindings === 'all' || bindings . length > 0
434+ return runtime && matchesModule ( specifier , '@/platform/app' )
435+ ? `platform/lib imports a view at runtime: ${ specifier } `
436+ : null
437+ } ) )
438+ )
439+ seamHits . zoneLibToViewTypes . push (
440+ ...( await scanImports ( file , ( { module, bindings } ) => {
441+ const specifier = aliasedSpecifier ( file , module . text )
442+ const typeOnly = bindings !== 'all' && bindings . length === 0
443+ return typeOnly && matchesModule ( specifier , '@/platform/app' )
444+ ? `platform/lib takes a view's type: ${ specifier } `
445+ : null
446+ } ) )
447+ )
448+ }
449+
410450 for ( const file of await allFiles ( PLATFORM_DIR ) ) {
411451 offenders . push (
412452 ...( await scanImports ( file , ( { module } ) =>
@@ -415,8 +455,9 @@ async function main() {
415455 )
416456 }
417457
458+ const zoneLibFileSet = new Set ( zoneLibFiles )
418459 for ( const file of await sourceFiles ( PLATFORM_DIR ) ) {
419- if ( platformLibFileSet . has ( file ) ) continue
460+ if ( platformLibFileSet . has ( file ) || zoneLibFileSet . has ( file ) ) continue
420461 seamHits . platformToRoutes . push (
421462 ...( await scanImports ( file , ( { module } ) => {
422463 const specifier = aliasedSpecifier ( file , module . text )
@@ -431,6 +472,14 @@ async function main() {
431472 viewSeamViolation ( aliasedSpecifier ( file , module . text ) , bindings )
432473 ) )
433474 )
475+ seamHits . viewsToWorkspace . push (
476+ ...( await scanImports ( file , ( { module } ) => {
477+ const specifier = aliasedSpecifier ( file , module . text )
478+ return matchesModule ( specifier , '@/app/workspace' )
479+ ? `view imports the workspace surface: ${ specifier } `
480+ : null
481+ } ) )
482+ )
434483 }
435484
436485 const baseline = readSeamBaseline ( )
@@ -459,7 +508,7 @@ async function main() {
459508 )
460509 if ( violations . length === 0 && dropped . length === 0 ) {
461510 console . log (
462- `✅ Monorepo boundaries OK: no package imports from apps/*, application code is surface-neutral, and platform/lib points away from views and routes (${ edgeCount } seam edges baselined)`
511+ `✅ Monorepo boundaries OK: no package imports from apps/*, application code is surface-neutral, the zone and the organization views stay apart, and both data layers point away from views and routes (${ edgeCount } seam edges baselined)`
463512 )
464513 return
465514 }
0 commit comments