guarantee-based-coding 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/LICENSE +0 -0
- {guarantee_based_coding-0.2.2/guarantee_based_coding.egg-info → guarantee_based_coding-0.2.3}/PKG-INFO +108 -108
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/README.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/__init__.py +1 -1
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/assets.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/config/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/config/backups.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/config/base.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/config/executor.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/config/project.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/core/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/core/env.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/core/executor.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/core/guarantee.py +12 -5
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/i18n/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/i18n/lang.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/i18n/translate.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/intent/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/intent/base.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/intent/cli.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/intent/editor.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/interface/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/interface/base.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/interface/cli.py +6 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/interface/mcp.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/models/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/models/errors.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/models/meta.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/models/verify.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/__init__.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/file_utils.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/gbc_md.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/json_model_operator.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/safe_file_writer.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/app.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/css/foundation.css +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/css/review.css +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/css/workspace.css +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/i18n.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/index.html +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/actions.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/api.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/diff.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/dom.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/editor-view.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/review-view.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/semantic.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/state.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/tree-view.js +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/catalog/en.json +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/catalog/zh.json +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/rules.en.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/rules.zh.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/setup.en.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/setup.zh.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/skills/README.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/skills/gbc-cli/SKILL.md +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/entry.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3/guarantee_based_coding.egg-info}/PKG-INFO +108 -108
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/pyproject.toml +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/setup.cfg +4 -4
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_assets.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_cli_commands.py +104 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_config_project.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_core_executor.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_env_actions.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_errors_i18n.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_executor_externalized.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_gbc_md.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_guarantee_crud.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_guarantee_deps.py +84 -1
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_guarantee_verify.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_i18n.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_intent_base.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_intent_editor_api.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_intent_flat.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_crud.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_deps.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_query.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_refactor.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_json_model_and_file_utils.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_mcp_doc_tools.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_safe_file_writer.py +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/guarantee_based_coding.egg-info/SOURCES.txt +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/guarantee_based_coding.egg-info/dependency_links.txt +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/guarantee_based_coding.egg-info/entry_points.txt +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/guarantee_based_coding.egg-info/requires.txt +0 -0
- {guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/guarantee_based_coding.egg-info/top_level.txt +0 -0
|
File without changes
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: guarantee-based-coding
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Make code safely modifiable even when not fully understood — turn implicit inter-module dependencies into explicit, executable, verifiable guarantees.
|
|
5
|
-
Author: Jesse-x86
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/Jesse-x86/guarantee-based-coding
|
|
8
|
-
Project-URL: Repository, https://github.com/Jesse-x86/guarantee-based-coding
|
|
9
|
-
Keywords: guarantee,testing,ai-coding,mcp,code-safety
|
|
10
|
-
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Topic :: Software Development :: Testing
|
|
14
|
-
Requires-Python: >=3.10
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
License-File: LICENSE
|
|
17
|
-
Requires-Dist: typer[all]
|
|
18
|
-
Requires-Dist: pydantic
|
|
19
|
-
Requires-Dist: mcp<2.0,>=1.0
|
|
20
|
-
Dynamic: license-file
|
|
21
|
-
|
|
22
|
-
# Guarantee-Based Coding (GBC)
|
|
23
|
-
|
|
24
|
-
**与其指望 AI 更聪明,不如让再笨的 agent 也改不坏你的代码。**
|
|
25
|
-
|
|
26
|
-
**English version: [docs/en/README.md](docs/en/README.md)**
|
|
27
|
-
|
|
28
|
-
GBC 把「这次改动会不会悄悄碰坏别处」从一种担心,变成可以当场验证的事实:你在意的行为被登记成
|
|
29
|
-
一条条带测试的**保证(guarantee)**,每次改完一跑——全绿就安心,有红就精确告诉你碰坏了谁、谁在
|
|
30
|
-
依赖它。
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 🚀 快速开始
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
pipx install guarantee-based-coding
|
|
38
|
-
gbc setup # 打印本地化接线指南:怎么把 MCP / skills 接入你的 agent
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
装好后 `gbc` 命令即在 PATH 上。完整上手(安装 → 接入 agent → 冒烟验证)见
|
|
42
|
-
**[docs/zh/quick-start.md](./docs/zh/quick-start.md)**。
|
|
43
|
-
|
|
44
|
-
想让 agent 替你接入?把 **[docs/zh/onboarding-agent.md](./docs/zh/onboarding-agent.md)** 交给它。
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
> 🚧 **交互式 demo 施工中**:旧的演示套件已废弃,新的交互式演示正在筹备。目前请直接读文档上手。
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## 📚 文档
|
|
53
|
-
|
|
54
|
-
| 你想 | 看这里 |
|
|
55
|
-
|------|--------|
|
|
56
|
-
| 装好并跑起来 | [快速开始](./docs/zh/quick-start.md) |
|
|
57
|
-
| 懂 GBC 在保护什么 | [核心概念](./docs/zh/concepts.md) |
|
|
58
|
-
| 在 GBC 下安全改代码 | [工作流](./docs/zh/workflow.md) |
|
|
59
|
-
| 查命令 / 工具 / executor | [参考手册](./docs/zh/reference.md) |
|
|
60
|
-
| 你是 agent,被要求接入 GBC | [Agent 上手](./docs/zh/onboarding-agent.md) |
|
|
61
|
-
|
|
62
|
-
English docs: [docs/en/](./docs/en/)。
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 核心想法
|
|
67
|
-
|
|
68
|
-
代码之间的依赖本质上是一组**保证**。模块 A 依赖模块 B,不是依赖它的实现细节,而是依赖它的某些
|
|
69
|
-
行为承诺——返回值的类型、格式、语义。把这些保证从隐含变成**显式、可执行、可验证**,正确性的判定
|
|
70
|
-
就从「AI 觉得自己改对了」变成「所有被依赖的保证仍通过」——一个可机械验证的布尔条件。
|
|
71
|
-
|
|
72
|
-

|
|
73
|
-
|
|
74
|
-
GBC **不是**另一个要挑战 Cursor / Aider 的 AI 编程助手,而是填补它们在大型项目里缺的一环:
|
|
75
|
-
**机器可判定的变更边界**。它与那些 agent 配合——改前查依赖树,改后必须跑通所有相关保证;也区别
|
|
76
|
-
于 CI——CI 是事后的,GBC 是准入制的门禁,错误在落地前就被拦在 agent 的上下文里。
|
|
77
|
-
|
|
78
|
-
完整概念、架构图、与已有概念(Design by Contract / 测试)的区别,见
|
|
79
|
-
[核心概念](./docs/zh/concepts.md)。
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## 当前状态
|
|
84
|
-
|
|
85
|
-
GBC 目前是一个可用的 Python 分发包(`pipx install guarantee-based-coding`),自身用 GBC 管理自己的
|
|
86
|
-
`.gbc/`(dogfooding):
|
|
87
|
-
|
|
88
|
-
- ✅ 核心保证机制(具名 id、多对一、出生即绿、退休保护、反查)
|
|
89
|
-
- ✅ 多语言 executor 配置
|
|
90
|
-
- ✅ CLI + MCP 双接口(含意图文档 `gbc doc` 全进 MCP)
|
|
91
|
-
- ✅ 意图文档子系统(`gbc doc` / web 编辑器)
|
|
92
|
-
- ✅ 随包分发的接线指南(`gbc setup`)与 CLI-only agent 的 skill 包
|
|
93
|
-
- ✅ 原子文件写入 + 备份
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
**诚实的局限**:保护能力上限 = 测试质量(测试只走 happy path 就是虚假安全感);依赖需主动登记,
|
|
97
|
-
覆盖率随项目增长需持续投入;每次验证真实跑测试,有一定延迟。详见
|
|
98
|
-
[核心概念 · 局限性](./docs/zh/concepts.md#局限性诚实地说)。
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 许可
|
|
103
|
-
|
|
104
|
-
本项目采用 [Apache-2.0](./LICENSE) 许可证。
|
|
105
|
-
|
|
106
|
-
## 联系
|
|
107
|
-
|
|
108
|
-
如果你对这个方向感兴趣,欢迎 star、issue 或者直接联系我。
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: guarantee-based-coding
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Make code safely modifiable even when not fully understood — turn implicit inter-module dependencies into explicit, executable, verifiable guarantees.
|
|
5
|
+
Author: Jesse-x86
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/Jesse-x86/guarantee-based-coding
|
|
8
|
+
Project-URL: Repository, https://github.com/Jesse-x86/guarantee-based-coding
|
|
9
|
+
Keywords: guarantee,testing,ai-coding,mcp,code-safety
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development :: Testing
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: typer[all]
|
|
18
|
+
Requires-Dist: pydantic
|
|
19
|
+
Requires-Dist: mcp<2.0,>=1.0
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Guarantee-Based Coding (GBC)
|
|
23
|
+
|
|
24
|
+
**与其指望 AI 更聪明,不如让再笨的 agent 也改不坏你的代码。**
|
|
25
|
+
|
|
26
|
+
**English version: [docs/en/README.md](docs/en/README.md)**
|
|
27
|
+
|
|
28
|
+
GBC 把「这次改动会不会悄悄碰坏别处」从一种担心,变成可以当场验证的事实:你在意的行为被登记成
|
|
29
|
+
一条条带测试的**保证(guarantee)**,每次改完一跑——全绿就安心,有红就精确告诉你碰坏了谁、谁在
|
|
30
|
+
依赖它。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🚀 快速开始
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pipx install guarantee-based-coding
|
|
38
|
+
gbc setup # 打印本地化接线指南:怎么把 MCP / skills 接入你的 agent
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
装好后 `gbc` 命令即在 PATH 上。完整上手(安装 → 接入 agent → 冒烟验证)见
|
|
42
|
+
**[docs/zh/quick-start.md](./docs/zh/quick-start.md)**。
|
|
43
|
+
|
|
44
|
+
想让 agent 替你接入?把 **[docs/zh/onboarding-agent.md](./docs/zh/onboarding-agent.md)** 交给它。
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
> 🚧 **交互式 demo 施工中**:旧的演示套件已废弃,新的交互式演示正在筹备。目前请直接读文档上手。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📚 文档
|
|
53
|
+
|
|
54
|
+
| 你想 | 看这里 |
|
|
55
|
+
|------|--------|
|
|
56
|
+
| 装好并跑起来 | [快速开始](./docs/zh/quick-start.md) |
|
|
57
|
+
| 懂 GBC 在保护什么 | [核心概念](./docs/zh/concepts.md) |
|
|
58
|
+
| 在 GBC 下安全改代码 | [工作流](./docs/zh/workflow.md) |
|
|
59
|
+
| 查命令 / 工具 / executor | [参考手册](./docs/zh/reference.md) |
|
|
60
|
+
| 你是 agent,被要求接入 GBC | [Agent 上手](./docs/zh/onboarding-agent.md) |
|
|
61
|
+
|
|
62
|
+
English docs: [docs/en/](./docs/en/)。
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 核心想法
|
|
67
|
+
|
|
68
|
+
代码之间的依赖本质上是一组**保证**。模块 A 依赖模块 B,不是依赖它的实现细节,而是依赖它的某些
|
|
69
|
+
行为承诺——返回值的类型、格式、语义。把这些保证从隐含变成**显式、可执行、可验证**,正确性的判定
|
|
70
|
+
就从「AI 觉得自己改对了」变成「所有被依赖的保证仍通过」——一个可机械验证的布尔条件。
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
GBC **不是**另一个要挑战 Cursor / Aider 的 AI 编程助手,而是填补它们在大型项目里缺的一环:
|
|
75
|
+
**机器可判定的变更边界**。它与那些 agent 配合——改前查依赖树,改后必须跑通所有相关保证;也区别
|
|
76
|
+
于 CI——CI 是事后的,GBC 是准入制的门禁,错误在落地前就被拦在 agent 的上下文里。
|
|
77
|
+
|
|
78
|
+
完整概念、架构图、与已有概念(Design by Contract / 测试)的区别,见
|
|
79
|
+
[核心概念](./docs/zh/concepts.md)。
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 当前状态
|
|
84
|
+
|
|
85
|
+
GBC 目前是一个可用的 Python 分发包(`pipx install guarantee-based-coding`),自身用 GBC 管理自己的
|
|
86
|
+
`.gbc/`(dogfooding):
|
|
87
|
+
|
|
88
|
+
- ✅ 核心保证机制(具名 id、多对一、出生即绿、退休保护、反查)
|
|
89
|
+
- ✅ 多语言 executor 配置
|
|
90
|
+
- ✅ CLI + MCP 双接口(含意图文档 `gbc doc` 全进 MCP)
|
|
91
|
+
- ✅ 意图文档子系统(`gbc doc` / web 编辑器)
|
|
92
|
+
- ✅ 随包分发的接线指南(`gbc setup`)与 CLI-only agent 的 skill 包
|
|
93
|
+
- ✅ 原子文件写入 + 备份
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
**诚实的局限**:保护能力上限 = 测试质量(测试只走 happy path 就是虚假安全感);依赖需主动登记,
|
|
97
|
+
覆盖率随项目增长需持续投入;每次验证真实跑测试,有一定延迟。详见
|
|
98
|
+
[核心概念 · 局限性](./docs/zh/concepts.md#局限性诚实地说)。
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 许可
|
|
103
|
+
|
|
104
|
+
本项目采用 [Apache-2.0](./LICENSE) 许可证。
|
|
105
|
+
|
|
106
|
+
## 联系
|
|
107
|
+
|
|
108
|
+
如果你对这个方向感兴趣,欢迎 star、issue 或者直接联系我。
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -241,9 +241,10 @@ def remove_dependency(
|
|
|
241
241
|
) -> None:
|
|
242
242
|
"""撤销一条依赖(add_dependency 的逆操作,同样维护双向一致)。
|
|
243
243
|
|
|
244
|
-
- gid 非 None
|
|
245
|
-
|
|
246
|
-
|
|
244
|
+
- gid 非 None:只摘掉这一个保证依赖,保留 symbol 边(可退为免费依赖)。
|
|
245
|
+
- gid 为 None:整条 symbol 边连同它挂的所有保证一起撤销。
|
|
246
|
+
两种撤销都仅在 consumer 不再通过任何 symbol 依赖同一 provider 的同一保证时,
|
|
247
|
+
才从该保证的 dependents 摘除 consumer。
|
|
247
248
|
"""
|
|
248
249
|
symbol = f"{provider}:{symbol_name}"
|
|
249
250
|
dep = _find_dependency(consumer_meta, symbol)
|
|
@@ -251,19 +252,25 @@ def remove_dependency(
|
|
|
251
252
|
raise GuaranteeNotFoundError(target_file=consumer, guarantee_path=symbol)
|
|
252
253
|
|
|
253
254
|
def _detach(target_gid: str) -> None:
|
|
255
|
+
if any(
|
|
256
|
+
remaining.symbol.startswith(f"{provider}:")
|
|
257
|
+
and target_gid in remaining.guarantees
|
|
258
|
+
for remaining in consumer_meta.depends_on
|
|
259
|
+
):
|
|
260
|
+
return
|
|
254
261
|
guarantee = provider_meta.provides.get(target_gid)
|
|
255
262
|
if guarantee and consumer in guarantee.dependents:
|
|
256
263
|
guarantee.dependents.remove(consumer)
|
|
257
264
|
|
|
258
265
|
if gid is None:
|
|
266
|
+
consumer_meta.depends_on.remove(dep)
|
|
259
267
|
for g in list(dep.guarantees):
|
|
260
268
|
_detach(g)
|
|
261
|
-
consumer_meta.depends_on.remove(dep)
|
|
262
269
|
return
|
|
263
270
|
|
|
264
271
|
if gid in dep.guarantees:
|
|
265
272
|
dep.guarantees.remove(gid)
|
|
266
|
-
|
|
273
|
+
_detach(gid)
|
|
267
274
|
# symbol 边变空(无保证)后是否保留:保留——它仍是一条有效的免费 symbol 依赖。
|
|
268
275
|
|
|
269
276
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -443,6 +443,8 @@ def verify_provider(
|
|
|
443
443
|
console.print(f"[magenta]{len(disabled)} DISABLED (born-green suspended):[/magenta] {tags}")
|
|
444
444
|
except Exception as e:
|
|
445
445
|
raise handle_error(e)
|
|
446
|
+
if not s.green:
|
|
447
|
+
raise typer.Exit(code=1)
|
|
446
448
|
|
|
447
449
|
|
|
448
450
|
@verify_app.command("single")
|
|
@@ -467,6 +469,8 @@ def verify_single(
|
|
|
467
469
|
console.print(f"[dim]── stderr ──[/dim]\n{result.stderr.rstrip()}")
|
|
468
470
|
except Exception as e:
|
|
469
471
|
raise handle_error(e)
|
|
472
|
+
if not passed:
|
|
473
|
+
raise typer.Exit(code=1)
|
|
470
474
|
|
|
471
475
|
|
|
472
476
|
# ======== Refactor ========
|
|
@@ -579,6 +583,8 @@ def doctor_check(
|
|
|
579
583
|
console.print_json(json.dumps(notices, ensure_ascii=False))
|
|
580
584
|
except Exception as e:
|
|
581
585
|
raise handle_error(e)
|
|
586
|
+
if errors:
|
|
587
|
+
raise typer.Exit(code=1)
|
|
582
588
|
|
|
583
589
|
|
|
584
590
|
# ======== Executor Commands ========
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/json_model_operator.py
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/app/utils/safe_file_writer.py
RENAMED
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/css/foundation.css
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/css/review.css
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/css/workspace.css
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/actions.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/editor-view.js
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/review-view.js
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/semantic.js
RENAMED
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/editor/js/tree-view.js
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/catalog/en.json
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/catalog/zh.json
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/rules.en.md
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/rules.zh.md
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/setup.en.md
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/i18n/texts/setup.zh.md
RENAMED
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/gbc/assets/skills/gbc-cli/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: guarantee-based-coding
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: Make code safely modifiable even when not fully understood — turn implicit inter-module dependencies into explicit, executable, verifiable guarantees.
|
|
5
|
-
Author: Jesse-x86
|
|
6
|
-
License-Expression: Apache-2.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/Jesse-x86/guarantee-based-coding
|
|
8
|
-
Project-URL: Repository, https://github.com/Jesse-x86/guarantee-based-coding
|
|
9
|
-
Keywords: guarantee,testing,ai-coding,mcp,code-safety
|
|
10
|
-
Classifier: Development Status :: 3 - Alpha
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Topic :: Software Development :: Testing
|
|
14
|
-
Requires-Python: >=3.10
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
License-File: LICENSE
|
|
17
|
-
Requires-Dist: typer[all]
|
|
18
|
-
Requires-Dist: pydantic
|
|
19
|
-
Requires-Dist: mcp<2.0,>=1.0
|
|
20
|
-
Dynamic: license-file
|
|
21
|
-
|
|
22
|
-
# Guarantee-Based Coding (GBC)
|
|
23
|
-
|
|
24
|
-
**与其指望 AI 更聪明,不如让再笨的 agent 也改不坏你的代码。**
|
|
25
|
-
|
|
26
|
-
**English version: [docs/en/README.md](docs/en/README.md)**
|
|
27
|
-
|
|
28
|
-
GBC 把「这次改动会不会悄悄碰坏别处」从一种担心,变成可以当场验证的事实:你在意的行为被登记成
|
|
29
|
-
一条条带测试的**保证(guarantee)**,每次改完一跑——全绿就安心,有红就精确告诉你碰坏了谁、谁在
|
|
30
|
-
依赖它。
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 🚀 快速开始
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
pipx install guarantee-based-coding
|
|
38
|
-
gbc setup # 打印本地化接线指南:怎么把 MCP / skills 接入你的 agent
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
装好后 `gbc` 命令即在 PATH 上。完整上手(安装 → 接入 agent → 冒烟验证)见
|
|
42
|
-
**[docs/zh/quick-start.md](./docs/zh/quick-start.md)**。
|
|
43
|
-
|
|
44
|
-
想让 agent 替你接入?把 **[docs/zh/onboarding-agent.md](./docs/zh/onboarding-agent.md)** 交给它。
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
> 🚧 **交互式 demo 施工中**:旧的演示套件已废弃,新的交互式演示正在筹备。目前请直接读文档上手。
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## 📚 文档
|
|
53
|
-
|
|
54
|
-
| 你想 | 看这里 |
|
|
55
|
-
|------|--------|
|
|
56
|
-
| 装好并跑起来 | [快速开始](./docs/zh/quick-start.md) |
|
|
57
|
-
| 懂 GBC 在保护什么 | [核心概念](./docs/zh/concepts.md) |
|
|
58
|
-
| 在 GBC 下安全改代码 | [工作流](./docs/zh/workflow.md) |
|
|
59
|
-
| 查命令 / 工具 / executor | [参考手册](./docs/zh/reference.md) |
|
|
60
|
-
| 你是 agent,被要求接入 GBC | [Agent 上手](./docs/zh/onboarding-agent.md) |
|
|
61
|
-
|
|
62
|
-
English docs: [docs/en/](./docs/en/)。
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 核心想法
|
|
67
|
-
|
|
68
|
-
代码之间的依赖本质上是一组**保证**。模块 A 依赖模块 B,不是依赖它的实现细节,而是依赖它的某些
|
|
69
|
-
行为承诺——返回值的类型、格式、语义。把这些保证从隐含变成**显式、可执行、可验证**,正确性的判定
|
|
70
|
-
就从「AI 觉得自己改对了」变成「所有被依赖的保证仍通过」——一个可机械验证的布尔条件。
|
|
71
|
-
|
|
72
|
-

|
|
73
|
-
|
|
74
|
-
GBC **不是**另一个要挑战 Cursor / Aider 的 AI 编程助手,而是填补它们在大型项目里缺的一环:
|
|
75
|
-
**机器可判定的变更边界**。它与那些 agent 配合——改前查依赖树,改后必须跑通所有相关保证;也区别
|
|
76
|
-
于 CI——CI 是事后的,GBC 是准入制的门禁,错误在落地前就被拦在 agent 的上下文里。
|
|
77
|
-
|
|
78
|
-
完整概念、架构图、与已有概念(Design by Contract / 测试)的区别,见
|
|
79
|
-
[核心概念](./docs/zh/concepts.md)。
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## 当前状态
|
|
84
|
-
|
|
85
|
-
GBC 目前是一个可用的 Python 分发包(`pipx install guarantee-based-coding`),自身用 GBC 管理自己的
|
|
86
|
-
`.gbc/`(dogfooding):
|
|
87
|
-
|
|
88
|
-
- ✅ 核心保证机制(具名 id、多对一、出生即绿、退休保护、反查)
|
|
89
|
-
- ✅ 多语言 executor 配置
|
|
90
|
-
- ✅ CLI + MCP 双接口(含意图文档 `gbc doc` 全进 MCP)
|
|
91
|
-
- ✅ 意图文档子系统(`gbc doc` / web 编辑器)
|
|
92
|
-
- ✅ 随包分发的接线指南(`gbc setup`)与 CLI-only agent 的 skill 包
|
|
93
|
-
- ✅ 原子文件写入 + 备份
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
**诚实的局限**:保护能力上限 = 测试质量(测试只走 happy path 就是虚假安全感);依赖需主动登记,
|
|
97
|
-
覆盖率随项目增长需持续投入;每次验证真实跑测试,有一定延迟。详见
|
|
98
|
-
[核心概念 · 局限性](./docs/zh/concepts.md#局限性诚实地说)。
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## 许可
|
|
103
|
-
|
|
104
|
-
本项目采用 [Apache-2.0](./LICENSE) 许可证。
|
|
105
|
-
|
|
106
|
-
## 联系
|
|
107
|
-
|
|
108
|
-
如果你对这个方向感兴趣,欢迎 star、issue 或者直接联系我。
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: guarantee-based-coding
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Make code safely modifiable even when not fully understood — turn implicit inter-module dependencies into explicit, executable, verifiable guarantees.
|
|
5
|
+
Author: Jesse-x86
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/Jesse-x86/guarantee-based-coding
|
|
8
|
+
Project-URL: Repository, https://github.com/Jesse-x86/guarantee-based-coding
|
|
9
|
+
Keywords: guarantee,testing,ai-coding,mcp,code-safety
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development :: Testing
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: typer[all]
|
|
18
|
+
Requires-Dist: pydantic
|
|
19
|
+
Requires-Dist: mcp<2.0,>=1.0
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Guarantee-Based Coding (GBC)
|
|
23
|
+
|
|
24
|
+
**与其指望 AI 更聪明,不如让再笨的 agent 也改不坏你的代码。**
|
|
25
|
+
|
|
26
|
+
**English version: [docs/en/README.md](docs/en/README.md)**
|
|
27
|
+
|
|
28
|
+
GBC 把「这次改动会不会悄悄碰坏别处」从一种担心,变成可以当场验证的事实:你在意的行为被登记成
|
|
29
|
+
一条条带测试的**保证(guarantee)**,每次改完一跑——全绿就安心,有红就精确告诉你碰坏了谁、谁在
|
|
30
|
+
依赖它。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🚀 快速开始
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pipx install guarantee-based-coding
|
|
38
|
+
gbc setup # 打印本地化接线指南:怎么把 MCP / skills 接入你的 agent
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
装好后 `gbc` 命令即在 PATH 上。完整上手(安装 → 接入 agent → 冒烟验证)见
|
|
42
|
+
**[docs/zh/quick-start.md](./docs/zh/quick-start.md)**。
|
|
43
|
+
|
|
44
|
+
想让 agent 替你接入?把 **[docs/zh/onboarding-agent.md](./docs/zh/onboarding-agent.md)** 交给它。
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
> 🚧 **交互式 demo 施工中**:旧的演示套件已废弃,新的交互式演示正在筹备。目前请直接读文档上手。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📚 文档
|
|
53
|
+
|
|
54
|
+
| 你想 | 看这里 |
|
|
55
|
+
|------|--------|
|
|
56
|
+
| 装好并跑起来 | [快速开始](./docs/zh/quick-start.md) |
|
|
57
|
+
| 懂 GBC 在保护什么 | [核心概念](./docs/zh/concepts.md) |
|
|
58
|
+
| 在 GBC 下安全改代码 | [工作流](./docs/zh/workflow.md) |
|
|
59
|
+
| 查命令 / 工具 / executor | [参考手册](./docs/zh/reference.md) |
|
|
60
|
+
| 你是 agent,被要求接入 GBC | [Agent 上手](./docs/zh/onboarding-agent.md) |
|
|
61
|
+
|
|
62
|
+
English docs: [docs/en/](./docs/en/)。
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 核心想法
|
|
67
|
+
|
|
68
|
+
代码之间的依赖本质上是一组**保证**。模块 A 依赖模块 B,不是依赖它的实现细节,而是依赖它的某些
|
|
69
|
+
行为承诺——返回值的类型、格式、语义。把这些保证从隐含变成**显式、可执行、可验证**,正确性的判定
|
|
70
|
+
就从「AI 觉得自己改对了」变成「所有被依赖的保证仍通过」——一个可机械验证的布尔条件。
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
GBC **不是**另一个要挑战 Cursor / Aider 的 AI 编程助手,而是填补它们在大型项目里缺的一环:
|
|
75
|
+
**机器可判定的变更边界**。它与那些 agent 配合——改前查依赖树,改后必须跑通所有相关保证;也区别
|
|
76
|
+
于 CI——CI 是事后的,GBC 是准入制的门禁,错误在落地前就被拦在 agent 的上下文里。
|
|
77
|
+
|
|
78
|
+
完整概念、架构图、与已有概念(Design by Contract / 测试)的区别,见
|
|
79
|
+
[核心概念](./docs/zh/concepts.md)。
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 当前状态
|
|
84
|
+
|
|
85
|
+
GBC 目前是一个可用的 Python 分发包(`pipx install guarantee-based-coding`),自身用 GBC 管理自己的
|
|
86
|
+
`.gbc/`(dogfooding):
|
|
87
|
+
|
|
88
|
+
- ✅ 核心保证机制(具名 id、多对一、出生即绿、退休保护、反查)
|
|
89
|
+
- ✅ 多语言 executor 配置
|
|
90
|
+
- ✅ CLI + MCP 双接口(含意图文档 `gbc doc` 全进 MCP)
|
|
91
|
+
- ✅ 意图文档子系统(`gbc doc` / web 编辑器)
|
|
92
|
+
- ✅ 随包分发的接线指南(`gbc setup`)与 CLI-only agent 的 skill 包
|
|
93
|
+
- ✅ 原子文件写入 + 备份
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
**诚实的局限**:保护能力上限 = 测试质量(测试只走 happy path 就是虚假安全感);依赖需主动登记,
|
|
97
|
+
覆盖率随项目增长需持续投入;每次验证真实跑测试,有一定延迟。详见
|
|
98
|
+
[核心概念 · 局限性](./docs/zh/concepts.md#局限性诚实地说)。
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 许可
|
|
103
|
+
|
|
104
|
+
本项目采用 [Apache-2.0](./LICENSE) 许可证。
|
|
105
|
+
|
|
106
|
+
## 联系
|
|
107
|
+
|
|
108
|
+
如果你对这个方向感兴趣,欢迎 star、issue 或者直接联系我。
|
|
File without changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[egg_info]
|
|
2
|
-
tag_build =
|
|
3
|
-
tag_date = 0
|
|
4
|
-
|
|
1
|
+
[egg_info]
|
|
2
|
+
tag_build =
|
|
3
|
+
tag_date = 0
|
|
4
|
+
|
|
File without changes
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
- 根 --help 根据 --lang / GBC_LANG 输出对应语言文本。
|
|
13
13
|
"""
|
|
14
14
|
import importlib
|
|
15
|
+
import json
|
|
15
16
|
import os
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
import subprocess
|
|
@@ -420,6 +421,109 @@ def _gbc(*args, env=None):
|
|
|
420
421
|
)
|
|
421
422
|
|
|
422
423
|
|
|
424
|
+
@pytest.fixture
|
|
425
|
+
def gate_project(tmp_path):
|
|
426
|
+
"""A real temporary GBC project whose executor runs a controllable script."""
|
|
427
|
+
project = tmp_path / "gate-project"
|
|
428
|
+
project.mkdir()
|
|
429
|
+
(project / "provider.py").write_text("def behavior(): pass\n", encoding="utf-8")
|
|
430
|
+
script = project / "check.py"
|
|
431
|
+
script.write_text("print('gate-check'); raise SystemExit(0)\n", encoding="utf-8")
|
|
432
|
+
|
|
433
|
+
def invoke(*args):
|
|
434
|
+
return _gbc("--lang", "en", *args, "-C", str(project))
|
|
435
|
+
|
|
436
|
+
config = {"command": [sys.executable, "{file}"], "cwd": str(project)}
|
|
437
|
+
result = invoke("executor", "upsert", "gate-script", "--json", json.dumps(config))
|
|
438
|
+
assert result.returncode == 0, result.stdout + result.stderr
|
|
439
|
+
result = invoke(
|
|
440
|
+
"guarantee", "create", "provider.py", "behavior.gate", "check.py",
|
|
441
|
+
"gate-script", "CLI gate regression",
|
|
442
|
+
)
|
|
443
|
+
assert result.returncode == 0, result.stdout + result.stderr
|
|
444
|
+
return project, script, invoke
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class TestGateExitCodes:
|
|
448
|
+
"""Real entry-point processes must expose gate outcomes to shell callers."""
|
|
449
|
+
|
|
450
|
+
@pytest.mark.parametrize("command", ["single", "provider"])
|
|
451
|
+
@pytest.mark.parametrize("fails", [False, True])
|
|
452
|
+
def test_verify_exit_matches_executed_result(self, gate_project, command, fails):
|
|
453
|
+
_, script, invoke = gate_project
|
|
454
|
+
script.write_text(
|
|
455
|
+
f"print('gate-check'); raise SystemExit({7 if fails else 0})\n",
|
|
456
|
+
encoding="utf-8",
|
|
457
|
+
)
|
|
458
|
+
args = ["verify", command, "provider.py"]
|
|
459
|
+
if command == "single":
|
|
460
|
+
args.append("behavior.gate")
|
|
461
|
+
result = invoke(*args)
|
|
462
|
+
output = result.stdout + result.stderr
|
|
463
|
+
status = ("FAIL" if fails else "PASS") if command == "single" else (
|
|
464
|
+
"RED" if fails else "GREEN"
|
|
465
|
+
)
|
|
466
|
+
assert status in output
|
|
467
|
+
assert (result.returncode != 0) is fails, output
|
|
468
|
+
assert "unexpected" not in output.lower()
|
|
469
|
+
assert "Traceback" not in output
|
|
470
|
+
if command == "single" and fails:
|
|
471
|
+
assert "gate-check" in output
|
|
472
|
+
|
|
473
|
+
@pytest.mark.parametrize("skip", ["heavy", "disabled"])
|
|
474
|
+
def test_provider_only_skips_are_success(self, gate_project, skip):
|
|
475
|
+
_, script, invoke = gate_project
|
|
476
|
+
if skip == "heavy":
|
|
477
|
+
update = invoke("guarantee", "update", "provider.py", "behavior.gate", "--heavy", "1")
|
|
478
|
+
else:
|
|
479
|
+
update = invoke("guarantee", "disable", "provider.py", "behavior.gate")
|
|
480
|
+
assert update.returncode == 0, update.stdout + update.stderr
|
|
481
|
+
script.write_text("raise SystemExit(7)\n", encoding="utf-8")
|
|
482
|
+
result = invoke("verify", "provider", "provider.py")
|
|
483
|
+
assert result.returncode == 0, result.stdout + result.stderr
|
|
484
|
+
assert "GREEN" in result.stdout
|
|
485
|
+
assert "skipped=1" in result.stdout
|
|
486
|
+
assert ("heavy skipped" if skip == "heavy" else "DISABLED") in result.stdout
|
|
487
|
+
|
|
488
|
+
@pytest.mark.parametrize("broken", [False, True])
|
|
489
|
+
@pytest.mark.parametrize("disabled", [False, True])
|
|
490
|
+
def test_doctor_errors_fail_but_disabled_notices_do_not(self, gate_project, broken, disabled):
|
|
491
|
+
project, _, invoke = gate_project
|
|
492
|
+
(project / "consumer.py").write_text("# consumer\n", encoding="utf-8")
|
|
493
|
+
result = invoke("dep", "add", "consumer.py", "provider.py", "behavior", "-g", "behavior.gate")
|
|
494
|
+
assert result.returncode == 0, result.stdout + result.stderr
|
|
495
|
+
if disabled:
|
|
496
|
+
result = invoke("guarantee", "disable", "provider.py", "behavior.gate")
|
|
497
|
+
assert result.returncode == 0, result.stdout + result.stderr
|
|
498
|
+
if broken:
|
|
499
|
+
# Simulate lost consumer metadata, leaving a real dangling reverse edge.
|
|
500
|
+
(project / ".gbc" / "gbc.consumer.py.json").unlink()
|
|
501
|
+
result = invoke("doctor", "check")
|
|
502
|
+
output = result.stdout + result.stderr
|
|
503
|
+
if broken:
|
|
504
|
+
assert "missing_forward" in output
|
|
505
|
+
elif not disabled:
|
|
506
|
+
assert "consistent" in output
|
|
507
|
+
if disabled:
|
|
508
|
+
assert "disabled notice" in output
|
|
509
|
+
assert (result.returncode != 0) is broken, output
|
|
510
|
+
assert "unexpected" not in output.lower()
|
|
511
|
+
assert "Traceback" not in output
|
|
512
|
+
|
|
513
|
+
def test_born_green_failure_stays_nonzero(self, gate_project):
|
|
514
|
+
_, script, invoke = gate_project
|
|
515
|
+
script.write_text("raise SystemExit(7)\n", encoding="utf-8")
|
|
516
|
+
result = invoke(
|
|
517
|
+
"guarantee", "create", "provider.py", "behavior.rejected", "check.py",
|
|
518
|
+
"gate-script", "Must refuse failing birth",
|
|
519
|
+
)
|
|
520
|
+
assert result.returncode != 0, result.stdout + result.stderr
|
|
521
|
+
assert "behavior.rejected" in result.stdout
|
|
522
|
+
listed = invoke("guarantee", "list", "provider.py")
|
|
523
|
+
assert listed.returncode == 0, listed.stdout + listed.stderr
|
|
524
|
+
assert "behavior.rejected" not in listed.stdout
|
|
525
|
+
|
|
526
|
+
|
|
423
527
|
def test_e2e_doctor_missing_gbc_propagates_nonzero_exit(tmp_path):
|
|
424
528
|
"""承诺:python -m 将 doctor 的失败返回码传播给真实子进程。"""
|
|
425
529
|
missing = tmp_path / "missing"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_executor_externalized.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
from gbc.app.models.meta import FileMeta, Guarantee, Dependency
|
|
5
|
-
from gbc.app.models.errors import GuaranteeNotFoundError
|
|
5
|
+
from gbc.app.models.errors import GuaranteeNotFoundError, GuaranteeHasDependentsError
|
|
6
6
|
from gbc.app.core.guarantee import (
|
|
7
7
|
add_dependency,
|
|
8
8
|
remove_dependency,
|
|
9
|
+
retire_guarantee,
|
|
9
10
|
list_provides,
|
|
10
11
|
list_depends_on,
|
|
11
12
|
dependents_of,
|
|
@@ -151,6 +152,88 @@ class TestRemoveDependency:
|
|
|
151
152
|
|
|
152
153
|
# ======================== list_provides / list_depends_on ========================
|
|
153
154
|
|
|
155
|
+
@pytest.mark.parametrize("whole_symbol", [False, True])
|
|
156
|
+
def test_shared_guarantee_keeps_retirement_guard_until_last_symbol_removed(whole_symbol):
|
|
157
|
+
consumer_meta = FileMeta()
|
|
158
|
+
provider_meta = make_provider_meta()
|
|
159
|
+
for name in (SYMBOL_NAME, "other_helper"):
|
|
160
|
+
add_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH, name, GID)
|
|
161
|
+
|
|
162
|
+
gid = None if whole_symbol else GID
|
|
163
|
+
remove_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH, SYMBOL_NAME, gid)
|
|
164
|
+
|
|
165
|
+
assert dependents_of(provider_meta, GID) == [CONSUMER_PATH]
|
|
166
|
+
assert any(dep.symbol == f"{PROVIDER_PATH}:other_helper" and GID in dep.guarantees
|
|
167
|
+
for dep in consumer_meta.depends_on)
|
|
168
|
+
with pytest.raises(GuaranteeHasDependentsError):
|
|
169
|
+
retire_guarantee(provider_meta, PROVIDER_PATH, GID)
|
|
170
|
+
|
|
171
|
+
remove_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH, "other_helper", gid)
|
|
172
|
+
|
|
173
|
+
assert dependents_of(provider_meta, GID) == []
|
|
174
|
+
if whole_symbol:
|
|
175
|
+
assert consumer_meta.depends_on == []
|
|
176
|
+
else:
|
|
177
|
+
assert len(consumer_meta.depends_on) == 2
|
|
178
|
+
assert all(dep.guarantees == [] for dep in consumer_meta.depends_on)
|
|
179
|
+
retire_guarantee(provider_meta, PROVIDER_PATH, GID)
|
|
180
|
+
assert GID not in provider_meta.provides
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@pytest.mark.parametrize("whole_symbol", [False, True])
|
|
184
|
+
def test_removing_dependency_preserves_other_consumer(whole_symbol):
|
|
185
|
+
consumer_meta = FileMeta()
|
|
186
|
+
other_consumer = FileMeta()
|
|
187
|
+
other_path = "app/core/other_consumer.py"
|
|
188
|
+
provider_meta = make_provider_meta()
|
|
189
|
+
for meta, path in ((consumer_meta, CONSUMER_PATH), (other_consumer, other_path)):
|
|
190
|
+
add_dependency(meta, path, provider_meta, PROVIDER_PATH, SYMBOL_NAME, GID)
|
|
191
|
+
|
|
192
|
+
remove_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH,
|
|
193
|
+
SYMBOL_NAME, None if whole_symbol else GID)
|
|
194
|
+
|
|
195
|
+
assert dependents_of(provider_meta, GID) == [other_path]
|
|
196
|
+
assert other_consumer.depends_on[0].guarantees == [GID]
|
|
197
|
+
with pytest.raises(GuaranteeHasDependentsError):
|
|
198
|
+
retire_guarantee(provider_meta, PROVIDER_PATH, GID)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@pytest.mark.parametrize("whole_symbol", [False, True])
|
|
202
|
+
def test_same_guarantee_id_on_other_provider_does_not_keep_removed_reverse_edge(whole_symbol):
|
|
203
|
+
consumer_meta = FileMeta()
|
|
204
|
+
provider_meta = make_provider_meta()
|
|
205
|
+
other_provider = make_provider_meta()
|
|
206
|
+
other_path = "app/core/provider.py.extra"
|
|
207
|
+
for meta, path in ((provider_meta, PROVIDER_PATH), (other_provider, other_path)):
|
|
208
|
+
add_dependency(consumer_meta, CONSUMER_PATH, meta, path, SYMBOL_NAME, GID)
|
|
209
|
+
|
|
210
|
+
remove_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH,
|
|
211
|
+
SYMBOL_NAME, None if whole_symbol else GID)
|
|
212
|
+
|
|
213
|
+
assert dependents_of(provider_meta, GID) == []
|
|
214
|
+
assert dependents_of(other_provider, GID) == [CONSUMER_PATH]
|
|
215
|
+
assert any(dep.symbol == f"{other_path}:{SYMBOL_NAME}" and GID in dep.guarantees
|
|
216
|
+
for dep in consumer_meta.depends_on)
|
|
217
|
+
retire_guarantee(provider_meta, PROVIDER_PATH, GID)
|
|
218
|
+
with pytest.raises(GuaranteeHasDependentsError):
|
|
219
|
+
retire_guarantee(other_provider, other_path, GID)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def test_removing_gid_not_attached_to_target_symbol_preserves_valid_dependency():
|
|
223
|
+
consumer_meta = FileMeta()
|
|
224
|
+
provider_meta = make_provider_meta()
|
|
225
|
+
add_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH, SYMBOL_NAME)
|
|
226
|
+
add_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH, "other_helper", GID)
|
|
227
|
+
before_consumer = consumer_meta.model_dump()
|
|
228
|
+
before_provider = provider_meta.model_dump()
|
|
229
|
+
|
|
230
|
+
remove_dependency(consumer_meta, CONSUMER_PATH, provider_meta, PROVIDER_PATH, SYMBOL_NAME, GID)
|
|
231
|
+
|
|
232
|
+
assert consumer_meta.model_dump() == before_consumer
|
|
233
|
+
assert provider_meta.model_dump() == before_provider
|
|
234
|
+
with pytest.raises(GuaranteeHasDependentsError):
|
|
235
|
+
retire_guarantee(provider_meta, PROVIDER_PATH, GID)
|
|
236
|
+
|
|
154
237
|
class TestListFunctions:
|
|
155
238
|
def test_list_provides_returns_provides_copy(self):
|
|
156
239
|
meta = make_provider_meta()
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_guarantee_verify.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_intent_editor_api.py
RENAMED
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_crud.py
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_deps.py
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_query.py
RENAMED
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_interface_base_refactor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{guarantee_based_coding-0.2.2 → guarantee_based_coding-0.2.3}/tests/test_safe_file_writer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|