Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,35 @@ Coding Code 是 AI 编程助手。
- 修改过程中发现错误,如果是本次范围就修改(包括测试),否则要在最后指出
- 仅允许使用简短注释

## 测试规则

**唯一判据**:改生产代码的逻辑,测试必须失败;改不影响行为的文案、命名、注释、格式,测试不应失败。不满足此判据的用例一律不写。

**该怎么写**:

- 只断言可观察的行为:给定输入 → 返回值、副作用、状态变化、抛出的错误。断言对象是生产代码的结果,不是测试里自造的数据。
- 采用 Arrange-Act-Assert:一段准备、一段触发、一段断言,一个用例只验证一个概念。
- 用例名描述行为与预期,不描述实现细节。
- 覆盖边界与失败路径(边界值、空集合、错误分支),这里才是缺陷高发区。
- 按层级选择:纯函数用单元测试;跨模块链路用集成测试(mock 掉外部依赖如 LLM),验证真实装配后的端到端行为。

**禁止写的类型**:

1. 文案 / 提示词断言——断言提示词、系统说明、注释、UI 文案包含或不再包含某个字符串。提示词是产品内容,其变更由人工评审守护,不写成测试。
2. 类型形状断言——运行时断言某字面量有哪些字段、字段是什么类型。类型正确性由 `tsc` 保证,这类断言恒真且零信息量;确需钉住类型时用编译期的 `@ts-expect-error` / `expectTypeOf`,不要写成运行时 `expect`。
3. 存在性 / 导出断言——断言文件存在、类 / 函数 / layer 已导出、方法存在。真断裂时编译与上层用例会同时失败,此类用例不提供额外信息。
4. 常量钉死——断言常量等于它自身的字面量。需要守护的是行为,不是常量的副本。
5. 测试内重新实现逻辑——在测试里重写一遍待测算法再断言自己写的副本,只证明写法一致,发现不了实现缺陷。
6. 源码文本 / 结构扫描——用字符串或正则解析源码断言导入、布局或写法。这属于静态分析:类型与导入可解析性由 `tsc` 保证,无需重复;架构分层等 `tsc` 无法表达的约束,改用 ESLint 规则或 AST 解析,而不是正则匹配源码文本(现有 `test/architecture/boundaries.test.ts`、`test/hooks/points-coverage.test.ts` 应按此方向迁移)。
7. 占位 / 恒真断言——`expect(true).toBe(true)`、只 `toBeDefined()` 不校验值、以及无论如何都会通过的断言。
8. 重复用例——与已有用例覆盖同一行为的副本;发现重复应合并,不要并存。

**其他**:

- 测试必须独立、确定、可任意顺序执行,不依赖执行顺序或共享可变状态(每个用例自备数据并自行清理)。
- 不为「将来可能的变化」预留用例,只覆盖当前真实存在的行为。
- 新增 / 删除测试前先取得用户许可(见「开发规则」)。

## 其他规则

- 用户要求回答问题时,必须清晰回答每一点问题,不得遗漏
Expand Down
29 changes: 29 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,35 @@ Coding Code 是 AI 编程助手。
- 修改过程中发现错误,如果是本次范围就修改(包括测试),否则要在最后指出
- 仅允许使用简短注释

## 测试规则

**唯一判据**:改生产代码的逻辑,测试必须失败;改不影响行为的文案、命名、注释、格式,测试不应失败。不满足此判据的用例一律不写。

**该怎么写**:

- 只断言可观察的行为:给定输入 → 返回值、副作用、状态变化、抛出的错误。断言对象是生产代码的结果,不是测试里自造的数据。
- 采用 Arrange-Act-Assert:一段准备、一段触发、一段断言,一个用例只验证一个概念。
- 用例名描述行为与预期,不描述实现细节。
- 覆盖边界与失败路径(边界值、空集合、错误分支),这里才是缺陷高发区。
- 按层级选择:纯函数用单元测试;跨模块链路用集成测试(mock 掉外部依赖如 LLM),验证真实装配后的端到端行为。

**禁止写的类型**:

