@antprofuse/saddle-skill 0.3.10 → 0.3.11
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 +9 -5
- package/agents/openai.yaml +1 -1
- package/assets/business-example/Cargo.lock +2606 -0
- package/assets/business-example/Cargo.toml +11 -0
- package/assets/business-example/contracts/api.proto +17 -0
- package/assets/business-example/contracts/saddle_external_function.proto +13 -0
- package/assets/business-example/mappings/users.json +1 -0
- package/assets/business-example/saddle.toml +31 -0
- package/assets/business-example/src/main.rs +389 -0
- package/package.json +2 -2
- package/references/business-example.md +40 -0
- package/references/consumer-start.md +2 -2
- package/references/database-name-mapping.md +47 -2
- package/references/external-function-contracts.md +2 -2
- package/references/local-integration.md +3 -3
- package/references/operations-observability.md +1 -1
- package/references/programming-model.md +21 -3
- package/references/response-model.md +2 -0
- package/references/validation.md +4 -4
- package/scripts/saddle-03-gate.js +7 -5
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 应用显式声明
|
|
4
4
|
|
|
5
|
-
业务应用使用 `saddle-framework = "=0.3.
|
|
5
|
+
业务应用使用 `saddle-framework = "=0.3.11"` 的公开编程面:
|
|
6
6
|
|
|
7
7
|
```rust
|
|
8
8
|
saddle::application! {
|
|
@@ -13,7 +13,7 @@ saddle::application! {
|
|
|
13
13
|
|
|
14
14
|
profusecontract {
|
|
15
15
|
contract_dir "contracts";
|
|
16
|
-
capability
|
|
16
|
+
capability Capabilities;
|
|
17
17
|
response_code BusinessCode;
|
|
18
18
|
functions {
|
|
19
19
|
QueryBoundAccounts => query_bound_accounts {
|
|
@@ -40,7 +40,7 @@ saddle::application! {
|
|
|
40
40
|
|
|
41
41
|
`deployment_app` 是本部署唯一固定应用身份。profusegw body 的 `target.app` 必须逐字匹配它;每个 service 的 `operation_type` 是对应 `target.interfaceId` 的静态身份。两者都是声明期字面量,不是 handler 参数或动态路由键。
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
handler 的第三参数是同一个应用能力聚合:所有 route 都保留声明过的
|
|
44
44
|
ProfuseContract 强类型方法;需要数据库的 route 另外在 service 声明中选择唯一静态
|
|
45
45
|
operation,例如 `database query_optional find_user (generated::FindUser);`、
|
|
46
46
|
`database write save_user (generated::SaveUser);`、`database transaction_commit save_user
|
|
@@ -107,6 +107,24 @@ database transaction_commit transaction (generated::SaveUserCommit);
|
|
|
107
107
|
database transaction_rollback rollback (generated::SaveUserRollback);
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
+
生成步骤就是正常 `cargo build`:在业务源码使用公开 `saddle::database_operations!`,声明逻辑表及具名 Params/Row。完整声明、字段规则与调用示例见 [数据库声明与映射](database-name-mapping.md)。不需要独立生成器、build.rs、手写 SQL 或隐藏 trait。
|
|
111
|
+
|
|
112
|
+
DB 方法只消费一次 DB 能力,并返回结果与剩余外呼能力:
|
|
113
|
+
|
|
114
|
+
```rust
|
|
115
|
+
let (result, c) = c.read(ops::ReadParams { id: request.id }.into_parameters()).await;
|
|
116
|
+
match result {
|
|
117
|
+
Ok(row) => {
|
|
118
|
+
let row = ops::ReadRow::from_database(row);
|
|
119
|
+
// 显式处理 Some/None;用具名行字段构造强类型外呼请求。
|
|
120
|
+
// c 的外呼继续沿用本请求;c 已无 read/write 等 DB 方法。
|
|
121
|
+
}
|
|
122
|
+
Err(error) => { /* 映射为封闭失败响应,不把错误当成无行 */ }
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
同一个 operation 可被多个 route 引用。`transaction_commit` 与 `transaction_rollback` 是静态 route 决策,不代表可在 handler 内动态开始、多步组合、commit 或 rollback 的事务 API。
|
|
127
|
+
|
|
110
128
|
- 无 DB route 没有数据库方法,框架以 `NotUsed` 结束。query 和 write 只消费生成的有界参数/行类型。
|
|
111
129
|
- 单层 transaction 的操作与 commit/rollback 决策都是 route 的生成期事实;同一连接成功后 commit,失败、timeout 或 cancel 时 rollback,无法证明可复用时 discard。业务不得调用 commit/rollback,不得嵌套 transaction。
|
|
112
130
|
- DB 物理终态后,handler 先使用返回值形成响应;框架保留私有 post-DB terminal,直到响应写回成功、断连或 timeout 后才 finish 原请求并归还准入资源。
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## 唯一响应
|
|
4
4
|
|
|
5
|
+
响应还受框架现有 1MiB 编码与 framing 边界约束;超界形成技术失败,不截断为成功数据。这个边界不等于全进程 RSS、driver/TLS 或任意业务分配的绝对硬上限。
|
|
6
|
+
|
|
5
7
|
handler 必须直接返回 `saddle::ingress::ProfuseGwResponse<Data, BusinessCode>`。合法语义只有两支:成功 `Success { data }`,失败 `Failure { failure: { code, message } }`。标准 JSON 投影为:
|
|
6
8
|
|
|
7
9
|
```json
|
package/references/validation.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Saddle 0.3.
|
|
1
|
+
# Saddle 0.3.11 Skill 正式业务 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.
|
|
15
|
+
saddle-framework = "=0.3.11"
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
在允许访问正式 registry 的依赖准备阶段生成并提交 `Cargo.lock`。禁止 `path`、`git`、`[patch]`、source replacement 或宽松 Saddle 版本。
|
|
@@ -25,10 +25,10 @@ saddle-framework = "=0.3.10"
|
|
|
25
25
|
npx --no-install saddle-03-gate --manifest-path Cargo.toml
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
命令由已安装的 `@antprofuse/saddle-skill@0.3.
|
|
28
|
+
命令由已安装的 `@antprofuse/saddle-skill@0.3.11` 提供,不需要 Saddle 源码仓库。它会检查:
|
|
29
29
|
|
|
30
30
|
- facade 精确版本、禁止直接中间件依赖和 Cargo source 旁路;
|
|
31
|
-
- `Cargo.lock` 中 admission、boundary、core、db、framework、macros、observability、runtime、service 九包统一精确映射 `0.3.
|
|
31
|
+
- `Cargo.lock` 中 admission、boundary、core、db、framework、macros、observability、runtime、service 九包统一精确映射 `0.3.11`;
|
|
32
32
|
- 唯一 `contract_dir`、目录存在、禁止旧单文件 contract 声明;
|
|
33
33
|
- 目录根部 `saddle_external_function.proto` 与 Skill 权威模板逐字一致且仅出现一次,使用 option 的业务 proto 必须 direct import 根文件;
|
|
34
34
|
- 编译期递归扫描/import 闭包、option-only 索引、身份唯一、请求结果类型匹配,以及所有 function 均有实际 `uses`;
|
|
@@ -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\.
|
|
34
|
-
stop("SADDLE_VERSION", '必须直接且精确依赖 saddle-framework = "=0.3.
|
|
33
|
+
if (!facade || !/^"=0\.3\.11"\s*(?:#.*)?$/.test(facade[1].trim())) {
|
|
34
|
+
stop("SADDLE_VERSION", '必须直接且精确依赖 saddle-framework = "=0.3.11"');
|
|
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) {
|
|
@@ -44,8 +44,8 @@ if (!fs.existsSync(lockPath)) {
|
|
|
44
44
|
const publicClosure = ["saddle-admission", "saddle-boundary", "saddle-core", "saddle-db", "saddle-framework", "saddle-macros", "saddle-observability", "saddle-runtime", "saddle-service"];
|
|
45
45
|
for (const name of publicClosure) {
|
|
46
46
|
const escaped = name.replaceAll("-", "\\-");
|
|
47
|
-
if (!new RegExp(`name = "${escaped}"\\nversion = "0\\.3\\.
|
|
48
|
-
stop("LOCK", `Cargo.lock 未绑定 ${name} 0.3.
|
|
47
|
+
if (!new RegExp(`name = "${escaped}"\\nversion = "0\\.3\\.11"`).test(lock)) {
|
|
48
|
+
stop("LOCK", `Cargo.lock 未绑定 ${name} 0.3.11`);
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -161,6 +161,7 @@ if (!/\bcapability\s+Capabilities\s*;/.test(source)) stop("CAPABILITIES", "appli
|
|
|
161
161
|
if (!/\bcapabilities\s*:\s*Capabilities(?:\s*<[^>]+>)?/.test(source)) stop("CAPABILITIES", "handler 第三参数必须使用生成 Capabilities");
|
|
162
162
|
if (/\b(?:contract|client)\s*:\s*[A-Za-z_][A-Za-z0-9_]*(?:Contract|Client)\b/.test(source)) stop("CAPABILITIES", "禁止旧第三参数 capability/client");
|
|
163
163
|
for (const db of source.matchAll(/\bdatabase\s+([A-Za-z_][A-Za-z0-9_]*)\s+/g)) {
|
|
164
|
+
if (!source.includes('database_operations!')) stop('DATABASE_DECLARATION', 'DB route 必须使用公开 database_operations!');
|
|
164
165
|
if (!new Set(["query_optional", "write", "transaction_commit", "transaction_rollback"]).has(db[1])) {
|
|
165
166
|
stop("DATABASE", `禁止非静态或未批准数据库模式 ${db[1]}`);
|
|
166
167
|
}
|
|
@@ -226,6 +227,7 @@ for (const certainty of ["NotExecuted","Executed","MayHaveExecuted"]) {
|
|
|
226
227
|
if (!source.includes(certainty)) stop("EXECUTION_CERTAINTY", `缺少显式分支 ${certainty}`);
|
|
227
228
|
}
|
|
228
229
|
const forbidden = [
|
|
230
|
+
["HIDDEN_DATABASE", /saddle::__private|\bStaticQueryOptionalOperation\b|\bStaticWriteOperation\b/],
|
|
229
231
|
["WILDCARD", /_\s*=>/], ["LISTENER", /\b(TcpListener|axum|hyper|actix_web|warp)\b/],
|
|
230
232
|
["RUNTIME", /\b(tokio::runtime|Runtime::new|spawn\s*\()/], ["RAW_RPC", /\b(tonic|Channel|ProfuseContractBoundary|raw_invoke|invoke_raw)\b/],
|
|
231
233
|
["DYNAMIC_FUNCTION", /\b(dynamic_function|call_dynamic|DynamicExternalFunction)\b/],
|
|
@@ -250,4 +252,4 @@ try {
|
|
|
250
252
|
fs.rmSync(target, {recursive: true, force: true});
|
|
251
253
|
}
|
|
252
254
|
if (process.exitCode) process.exit(process.exitCode);
|
|
253
|
-
process.stdout.write("SADDLE_03_GATE PASS; SKILL=0.3.
|
|
255
|
+
process.stdout.write("SADDLE_03_GATE PASS; SKILL=0.3.11; RUST=0.3.11; ADMISSION_DERIVED; W0; CLOSED_RESPONSE; CLOSED_CODES; FAILURE_MESSAGE_256; FAILURE_8X3; LOCKED_OFFLINE\n");
|