perf: simplify tsgo test lanes

This commit is contained in:
Peter Steinberger
2026-04-18 23:16:38 +01:00
parent 9a94194329
commit 6fb74d4985
6 changed files with 44 additions and 25 deletions

View File

@@ -127,14 +127,13 @@
- Node remains supported for running built output (`dist/*`) and production installs.
- Mac packaging (dev): `scripts/package-mac-app.sh` defaults to current arch.
- Type-check/build: `pnpm build`
- TypeScript checks are split by architecture boundary:
- TypeScript checks are split by architecture boundary, with four normal lanes:
- `pnpm tsgo` / `pnpm tsgo:core`: core production roots (`src/`, `ui/`, `packages/`; no `extensions/` include roots).
- `pnpm tsgo:core:test`: core colocated tests.
- `pnpm tsgo:core:test:agents` / `pnpm tsgo:core:test:non-agents`: core test slices for isolating the heavy agent graph while debugging type-check performance.
- `pnpm tsgo:extensions`: bundled extension production graph.
- `pnpm tsgo:extensions:test`: bundled extension colocated tests.
- `pnpm tsgo:all`: every TypeScript graph above; this is what `pnpm check` runs.
- `pnpm tsgo:profile [core-test|core-test-agents|core-test-non-agents|extensions-test|--all]`: profile fresh graph cost into `.artifacts/tsgo-profile/`; if a core graph lists `extensions/<id>/`, treat that as boundary/perf debt from imports (usually plugin-sdk facades or shared helpers pulling extension sources).
- `pnpm tsgo:profile [core-test|extensions-test|--all]`: profile fresh graph cost into `.artifacts/tsgo-profile/`. Diagnostic-only profile slices (`core-test-agents`, `core-test-non-agents`) exist for investigating agent graph cost; do not treat them as normal user-facing checks.
- Narrow aliases remain for local loops: `pnpm tsgo:test:src`, `pnpm tsgo:test:ui`, `pnpm tsgo:test:packages`.
- Do not add `tsc --noEmit`, `typecheck`, or `check:types` lanes for repo type checking. Use `tsgo` graphs. `tsc` is allowed only when emitting declaration/package-boundary compatibility artifacts that `tsgo` does not replace.
- Boundary rule: core must not know extension implementation details. Extensions hook into core through manifests, registries, capabilities, and public `openclaw/plugin-sdk/*` contracts. If you find core production code naming a specific extension, or a core test that is really testing extension-owned behavior, call it out and prefer moving coverage/logic to the owning extension or a generic contract test.

View File

@@ -1474,8 +1474,6 @@
"tsgo:all": "pnpm tsgo:core && pnpm tsgo:core:test && pnpm tsgo:extensions && pnpm tsgo:extensions:test",
"tsgo:core": "node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo",
"tsgo:core:test": "node scripts/run-tsgo.mjs -p tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo",
"tsgo:core:test:agents": "node scripts/run-tsgo.mjs -p tsconfig.core.test.agents.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test-agents.tsbuildinfo",
"tsgo:core:test:non-agents": "node scripts/run-tsgo.mjs -p tsconfig.core.test.non-agents.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test-non-agents.tsbuildinfo",
"tsgo:extensions": "node scripts/run-tsgo.mjs -p tsconfig.extensions.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions.tsbuildinfo",
"tsgo:extensions:test": "node scripts/run-tsgo.mjs -p tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo",
"tsgo:prod": "pnpm tsgo:core && pnpm tsgo:extensions",

View File

