@antprofuse/saddle-skill 0.3.0-alpha.3 → 0.3.0-alpha.4
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.
- package/SKILL.md +10 -5
- package/agents/openai.yaml +1 -1
- package/package.json +2 -2
- package/references/consumer-start.md +5 -2
- package/references/external-function-contracts.md +1 -1
- package/references/local-integration.md +49 -0
- package/references/programming-model.md +8 -1
- package/references/validation.md +7 -4
- package/scripts/saddle-03-gate.js +18 -6
package/SKILL.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: saddle-service-0-3
|
|
3
|
-
description:
|
|
3
|
+
description: 使用 Saddle 0.3.0-alpha.4 开发或审查带 profusegw 固定入口和 profusecontract 强类型外部函数调用的 Rust 业务应用。用于根据纯业务 spec 定义共同 protobuf 契约、编写固定 ProfuseGwContext handler、穷举技术失败、配置 plaintext 联调 endpoint,或运行正式业务门禁。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Saddle 0.3.0-alpha.
|
|
6
|
+
# Saddle 0.3.0-alpha.4 业务研发契约
|
|
7
7
|
|
|
8
8
|
业务 Agent 的直接输入只有业务 spec 与本 Skill。不要要求用户阅读 Saddle 仓库、审计报告、组件提交或内部实现。
|
|
9
9
|
|
|
@@ -13,7 +13,8 @@ description: 使用正式 Saddle 0.3.0-alpha.3 开发或审查带 profusegw 固
|
|
|
13
13
|
2. 先按 [外部函数协议](references/external-function-contracts.md) 在唯一 `contract_dir` 根部生成固定 `saddle_external_function.proto`,再只把具体外部函数写入业务 `.proto`。冻结目录内容后,才并行交给 Saddle 后端和 profusecontract 实现。
|
|
14
14
|
3. 按 [编程模型](references/programming-model.md) 声明应用、固定 profusegw operation、应用级强类型外部函数能力和唯一 handler。
|
|
15
15
|
4. 对八类技术失败与三种执行确定性逐项给出业务 spec 明确允许的处理。禁止 wildcard/default、自动重试、默认业务成功或空结果。
|
|
16
|
-
5. 按 [
|
|
16
|
+
5. 按 [本地联调与部署配置](references/local-integration.md) 配置唯一 plaintext profusecontract authority,使用固定 profusegw body 验证真实强类型调用链。
|
|
17
|
+
6. 按 [正式 Gate](references/validation.md) 生成 lock,并在交付前运行:
|
|
17
18
|
|
|
18
19
|
```bash
|
|
19
20
|
npx --no-install saddle-03-gate --manifest-path Cargo.toml
|
|
@@ -27,7 +28,7 @@ description: 使用正式 Saddle 0.3.0-alpha.3 开发或审查带 profusegw 固
|
|
|
27
28
|
|
|
28
29
|
```toml
|
|
29
30
|
[dependencies]
|
|
30
|
-
saddle-framework = "=0.3.0-alpha.
|
|
31
|
+
saddle-framework = "=0.3.0-alpha.4"
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
`saddle-framework` 是唯一业务 facade。业务不得直接依赖 `saddle-core`、`saddle-admission`、`saddle-boundary`、`saddle-db`、`saddle-macros`、`saddle-observability`、`saddle-runtime` 或 `saddle-service`。
|
|
@@ -36,6 +37,8 @@ saddle-framework = "=0.3.0-alpha.3"
|
|
|
36
37
|
|
|
37
38
|
- Saddle 编译进业务应用,不是独立服务、进程或控制面。
|
|
38
39
|
- profusegw 唯一入口是 `POST /saddle/v1/ingress/profusegw/invoke`;不得手写 listener、HTTP handler 或第二路由。
|
|
40
|
+
- 应用声明唯一字面量 `deployment_app`;请求 `target.app` 必须逐字匹配。每个字面量 `target.interfaceId` 只由静态 `operation_type` 分派,业务 handler 不读取或自行路由它。
|
|
41
|
+
- profusegw body 固定且只含 `target`、`profuseGwContext`、`requestData`;`profuseGwContext.userInfo.userId` 由框架形成 `ProfuseGwContext { user_id }`,业务 payload 不得覆盖。
|
|
39
42
|
- 所有 handler 使用 `saddle::ingress::ProfuseGwContext`;只读取正式 API 提供的只读、有界字段,不得读取 Header、Cookie、原始 JSON 或任意上下文 Map。
|
|
40
43
|
- 应用只配置一个 `contract_dir`。Saddle 在编译期确定性递归扫描其中的 `.proto`、闭合 import,并按 canonical 相对路径形成身份;不得列 proto 文件清单、维护聚合 proto,或在运行时扫描目录。
|
|
41
44
|
- 将 [固定协议模板](assets/saddle_external_function.proto) 原样写为 `${contract_dir}/saddle_external_function.proto`。不得改名、改内容、增加版本副本或另建 protocol 目录。
|
|
@@ -46,6 +49,7 @@ saddle-framework = "=0.3.0-alpha.3"
|
|
|
46
49
|
- 业务只使用生成的应用级强类型 capability,不接触 channel、stub、裸 protobuf bytes、动态函数名或通用依赖容器。
|
|
47
50
|
- 不支持 contract 多版本路由、`Any`、开放 Map、任意 JSON、streaming、cancel 或框架自动业务重试。
|
|
48
51
|
- 不创建线程、第二 Runtime、后台 task、裸 DB/网络 I/O、日志 subscriber 或第二执行面。
|
|
52
|
+
- profusecontract 部署只接受一个 `http://host:port` plaintext authority;不得携带 URL path、凭据、TLS、服务发现或 per-call endpoint。业务 handler 不读取该配置。
|
|
49
53
|
|
|
50
54
|
## 立即停止
|
|
51
55
|
|
|
@@ -53,7 +57,8 @@ saddle-framework = "=0.3.0-alpha.3"
|
|
|
53
57
|
- method option 缺少逐字 `puc + function`,或 DSL `business_unit` 与 `puc` 不同;
|
|
54
58
|
- 请求、结果、字符串、bytes、集合或嵌套对象没有业务静态上限;
|
|
55
59
|
- 需要动态 function/descriptor、raw invoke、裸 gRPC、原始网络上下文或未声明外部 I/O;
|
|
60
|
+
- 缺少固定 `deployment_app`,`target.app`/`interfaceId` 依赖运行时业务选择,或 endpoint 不是单一 plaintext authority;
|
|
56
61
|
- 八类技术失败或三种执行确定性未显式处理;
|
|
57
|
-
- Cargo 不是精确 alpha.
|
|
62
|
+
- Cargo 不是精确 alpha.4 Rust facade、缺 lock,或正式 Gate 不通过。
|
|
58
63
|
|
|
59
64
|
停止时只交最小复现和期望业务表达,由 Saddle 修复公共能力缺口。
|
package/agents/openai.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Saddle 0.3 业务应用"
|
|
3
3
|
short_description: "使用 Saddle 0.3 开发受控边界的 Rust 业务应用"
|
|
4
|
-
default_prompt: "请安装 Saddle 0.3.0-alpha.
|
|
4
|
+
default_prompt: "请安装 Saddle 0.3.0-alpha.4 Skill(npm install --save-exact --ignore-scripts --no-audit --no-fund @antprofuse/saddle-skill@0.3.0-alpha.4),结合业务 spec 开始研发。"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antprofuse/saddle-skill",
|
|
3
|
-
"version": "0.3.0-alpha.
|
|
4
|
-
"description": "Saddle 0.3.0-alpha.
|
|
3
|
+
"version": "0.3.0-alpha.4",
|
|
4
|
+
"description": "Saddle 0.3.0-alpha.4 中文 AI Coding 研发契约与业务门禁。",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"files": ["SKILL.md", "agents", "references", "scripts", "assets"],
|
|
7
7
|
"bin": {"saddle-03-gate": "scripts/saddle-03-gate.js"},
|
|
@@ -46,7 +46,9 @@ Saddle 在编译期从 `contract_dir` 确定性递归收集 `.proto`,闭合 im
|
|
|
46
46
|
|
|
47
47
|
## 阶段 3:Rust 实现
|
|
48
48
|
|
|
49
|
-
业务 crate 精确使用 `saddle-framework = "=0.3.0-alpha.
|
|
49
|
+
业务 crate 精确使用 `saddle-framework = "=0.3.0-alpha.4"`,然后按 [最小编程模型](programming-model.md) 编写固定 `deployment_app`、静态 operation 声明和 handler。不得直接依赖任何 Saddle 中间件 crate。
|
|
50
|
+
|
|
51
|
+
实现通过 Gate 后,按 [本地联调](local-integration.md) 由外部 harness 注入唯一 plaintext profusecontract authority,并以固定 profusegw body 验证真实 typed call。endpoint、request/call identity 和 deadline 都是框架或部署输入,不写入业务 spec。
|
|
50
52
|
|
|
51
53
|
## 阶段 4:闭合前停止条件
|
|
52
54
|
|
|
@@ -58,8 +60,9 @@ Saddle 在编译期从 `contract_dir` 确定性递归收集 `.proto`,闭合 im
|
|
|
58
60
|
- `functions` 声明了没有被 service `uses` 的能力;
|
|
59
61
|
- 中文 `function` 被翻译、alias、fallback 或动态选择;
|
|
60
62
|
- handler 不使用唯一固定 `ProfuseGwContext`,或读取原始网络上下文;
|
|
63
|
+
- 缺少固定 `deployment_app`,或 app/interfaceId/endpoint 被做成动态业务输入;
|
|
61
64
|
- 技术失败码或执行确定性存在 catch-all/default;
|
|
62
65
|
- 需要裸 gRPC/channel/bytes、第二入口、动态 descriptor 或未声明外部 I/O;
|
|
63
|
-
- `saddle-framework` 不是精确 `=0.3.0-alpha.
|
|
66
|
+
- `saddle-framework` 不是精确 `=0.3.0-alpha.4`,或 [正式 Gate](validation.md) 失败。
|
|
64
67
|
|
|
65
68
|
停止产物只包含最小复现、缺失身份和期望业务表达,不包含中间件替代实现。
|
|
@@ -68,7 +68,7 @@ message BoundAccount {
|
|
|
68
68
|
|
|
69
69
|
这里的跨系统正式身份是 `("puc", "查询用户绑定户号")`。`QueryBoundAccounts`、未来生成的 Rust 方法名和 Java 方法名都只是本地代码标识符,不能替换、翻译或推导中文 `function`。
|
|
70
70
|
|
|
71
|
-
该 import 必须精确指向同目录根部的 `saddle_external_function.proto`。其 bytes 来自
|
|
71
|
+
该 import 必须精确指向同目录根部的 `saddle_external_function.proto`。其 bytes 来自 Rust Alpha.4 公开闭包的权威模板并由 Skill 固定携带;不得自行创建同名 extension,也不得复制为另一份协议。
|
|
72
72
|
|
|
73
73
|
实际线上网络仍只调用 Saddle 固定 `ProfuseContractBoundary/Invoke` unary。契约中的 service/rpc 用于绑定身份、request 和 result,不要求 profusecontract 暴露同名网络方法。
|
|
74
74
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# profusegw / profusecontract 本地联调
|
|
2
|
+
|
|
3
|
+
## 固定入口 body
|
|
4
|
+
|
|
5
|
+
profusegw 只向固定路径发送通用 JSON body;业务接口不新增 URL:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"target": {
|
|
10
|
+
"app": "bill-service",
|
|
11
|
+
"interfaceId": "bill.query"
|
|
12
|
+
},
|
|
13
|
+
"profuseGwContext": {
|
|
14
|
+
"userInfo": { "userId": "2088-user" }
|
|
15
|
+
},
|
|
16
|
+
"requestData": { "account": "A-1" }
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `target.app` 必须逐字等于应用 DSL 的 `deployment_app`。
|
|
21
|
+
- `target.interfaceId` 必须逐字等于某个 service 的 `operation_type`,并由生成的静态表唯一分派。
|
|
22
|
+
- `requestData` 严格解码为该 service 的具名 request。
|
|
23
|
+
- `userId` 由框架以只读 `ProfuseGwContext::user_id()` 交给 handler,业务不得从 `requestData`、Header 或任意 Map 覆盖。
|
|
24
|
+
|
|
25
|
+
固定 HTTP profile 是 `POST /saddle/v1/ingress/profusegw/invoke` 与 `application/json`。本地 harness 必须给出受控 request identity、call identity 和绝对 deadline;不要在业务 handler 中构造它们。
|
|
26
|
+
|
|
27
|
+
## 唯一 plaintext endpoint
|
|
28
|
+
|
|
29
|
+
Alpha.4 部署配置只接受 profusecontract authority:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
http://127.0.0.1:50051
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
它必须是 `http` plaintext 的 `host:port`,不得包含 path、query、fragment、userinfo、凭据或动态函数信息。所有强类型函数共享这一部署级连接目标;线上 gRPC method 固定为 `ProfuseContractBoundary/Invoke`,应用不得按函数配置 endpoint。
|
|
36
|
+
|
|
37
|
+
此 endpoint 是部署输入,不进入业务 spec、request 或 handler。TLS、鉴权、服务发现、负载均衡和生产凭据不属于 Alpha.4;需要其中任一能力时立即停止,不得在业务 crate 自建 client。
|
|
38
|
+
|
|
39
|
+
## 联调完成条件
|
|
40
|
+
|
|
41
|
+
本地联调必须观察到:
|
|
42
|
+
|
|
43
|
+
1. 固定 profusegw body 被唯一静态 operation 接受;错误 app 被拒绝,未知 interfaceId 不进入 handler。
|
|
44
|
+
2. handler 读取同一请求的 `user_id`,发起一次生成的强类型调用。
|
|
45
|
+
3. profusecontract 收到同一 request identity、派生 call identity、绝对 deadline、`user_id`、`business_unit + function` 和强类型 payload。
|
|
46
|
+
4. 返回 `Completed` 或八类 `TechnicalFailure × ExecutionCertainty` 之一;业务代码显式处理,不自动重试。
|
|
47
|
+
5. 受管请求只形成一个 terminal,并在写 HTTP response 前完成资源归还。
|
|
48
|
+
|
|
49
|
+
联调 harness 可托管 listener 与受控 profusecontract server;业务源码不得复制 harness、直接依赖中间件 crate或注册第二入口。
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## 应用显式声明
|
|
4
4
|
|
|
5
|
-
业务应用使用 `saddle-framework = "=0.3.0-alpha.
|
|
5
|
+
业务应用使用 `saddle-framework = "=0.3.0-alpha.4"` 的公开编程面:
|
|
6
6
|
|
|
7
7
|
```rust
|
|
8
8
|
saddle::application! {
|
|
9
9
|
schema "saddle-application/2";
|
|
10
10
|
application PucBackend;
|
|
11
|
+
deployment_app "puc-backend";
|
|
11
12
|
|
|
12
13
|
profusecontract {
|
|
13
14
|
contract_dir "contracts";
|
|
@@ -35,6 +36,8 @@ saddle::application! {
|
|
|
35
36
|
|
|
36
37
|
这是业务实现显式写出的静态事实。`contract_dir` 是唯一 proto 真源;不要再列文件清单或维护聚合 proto。Saddle 只在编译期确定性递归扫描、闭合 import 并建立 option-only 索引,不在运行时发现函数。
|
|
37
38
|
|
|
39
|
+
`deployment_app` 是本部署唯一固定应用身份。profusegw body 的 `target.app` 必须逐字匹配它;每个 service 的 `operation_type` 是对应 `target.interfaceId` 的静态身份。两者都是声明期字面量,不是 handler 参数或动态路由键。
|
|
40
|
+
|
|
38
41
|
`functions` 只写当前应用实际使用的外部函数。每项必须由至少一个 service 的 `uses` 引用;普通 RPC、纯消息 proto 和未带正式 method option 的 RPC 不写入 `functions`。
|
|
39
42
|
|
|
40
43
|
业务 proto option 使用字段 `puc`;应用 DSL 使用 `business_unit`。两者必须逐字相等,均不允许翻译、alias 或 fallback。
|
|
@@ -86,3 +89,7 @@ match contract.query_bound_accounts(input).await {
|
|
|
86
89
|
每个分支还必须显式考虑正式 API 允许的执行确定性。不得使用 `_`、`default`、`UNKNOWN` 或 catch-all;新增技术码必须让旧消费者编译或 Gate 失败,而不是静默进入通用失败。
|
|
87
90
|
|
|
88
91
|
正式枚举名是 `TechnicalFailureCode::{FunctionNotFound, FunctionRequestInvalid, CapacityRejected, DeadlineExceeded, DependencyUnavailable, ContractResultInvalid, InternalFailure, TransportFailure}` 与 `ExecutionCertainty::{NotExecuted, Executed, MayHaveExecuted}`。对二者做笛卡尔积 match,每个技术码在三种 certainty 下均须出现于具名 arm;可用 `|` 合并业务决策相同的 arm,但不能省略任一组合。
|
|
92
|
+
|
|
93
|
+
## 本地真实 I/O
|
|
94
|
+
|
|
95
|
+
业务模块只提供以上声明、handler 与 generated capability。部署 harness 以唯一 plaintext profusecontract authority 连接生成的应用部署能力,再把固定 profusegw body 交给框架入口;业务不得直接构造 gRPC channel、HTTP listener 或受管请求身份。完整输入和完成条件见 [本地联调](local-integration.md)。
|
package/references/validation.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Saddle 0.3.0-alpha.
|
|
1
|
+
# Saddle 0.3.0-alpha.4 正式业务 Gate
|
|
2
2
|
|
|
3
3
|
## 依赖与锁
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ edition = "2024"
|
|
|
12
12
|
rust-version = "1.95"
|
|
13
13
|
|
|
14
14
|
[dependencies]
|
|
15
|
-
saddle-framework = "=0.3.0-alpha.
|
|
15
|
+
saddle-framework = "=0.3.0-alpha.4"
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
在允许访问正式 registry 的依赖准备阶段生成并提交 `Cargo.lock`。禁止 `path`、`git`、`[patch]`、source replacement 或宽松 Saddle 版本。
|
|
@@ -25,15 +25,18 @@ saddle-framework = "=0.3.0-alpha.3"
|
|
|
25
25
|
npx --no-install saddle-03-gate --manifest-path Cargo.toml
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
命令由已安装的 `@antprofuse/saddle-skill@0.3.0-alpha.
|
|
28
|
+
命令由已安装的 `@antprofuse/saddle-skill@0.3.0-alpha.4` 提供,不需要 Saddle 源码仓库。它会检查:
|
|
29
29
|
|
|
30
30
|
- facade 精确版本、禁止直接中间件依赖和 Cargo source 旁路;
|
|
31
|
-
- `Cargo.lock`
|
|
31
|
+
- `Cargo.lock` 中 boundary、db、framework、macros、observability、runtime、service 七包统一精确映射 `0.3.0-alpha.4`;
|
|
32
32
|
- 唯一 `contract_dir`、目录存在、禁止旧单文件 contract 声明;
|
|
33
33
|
- 目录根部 `saddle_external_function.proto` 与 Skill 权威模板逐字一致且仅出现一次,使用 option 的业务 proto 必须 direct import 根文件;
|
|
34
34
|
- 编译期递归扫描/import 闭包、option-only 索引、身份唯一、请求结果类型匹配,以及所有 function 均有实际 `uses`;
|
|
35
35
|
- 固定 `ProfuseGwContext`、应用声明、八类技术失败与三种 certainty 均被显式引用;
|
|
36
|
+
- 唯一字面量 `deployment_app`、静态 `operation_type`,并拒绝业务代码读取或动态路由 `target.app/interfaceId`;
|
|
36
37
|
- 无 wildcard/default、第二 listener/Runtime、裸 gRPC/HTTP、动态函数或 raw invoke;
|
|
37
38
|
- Rust 1.95 下 `cargo check --locked --offline`。
|
|
38
39
|
|
|
40
|
+
Gate 只验证业务 consumer 的静态边界与可编译性;本地真实 I/O 由 [联调完成条件](local-integration.md) 验证。plaintext authority 是部署配置,不得塞入业务源码以绕过 Gate。
|
|
41
|
+
|
|
39
42
|
Gate 使用临时 target 并在成功、失败和信号退出时清理。任何失败均为 STOP;不得加跳过参数或改 Gate 脚本。
|
|
@@ -30,8 +30,8 @@ if (/^\s*\[(patch|replace)\b/m.test(cargo) || /\b(path|git|branch|tag)\s*=/.test
|
|
|
30
30
|
stop("DEPENDENCY_SOURCE", "禁止 path/git/patch/replace 依赖旁路");
|
|
31
31
|
}
|
|
32
32
|
const facade = cargo.match(/^\s*saddle-framework\s*=\s*(.+)$/m);
|
|
33
|
-
if (!facade || !/^"=0\.3\.0-alpha\.
|
|
34
|
-
stop("SADDLE_VERSION", '必须直接且精确依赖 saddle-framework = "=0.3.0-alpha.
|
|
33
|
+
if (!facade || !/^"=0\.3\.0-alpha\.4"\s*(?:#.*)?$/.test(facade[1].trim())) {
|
|
34
|
+
stop("SADDLE_VERSION", '必须直接且精确依赖 saddle-framework = "=0.3.0-alpha.4"');
|
|
35
35
|
}
|
|
36
36
|
const internals = ["saddle-core","saddle-admission","saddle-boundary","saddle-db","saddle-macros","saddle-observability","saddle-runtime","saddle-service"];
|
|
37
37
|
for (const name of internals) {
|
|
@@ -41,8 +41,12 @@ if (!fs.existsSync(lockPath)) {
|
|
|
41
41
|
stop("LOCK", "缺少 Cargo.lock");
|
|
42
42
|
} else {
|
|
43
43
|
const lock = fs.readFileSync(lockPath, "utf8");
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
const publicClosure = ["saddle-boundary", "saddle-db", "saddle-framework", "saddle-macros", "saddle-observability", "saddle-runtime", "saddle-service"];
|
|
45
|
+
for (const name of publicClosure) {
|
|
46
|
+
const escaped = name.replaceAll("-", "\\-");
|
|
47
|
+
if (!new RegExp(`name = "${escaped}"\\nversion = "0\\.3\\.0-alpha\\.4"`).test(lock)) {
|
|
48
|
+
stop("LOCK", `Cargo.lock 未绑定 ${name} 0.3.0-alpha.4`);
|
|
49
|
+
}
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
52
|
|
|
@@ -59,6 +63,12 @@ visit(sourceRoot);
|
|
|
59
63
|
const source = files.map(p => fs.readFileSync(p, "utf8")).join("\n");
|
|
60
64
|
if (!source.includes("application!")) stop("APPLICATION", "缺少 Saddle application! 声明");
|
|
61
65
|
if (!source.includes("ProfuseGwContext")) stop("CONTEXT", "handler 必须使用固定 ProfuseGwContext");
|
|
66
|
+
const deploymentApps = [...source.matchAll(/\bdeployment_app\s+"([^"]+)"\s*;/g)];
|
|
67
|
+
if (deploymentApps.length !== 1) stop("DEPLOYMENT_APP", "必须且只能声明一个字面量 deployment_app");
|
|
68
|
+
const operations = [...source.matchAll(/\boperation_type\s+"([^"]+)"\s*;/g)];
|
|
69
|
+
if (operations.length === 0 || new Set(operations.map(match => match[1])).size !== operations.length) {
|
|
70
|
+
stop("INTERFACE_ID", "operation_type 必须存在且逐字唯一");
|
|
71
|
+
}
|
|
62
72
|
const contractDirs = [...source.matchAll(/\bcontract_dir\s+"([^"]+)"\s*;/g)];
|
|
63
73
|
if (contractDirs.length !== 1) stop("CONTRACT_DIR", "必须且只能声明一个 contract_dir");
|
|
64
74
|
if (/\bcontract\s+"[^"]+"\s*;/.test(source)) stop("CONTRACT_DIR", "禁止旧单 proto contract 声明");
|
|
@@ -107,7 +117,9 @@ for (const certainty of ["NotExecuted","Executed","MayHaveExecuted"]) {
|
|
|
107
117
|
const forbidden = [
|
|
108
118
|
["WILDCARD", /_\s*=>/], ["LISTENER", /\b(TcpListener|axum|hyper|actix_web|warp)\b/],
|
|
109
119
|
["RUNTIME", /\b(tokio::runtime|Runtime::new|spawn\s*\()/], ["RAW_RPC", /\b(tonic|Channel|ProfuseContractBoundary|raw_invoke|invoke_raw)\b/],
|
|
110
|
-
["DYNAMIC_FUNCTION", /\b(dynamic_function|call_dynamic|DynamicExternalFunction)\b/],
|
|
120
|
+
["DYNAMIC_FUNCTION", /\b(dynamic_function|call_dynamic|DynamicExternalFunction)\b/],
|
|
121
|
+
["DYNAMIC_INGRESS_IDENTITY", /\b(target\.app|target\.interfaceId|interface_id\s*\()/],
|
|
122
|
+
["UNSAFE", /\bunsafe\b/]
|
|
111
123
|
];
|
|
112
124
|
for (const [rule, pattern] of forbidden) if (pattern.test(source)) stop(rule, "命中禁止业务旁路");
|
|
113
125
|
|
|
@@ -121,4 +133,4 @@ try {
|
|
|
121
133
|
fs.rmSync(target, {recursive: true, force: true});
|
|
122
134
|
}
|
|
123
135
|
if (process.exitCode) process.exit(process.exitCode);
|
|
124
|
-
process.stdout.write("SADDLE_03_GATE PASS;
|
|
136
|
+
process.stdout.write("SADDLE_03_GATE PASS; SKILL=0.3.0-alpha.4; RUST=0.3.0-alpha.4; PROFUSEGW_STATIC_IDENTITY; LOCKED_OFFLINE; BUSINESS_BOUNDARIES=CLOSED\n");
|