diff --git a/eslint.config.mjs b/eslint.config.mjs index ba79f9d5..9beadc1a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -28,6 +28,14 @@ const chatSignalAdapterRestrictions = [ message: "Keep chat signals in panel/shell-state.tsx as a reducer-to-Preact notification adapter.", }, ]; +const chatDomainLayerRestrictions = [ + { + selector: + "ImportDeclaration[source.value=/^(?:\\.\\.\\/)+(?:app-server|application|host|panel|presentation|ui)(?:\\/|$)|^src\\/features\\/chat\\/(?:app-server|application|host|panel|presentation|ui)(?:\\/|$)/]", + message: + "Keep chat/domain as Panel-owned meaning models and pure derivations; app-server, application, host, panel, presentation, and UI layers may depend on domain, not the reverse.", + }, +]; const uiRootImportRestrictions = [ { selector: "ImportDeclaration[source.value=/shared\\/ui\\/ui-root$/]", @@ -684,6 +692,10 @@ export default defineConfig([ "codex-panel/no-chat-state-direct-mutation": "error", }, }, + { + files: ["src/features/chat/domain/**/*.{ts,tsx}"], + rules: restrictedSyntaxRule([...sourceSyntaxRestrictions, ...chatDomainLayerRestrictions]), + }, { files: ["src/app-server/**/*.{ts,tsx}", "src/domain/**/*.{ts,tsx}", "src/shared/**/*.{ts,tsx}"], rules: { diff --git a/tests/scripts/eslint-config.test.ts b/tests/scripts/eslint-config.test.ts index 451f4fca..13916b12 100644 --- a/tests/scripts/eslint-config.test.ts +++ b/tests/scripts/eslint-config.test.ts @@ -362,6 +362,32 @@ export function timestamp(): number { expect(messages).toContain("no-restricted-syntax"); }); + + it("keeps chat domain independent from outer chat layers", async () => { + const messages = await lintSource( + "src/features/chat/domain/message-stream/selectors.ts", + ` +import type { ChatStateStore } from "../../application/state/reducer"; + +export type Store = ChatStateStore; +`, + ); + + expect(messages).toContain("no-restricted-syntax"); + }); + + it("allows chat domain modules to depend on sibling domain modules", async () => { + const messages = await lintSource( + "src/features/chat/domain/message-stream/selectors.ts", + ` +import type { MessageStreamItem } from "./items"; + +export type Item = MessageStreamItem; +`, + ); + + expect(messages).not.toContain("no-restricted-syntax"); + }); }); async function lintSource(filePath: string, source: string): Promise {