From 82ef80ece4abc2ac82e54da19ac1651de7d756b5 Mon Sep 17 00:00:00 2001 From: murashit Date: Tue, 30 Jun 2026 19:03:04 +0900 Subject: [PATCH] Enforce app-server RPC boundary policy --- biome.jsonc | 4 +-- .../runtime/no-app-server-direct-rpcs.grit | 5 +++ .../no-app-server-projection-rpcs.grit | 11 ------ tests/scripts/grit-policy.test.mjs | 36 +++++++++++++++---- 4 files changed, 37 insertions(+), 19 deletions(-) create mode 100644 scripts/grit/runtime/no-app-server-direct-rpcs.grit delete mode 100644 scripts/grit/runtime/no-app-server-projection-rpcs.grit diff --git a/biome.jsonc b/biome.jsonc index 0bea0352..056f6837 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -86,8 +86,8 @@ ] }, { - "path": "./scripts/grit/runtime/no-app-server-projection-rpcs.grit", - "includes": ["**/src/features/chat/application/**/*.ts"] + "path": "./scripts/grit/runtime/no-app-server-direct-rpcs.grit", + "includes": ["**/src/**/*.ts", "**/src/**/*.tsx", "!**/src/app-server/**", "!**/src/features/chat/app-server/**"] }, // Workspace and feature coordination boundaries. { diff --git a/scripts/grit/runtime/no-app-server-direct-rpcs.grit b/scripts/grit/runtime/no-app-server-direct-rpcs.grit new file mode 100644 index 00000000..db3029e3 --- /dev/null +++ b/scripts/grit/runtime/no-app-server-direct-rpcs.grit @@ -0,0 +1,5 @@ +language js + +`$target.request($...)` as $stmt where { + register_diagnostic(span=$stmt, message="Keep direct app-server RPC calls behind app-server services and chat app-server adapters.", severity="error") +} diff --git a/scripts/grit/runtime/no-app-server-projection-rpcs.grit b/scripts/grit/runtime/no-app-server-projection-rpcs.grit deleted file mode 100644 index 096f142e..00000000 --- a/scripts/grit/runtime/no-app-server-projection-rpcs.grit +++ /dev/null @@ -1,11 +0,0 @@ -language js - -or { - `$client.request("thread/resume", $...)` as $stmt, - `$client.request("thread/turns/list", $...)` as $stmt, - `$client.request("thread/fork", $...)` as $stmt, - `$client.request("thread/rollback", $...)` as $stmt -} where { - $client <: r"^(?:client|[A-Za-z_$][A-Za-z0-9_$]*Client)$", - register_diagnostic(span=$stmt, message="Keep app-server projection RPCs behind app-server facades; consume Panel-owned snapshots or view models here.", severity="error") -} diff --git a/tests/scripts/grit-policy.test.mjs b/tests/scripts/grit-policy.test.mjs index fc031078..53151997 100644 --- a/tests/scripts/grit-policy.test.mjs +++ b/tests/scripts/grit-policy.test.mjs @@ -42,6 +42,7 @@ const DOM_EVENTS_IMPORT_MESSAGE = "Import DOM event listener helpers only from e const CHAT_SHELL_READ_MODEL_IMPORT_MESSAGE = "Import chat panel signal read models only from the shell and panel surface rendering adapters."; const CHAT_SIGNAL_TYPE_REFERENCE_MESSAGE = "Keep Preact signal types inside the chat panel read-model and surface rendering adapter layer."; +const APP_SERVER_DIRECT_RPC_MESSAGE = "Keep direct app-server RPC calls behind app-server services and chat app-server adapters."; let appServerBoundaryPolicyReportPromise; let renderingAndCssPolicyReportPromise; @@ -950,14 +951,14 @@ export const read = listThreads; expect(pluginDiagnostics(report, "src/app-server/services/allowed.ts")).toEqual([]); }); - it("keeps chat application app-server projection RPCs behind facades", async () => { + it("keeps direct app-server RPCs behind app-server boundary adapters", async () => { const report = await appServerBoundaryPolicyReport(); - expect(pluginMessages(report, "src/features/chat/application/threads/history.ts")).toEqual([ - "Keep app-server projection RPCs behind app-server facades; consume Panel-owned snapshots or view models here.", - ]); + expect(pluginMessages(report, "src/features/chat/application/threads/history.ts")).toEqual([APP_SERVER_DIRECT_RPC_MESSAGE]); + expect(pluginMessages(report, "src/features/chat/host/bundles/connection-bundle.ts")).toEqual([APP_SERVER_DIRECT_RPC_MESSAGE]); + expect(pluginMessages(report, "src/settings/runtime-config.ts")).toEqual([APP_SERVER_DIRECT_RPC_MESSAGE]); expect(pluginDiagnostics(report, "src/app-server/services/threads.ts")).toEqual([]); - expect(pluginDiagnostics(report, "src/features/chat/host/bundles/connection-bundle.ts")).toEqual([]); + expect(pluginDiagnostics(report, "src/features/chat/app-server/transports/threads.ts")).toEqual([]); }); it("keeps CSS on design tokens and scoped selectors", async () => { @@ -1126,7 +1127,7 @@ async function createAppServerBoundaryPolicyReport() { "no-domain-outer-layer-imports.grit", "no-lower-level-feature-imports.grit", "no-app-server-connection-boundary-imports.grit", - "no-app-server-projection-rpcs.grit", + "no-app-server-direct-rpcs.grit", ]); await writeFile( path.join(cwd, "src/features/chat/domain/generated-thread.ts"), @@ -1397,6 +1398,27 @@ import type { AppServerClient } from "../../../../app-server/connection/client"; export async function resume(client: AppServerClient): Promise { await client.request("thread/resume", { threadId: "thread", cwd: "/vault" }); } +`.trimStart(), + ); + await writeFile( + path.join(cwd, "src/settings/runtime-config.ts"), + ` +import type { AppServerClient } from "../app-server/connection/client"; + +export async function read(client: AppServerClient): Promise { + await client.request("config/read", { cwd: "/vault", includeLayers: true }); +} +`.trimStart(), + ); + await mkdir(path.join(cwd, "src/features/chat/app-server/transports"), { recursive: true }); + await writeFile( + path.join(cwd, "src/features/chat/app-server/transports/threads.ts"), + ` +import type { AppServerClient } from "../../../../app-server/connection/client"; + +export async function read(client: AppServerClient): Promise { + await client.request("thread/turns/list", { threadId: "thread", cursor: null, limit: 20 }); +} `.trimStart(), ); return biomeLint( @@ -1431,6 +1453,8 @@ export async function resume(client: AppServerClient): Promise { "src/features/chat/application/threads/history.ts", "src/app-server/services/threads.ts", "src/features/chat/host/bundles/connection-bundle.ts", + "src/settings/runtime-config.ts", + "src/features/chat/app-server/transports/threads.ts", ], cwd, );