@@ -24,11 +24,11 @@ const GRAPH_DEFINITIONS = {
},
"core-test-agents": {
config: "tsconfig.core.test.agents.json",
description: "core agent colocated test graph",
description: "diagnostic slice: core agent colocated tests",
},
"core-test-non-agents": {
config: "tsconfig.core.test.non-agents.json",
description: "core non-agent colocated test graph",
description: "diagnostic slice: core tests excluding agent test roots",
},
extensions: {
config: "tsconfig.extensions.json",

View File

@@ -1,4 +1,3 @@
import { Container, Separator, TextDisplay } from "@buape/carbon";
import { beforeEach, describe, expect, it } from "vitest";
import type { ChannelPlugin } from "../../channels/plugins/types.js";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
@@ -8,7 +7,17 @@ import {
} from "../../test-utils/channel-plugins.js";
import { getChannelMessageAdapter } from "./channel-adapters.js";
class TestDiscordUiContainer extends Container {}
class TestTextDisplay {
constructor(readonly content: string) {}
}
class TestSeparator {
constructor(readonly options: { divider: boolean; spacing: string }) {}
}
class TestDiscordUiContainer {
constructor(readonly components: Array<TestTextDisplay | TestSeparator>) {}
}
const discordCrossContextPlugin: Pick<
ChannelPlugin,
@@ -18,12 +27,12 @@ const discordCrossContextPlugin: Pick<
messaging: {
buildCrossContextComponents: ({ originLabel, message, cfg, accountId }) => {
const trimmed = message.trim();
const components: Array<TextDisplay | Separator> = [];
const components: Array<TestTextDisplay | TestSeparator> = [];
if (trimmed) {
components.push(new TextDisplay(message));
components.push(new Separator({ divider: true, spacing: "small" }));
components.push(new TestTextDisplay(message));
components.push(new TestSeparator({ divider: true, spacing: "small" }));
}
components.push(new TextDisplay(`*From ${originLabel}*`));
components.push(new TestTextDisplay(`*From ${originLabel}*`));
void cfg;
void accountId;
return [new TestDiscordUiContainer(components)];
@@ -68,9 +77,9 @@ describe("getChannelMessageAdapter", () => {
expect(components).toHaveLength(1);
expect(container).toBeInstanceOf(TestDiscordUiContainer);
expect(container?.components).toEqual([
expect.any(TextDisplay),
expect.any(Separator),
expect.any(TextDisplay),
expect.any(TestTextDisplay),
expect.any(TestSeparator),
expect.any(TestTextDisplay),
]);
});
@@ -79,12 +88,16 @@ describe("getChannelMessageAdapter", () => {
message: "Hello from chat",
originLabel: "Telegram",
accountId: "primary",
expectedComponents: [expect.any(TextDisplay), expect.any(Separator), expect.any(TextDisplay)],
expectedComponents: [
expect.any(TestTextDisplay),
expect.any(TestSeparator),
expect.any(TestTextDisplay),
],
},
{
message: " ",
originLabel: "Signal",
expectedComponents: [expect.any(TextDisplay)],
expectedComponents: [expect.any(TestTextDisplay)],
},
])(
"builds cross-context components for %j",

View File

@@ -1,4 +1,3 @@
import { Container, Separator, TextDisplay } from "@buape/carbon";
import { beforeAll, beforeEach, describe, expect, it } from "vitest";
import { vi } from "vitest";
import type { ChannelMessageActionName } from "../../channels/plugins/types.js";
@@ -9,7 +8,17 @@ let buildCrossContextDecoration: typeof import("./outbound-policy.js").buildCros
let enforceCrossContextPolicy: typeof import("./outbound-policy.js").enforceCrossContextPolicy;
let shouldApplyCrossContextMarker: typeof import("./outbound-policy.js").shouldApplyCrossContextMarker;
class TestDiscordUiContainer extends Container {}
class TestTextDisplay {
constructor(readonly content: string) {}
}
class TestSeparator {
constructor(readonly options: { divider: boolean; spacing: string }) {}
}
class TestDiscordUiContainer {
constructor(readonly components: Array<TestTextDisplay | TestSeparator>) {}
}
const mocks = vi.hoisted(() => ({
getChannelMessageAdapter: vi.fn((channel: string) =>
@@ -24,12 +33,12 @@ const mocks = vi.hoisted(() => ({
message: string;
}) => {
const trimmed = message.trim();
const components: Array<TextDisplay | Separator> = [];
const components: Array<TestTextDisplay | TestSeparator> = [];
if (trimmed) {
components.push(new TextDisplay(message));
components.push(new Separator({ divider: true, spacing: "small" }));
components.push(new TestTextDisplay(message));
components.push(new TestSeparator({ divider: true, spacing: "small" }));
}
components.push(new TextDisplay(`*From ${originLabel}*`));
components.push(new TestTextDisplay(`*From ${originLabel}*`));
return [new TestDiscordUiContainer(components)];
},
}

View File

@@ -1,4 +1,4 @@
import "@mariozechner/pi-coding-agent";
export type OpenClawPiCodingAgentSkillSourceAugmentation = never;
declare module "@mariozechner/pi-coding-agent" {
interface Skill {