1. 文案 / 提示词断言——断言提示词、系统说明、注释、UI 文案包含或不再包含某个字符串。提示词是产品内容,其变更由人工评审守护,不写成测试。
2. 类型形状断言——运行时断言某字面量有哪些字段、字段是什么类型。类型正确性由 `tsc` 保证,这类断言恒真且零信息量;确需钉住类型时用编译期的 `@ts-expect-error` / `expectTypeOf`,不要写成运行时 `expect`。
3. 存在性 / 导出断言——断言文件存在、类 / 函数 / layer 已导出、方法存在。真断裂时编译与上层用例会同时失败,此类用例不提供额外信息。
4. 常量钉死——断言常量等于它自身的字面量。需要守护的是行为,不是常量的副本。
5. 测试内重新实现逻辑——在测试里重写一遍待测算法再断言自己写的副本,只证明写法一致,发现不了实现缺陷。
6. 源码文本 / 结构扫描——用字符串或正则解析源码断言导入、布局或写法。这属于静态分析:类型与导入可解析性由 `tsc` 保证,无需重复;架构分层等 `tsc` 无法表达的约束,改用 ESLint 规则或 AST 解析,而不是正则匹配源码文本(现有 `test/architecture/boundaries.test.ts`、`test/hooks/points-coverage.test.ts` 应按此方向迁移)。
7. 占位 / 恒真断言——`expect(true).toBe(true)`、只 `toBeDefined()` 不校验值、以及无论如何都会通过的断言。
8. 重复用例——与已有用例覆盖同一行为的副本;发现重复应合并,不要并存。

**其他**:

- 测试必须独立、确定、可任意顺序执行,不依赖执行顺序或共享可变状态(每个用例自备数据并自行清理)。
- 不为「将来可能的变化」预留用例,只覆盖当前真实存在的行为。
- 新增 / 删除测试前先取得用户许可(见「开发规则」)。

## 其他规则

- 用户要求回答问题时,必须清晰回答每一点问题,不得遗漏
Expand Down
64 changes: 0 additions & 64 deletions packages/codingcode/test/agent/agent-cache-stability.test.ts

This file was deleted.

13 changes: 0 additions & 13 deletions packages/codingcode/test/agent/agent-profile-filter.test.ts

This file was deleted.

67 changes: 0 additions & 67 deletions packages/codingcode/test/agent/build-system-prompt.test.ts

This file was deleted.

27 changes: 2 additions & 25 deletions packages/codingcode/test/agent/memory-snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ function makeStateForMemory() {
}

function makeCapturingLlm() {
const captured: { system?: string; messages?: any[] } = {};
const captured: { system?: string } = {};
const llm = {
completeStream: vi.fn((params: any) => {
captured.system = params.system;
captured.messages = params.messages;
return llmStream(pEnd());
}),
modelInfo: { maxTokens: 1000 },
Expand All @@ -45,31 +44,9 @@ async function runOnce(llm: any, memorySnapshot: string = '') {
}

describe('Memory snapshot semantics', () => {
it('loads memory via MemoryPort and includes it in the system prompt', async () => {
it('injects the provided memory snapshot into the system prompt', async () => {
const { llm, captured } = makeCapturingLlm();
await runOnce(llm, MEMORY);
expect(captured.system).toContain('## Session Memory');
expect(captured.system).toContain('Frozen content');
});

it('system prompt is byte-identical across consecutive turns with the same memory snapshot', async () => {
const { llm, captured } = makeCapturingLlm();
await runOnce(llm, MEMORY);
const first = captured.system;
expect(first).toBeDefined();
await runOnce(llm, MEMORY);
const second = captured.system;
expect(second).toBe(first);
});

it('appends memory verbatim and does not inject <system-reminder> into messages', async () => {
const { llm, captured } = makeCapturingLlm();
await runOnce(llm, MEMORY);
// memory 块原样拼在 "## Session Memory" 标题之后,中间无注入的 reminder 包装
expect(captured.system).toContain('## Session Memory\n\n## Long-term Memory\n\nFrozen content');
const allContents = (captured.messages ?? [])
.map((m: any) => (typeof m.content === 'string' ? m.content : JSON.stringify(m.content)))
.join('\n');
expect(allContents).not.toContain('<system-reminder>');
});
});
35 changes: 0 additions & 35 deletions packages/codingcode/test/agent/message-tool-calls.test.ts

This file was deleted.

54 changes: 0 additions & 54 deletions packages/codingcode/test/agent/stop-decision-type.test.ts

This file was deleted.

Loading
Loading