@sema-agent/server 7.122.0 → 7.124.0
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/MIGRATION.md +209 -0
- package/README.md +7 -2
- package/README.zh-CN.md +5 -2
- package/USAGE.md +76 -56
- package/dist/approval-ask-audit-store.d.ts +27 -32
- package/dist/approval-ask-audit-store.js +10 -9
- package/dist/approval-crash-convergence.d.ts +2 -2
- package/dist/approval-crash-convergence.js +5 -5
- package/dist/approval-deny-reasons.d.ts +163 -51
- package/dist/approval-deny-reasons.js +79 -8
- package/dist/approval-policy-settlement.d.ts +4 -1
- package/dist/approval-policy-settlement.js +3 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval-reconciler.js +10 -10
- package/dist/approval.d.ts +1 -1
- package/dist/approval.js +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +53 -23
- package/dist/auth-bridge.d.ts +8 -8
- package/dist/auth-bridge.js +6 -6
- package/dist/auth-keys.d.ts +2 -2
- package/dist/auto-mode-face.d.ts +13 -9
- package/dist/auto-mode-face.js +8 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/execution-env.js +1 -0
- package/dist/boot/leader.d.ts +1 -1
- package/dist/boot/memory-consolidation.d.ts +4 -4
- package/dist/boot/org-memory.d.ts +3 -3
- package/dist/boot/org-memory.js +5 -5
- package/dist/boot/resolve-spec.js +7 -7
- package/dist/boot/runner-deps.d.ts +1 -1
- package/dist/boot/runtime-caps.d.ts +1 -1
- package/dist/boot/runtime-caps.js +10 -10
- package/dist/boot/shutdown.d.ts +2 -2
- package/dist/boot/shutdown.js +2 -2
- package/dist/boot/side-query-lane.d.ts +3 -3
- package/dist/boot/{stage-02-registry-pull.d.ts → stage-02-web-admin-pull.d.ts} +2 -2
- package/dist/boot/{stage-02-registry-pull.js → stage-02-web-admin-pull.js} +4 -4
- package/dist/boot/stage-03-store-backend.d.ts +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +6 -6
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +6 -5
- package/dist/boot/stage-08-reapers.d.ts +3 -3
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -3
- package/dist/boot/stage-09-leader.js +7 -7
- package/dist/boot/stage-10-http-server.d.ts +3 -3
- package/dist/boot/stage-10-http-server.js +19 -19
- package/dist/boot/unpriced-ceiling-verdict.d.ts +1 -1
- package/dist/boot/{config-center.d.ts → web-admin.d.ts} +11 -11
- package/dist/boot/{config-center.js → web-admin.js} +39 -20
- package/dist/boot/webfetch-summarize-lane.d.ts +2 -2
- package/dist/brain.d.ts +1 -1
- package/dist/brain.js +1 -1
- package/dist/budget.d.ts +3 -3
- package/dist/canonical-json.d.ts +2 -2
- package/dist/capabilities/center-plugins.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +12 -5
- package/dist/capabilities/center-wiring.js +11 -2
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capabilities/team.d.ts +1 -1
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/center-credential-renewer.d.ts +1 -1
- package/dist/center-credential-renewer.js +7 -7
- package/dist/center-credential.d.ts +9 -9
- package/dist/center-credential.js +6 -6
- package/dist/config-catalog.d.ts +7 -10
- package/dist/config-catalog.js +16 -16
- package/dist/config-d-migration.d.ts +32 -0
- package/dist/config-d-migration.js +59 -0
- package/dist/config-invariants.d.ts +14 -4
- package/dist/config-invariants.js +31 -2
- package/dist/config-lkg.d.ts +34 -11
- package/dist/config-lkg.js +76 -48
- package/dist/config-provider.d.ts +26 -21
- package/dist/config-provider.js +25 -27
- package/dist/config-types.d.ts +59 -50
- package/dist/config.d.ts +17 -54
- package/dist/config.js +99 -181
- package/dist/execution-lane-caps.d.ts +1 -1
- package/dist/fleet/drain-entry.d.ts +1 -1
- package/dist/fleet/engine-signal.d.ts +61 -30
- package/dist/fleet/engine-signal.js +29 -5
- package/dist/fleet/fleet-bus.d.ts +12 -3
- package/dist/fleet/fleet-bus.js +13 -9
- package/dist/fleet/serving-lease.d.ts +3 -3
- package/dist/fleet/serving-lease.js +1 -1
- package/dist/fleet-client.d.ts +15 -13
- package/dist/fleet-client.js +9 -7
- package/dist/fleet-lease.d.ts +3 -3
- package/dist/fleet-lease.js +2 -2
- package/dist/host-lsp-manager.d.ts +1 -1
- package/dist/hosted-posture.d.ts +4 -4
- package/dist/http/admission.js +4 -4
- package/dist/http/checkpoint-ctx.d.ts +20 -3
- package/dist/http/checkpoint-ctx.js +13 -5
- package/dist/http/dispatch.js +7 -16
- package/dist/http/durable-run-leg.js +2 -1
- package/dist/http/health-self-report.d.ts +7 -4
- package/dist/http/health-self-report.js +3 -3
- package/dist/http/idempotency.d.ts +1 -1
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +31 -18
- package/dist/http/route-ctx.d.ts +8 -0
- package/dist/http/routes/admin-config-refresh.d.ts +1 -1
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.d.ts +1 -1
- package/dist/http/routes/admin-drain.js +5 -4
- package/dist/http/routes/approvals-assistant.js +4 -4
- package/dist/http/routes/capabilities.js +6 -5
- package/dist/http/routes/config-catalog.js +2 -3
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/runs.js +8 -4
- package/dist/http/routes/sessions-list.js +2 -1
- package/dist/http/routes/sessions.js +2 -5
- package/dist/http/routes/side-query.js +3 -3
- package/dist/http/routes/tasks.js +3 -2
- package/dist/http/run-meta.d.ts +1 -1
- package/dist/http/run-meta.js +2 -2
- package/dist/http/server.d.ts +7 -7
- package/dist/http/server.js +1 -1
- package/dist/http/stored-body-replay.d.ts +4 -3
- package/dist/http/stored-body-replay.js +5 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/key-resolver.d.ts +1 -1
- package/dist/leader/leader.d.ts +7 -6
- package/dist/leader/leader.js +3 -1
- package/dist/leader/run-entry.d.ts +2 -2
- package/dist/leader/run-entry.js +3 -3
- package/dist/leader/wire.d.ts +4 -4
- package/dist/leader/wire.js +2 -1
- package/dist/main.js +1 -1
- package/dist/mcp-tool-faces.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +20 -11
- package/dist/model-entry-refusal.js +22 -17
- package/dist/model-provider.d.ts +2 -2
- package/dist/model-route-endpoint.d.ts +22 -2
- package/dist/model-route-endpoint.js +9 -3
- package/dist/model-route-gap.d.ts +103 -0
- package/dist/model-route-gap.js +80 -0
- package/dist/model-route-url.d.ts +1 -1
- package/dist/model-route-url.js +2 -1
- package/dist/model-select.d.ts +24 -21
- package/dist/model-select.js +22 -17
- package/dist/namespaced-rule-name.d.ts +16 -30
- package/dist/namespaced-rule-name.js +2 -20
- package/dist/observability/fail-open.d.ts +0 -4
- package/dist/observability/fail-open.js +0 -4
- package/dist/observability/metrics.d.ts +1 -1
- package/dist/org-memory-admission.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -2
- package/dist/plugins/approval-ask-store-file.js +3 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +4 -3
- package/dist/plugins/approval-ask-store-memory.js +10 -4
- package/dist/plugins/approval-ask-store-sql.d.ts +16 -2
- package/dist/plugins/approval-ask-store-sql.js +20 -13
- package/dist/plugins/caching-session-store.d.ts +0 -10
- package/dist/plugins/caching-session-store.js +0 -3
- package/dist/plugins/file-run-store.js +9 -3
- package/dist/plugins/leader-run-store-sql.d.ts +3 -2
- package/dist/plugins/leader-run-store-sql.js +3 -2
- package/dist/plugins/local-session-store.d.ts +20 -27
- package/dist/plugins/local-session-store.js +19 -17
- package/dist/plugins/memory-run-store.js +9 -3
- package/dist/plugins/one-time-migrations.js +51 -0
- package/dist/plugins/scheduler-support.d.ts +26 -7
- package/dist/plugins/scheduler-support.js +96 -53
- package/dist/plugins/session-policy-store-sql.js +1 -2
- package/dist/plugins/store-backend.js +1 -1
- package/dist/plugins/store-contracts.d.ts +20 -4
- package/dist/plugins/web-search.d.ts +1 -1
- package/dist/plugins/web-search.js +2 -1
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -2
- package/dist/posture-source.d.ts +1 -1
- package/dist/read-face-posture.d.ts +3 -3
- package/dist/read-face-posture.js +1 -1
- package/dist/rule-entry-list.d.ts +3 -13
- package/dist/rule-entry-list.js +1 -12
- package/dist/run-local.js +10 -7
- package/dist/runtime-caps-resolver.d.ts +4 -4
- package/dist/runtime-caps-resolver.js +2 -2
- package/dist/runtime-governance.d.ts +36 -13
- package/dist/runtime-governance.js +7 -2
- package/dist/sealed-key.d.ts +4 -4
- package/dist/sealed-key.js +3 -2
- package/dist/security.d.ts +3 -3
- package/dist/service-version.d.ts +1 -1
- package/dist/service-version.js +5 -0
- package/dist/session-policy-wire.d.ts +47 -49
- package/dist/session-policy-wire.js +41 -36
- package/dist/session-sync.d.ts +5 -1
- package/dist/session-sync.js +2 -1
- package/dist/session-titler.d.ts +0 -11
- package/dist/session-titler.js +3 -5
- package/dist/shared-memory-scope-authorizer.d.ts +4 -4
- package/dist/spec-fields.d.ts +4 -4
- package/dist/spec-fields.js +1 -4
- package/dist/task-a2a.d.ts +1 -1
- package/dist/task-settings.d.ts +4 -5
- package/dist/task-settings.js +5 -8
- package/dist/tool-approval.d.ts +43 -4
- package/dist/tool-approval.js +147 -98
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/project.d.ts +3 -3
- package/dist/trace/redact.d.ts +2 -23
- package/dist/trace/redact.js +1 -6
- package/dist/trace/self-minted-wire.d.ts +147 -3
- package/dist/trace/self-minted-wire.js +50 -9
- package/dist/unattended-permission-mode.d.ts +3 -3
- package/dist/unattended-permission-mode.js +2 -2
- package/dist/url-refusal.d.ts +35 -0
- package/dist/url-refusal.js +15 -0
- package/dist/user-authored-text.d.ts +31 -0
- package/dist/user-authored-text.js +18 -0
- package/dist/{config-center → web-admin-client}/apply-effective.d.ts +13 -70
- package/dist/{config-center → web-admin-client}/apply-effective.js +104 -121
- package/dist/{config-center → web-admin-client}/apply-ledger.d.ts +2 -2
- package/dist/{config-center → web-admin-client}/center-request.d.ts +7 -7
- package/dist/{config-center → web-admin-client}/center-request.js +5 -4
- package/dist/{config-center → web-admin-client}/effective-keys.d.ts +1 -3
- package/dist/{config-center → web-admin-client}/effective-keys.js +0 -9
- package/dist/{config-center → web-admin-client}/facade.d.ts +6 -6
- package/dist/{config-center → web-admin-client}/facade.js +2 -2
- package/dist/{config-center → web-admin-client}/http-client.d.ts +6 -10
- package/dist/{config-center → web-admin-client}/http-client.js +15 -15
- package/dist/{config-center → web-admin-client}/pull-state.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/read-face.js +4 -4
- package/dist/web-admin-client/read-warnings.d.ts +137 -0
- package/dist/web-admin-client/read-warnings.js +168 -0
- package/dist/{config-center → web-admin-client}/restart-signal.d.ts +5 -3
- package/dist/{config-center → web-admin-client}/restart-signal.js +3 -4
- package/dist/{config-center → web-admin-client}/skills-mcp.d.ts +1 -1
- package/dist/{config-center → web-admin-client}/skills-mcp.js +13 -13
- package/dist/{config-center → web-admin-client}/stage-limits.d.ts +1 -7
- package/dist/{config-center → web-admin-client}/stage-limits.js +6 -7
- package/dist/{config-center → web-admin-client}/types.d.ts +19 -47
- package/package.json +3 -3
- package/skills/find-skills.md +2 -2
- package/dist/config-center/read-warnings.d.ts +0 -109
- package/dist/config-center/read-warnings.js +0 -110
- package/dist/url-shape.d.ts +0 -31
- package/dist/url-shape.js +0 -41
- /package/dist/{config-center → web-admin-client}/apply-ledger.js +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/hot-keys-registry.js +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/mcp-revocation.js +0 -0
- /package/dist/{config-center → web-admin-client}/pull-state.js +0 -0
- /package/dist/{config-center → web-admin-client}/read-face.d.ts +0 -0
- /package/dist/{config-center → web-admin-client}/types.js +0 -0
|
@@ -1,32 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 规则里的工具名**够不够得着**一只挂载工具 ——
|
|
2
|
+
* 规则里的工具名**够不够得着**一只挂载工具 —— 判官只有一个:引擎的 `judgeRuleToolName`。本文件只剩「规则文本里工具名那一段怎么取」与「判词怎么说」。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* · **工具段为空的协议名**(`mcp__srv__`)—— 引擎判官答 `current`、规则文法收下、allow 条目读成一条精确名行,而它一只工具都够不着
|
|
9
|
-
* (引擎自己的两种拆法 —— 精确名 `ns.parse`、覆盖形 `isNamespacedCoveringRuleName` —— 都不认它)。这是引擎读不到的一形,本仓在下面点名的那些面上
|
|
10
|
-
* 拒它({@link emptyToolSegmentOf}),句子在这里({@link describeEmptyToolSegment})。翻转条件:引擎判官给这一形一个判词 ⇒ 本文件整只退役。
|
|
4
|
+
* 一个名字永远匹配不到工具的成因,全是引擎判官的判词(`retired` / `unprefixed_namespace` / `unmintable_segment`,带 `guidance` 与 1:1 `currentName`):
|
|
5
|
+
* 退役名、无协议前缀的 `__` 短名、协议名的对端段引擎铸不出(`mcp__github.com__*`、`mcp__*`、`mcp____x`、`mcp__`),以及(core 7.48.0 #1400 起)
|
|
6
|
+
* **工具段为空**(`mcp__srv__` / `a2a__peer__`)。最后这一形 7.116.0–7.122.x 是本仓自答的(引擎判官当时答 `current`);引擎给了判词 ⇒ 本仓那一问
|
|
7
|
+
* (本文件那只判与它在会话规则写口、SQL 店写口、四张条目表上的调用)退役,零双读。
|
|
11
8
|
*
|
|
12
|
-
* **调它的面**(
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `agents[].skills[]` 两处受理口)—— 经 `rule-entry-list.ts` 的 `emptyToolSegmentEntryOf`(本仓这一问;退役名 / 铸不出的判词那一半由引擎 `compileAllowList` 给)。
|
|
9
|
+
* **调它的面**(点名,不是「每个面」):运维三张名表(`APPROVAL_REQUIRE` / `DENY` / `NEVER_AUTO`)与中心下发的同名表、请求
|
|
10
|
+
* `settings.permissions.{ask,deny}`(经 `config.ts` 的 `unmatchableToolNamesRefusal`)。会话规则写口直接调 core 的 `assertSessionRuleNamesCurrent`
|
|
11
|
+
* (同一只判官的店形);引擎 allow 层的条目表(请求 `settings.permissions.allow`、运维 `APPROVAL_GRANT`、技能两只清单)交引擎 `compileAllowList`
|
|
12
|
+
* (名册 = {@link NO_DECLARED_TOOL_NAMES};判官判非现役的条目读成 `tool_name`)。
|
|
17
13
|
* **不调它的面**:`/v1/rules` 的持久规则写口与 `cc-import` 导入口(`http/routes/rules.ts`、`rules-consent.ts` 与两只持久规则店零判官调用)—— 如实未接,
|
|
18
|
-
*
|
|
14
|
+
* 在那里写铸不出的服务器段仍被收下、永不命中;把它接上判官 = 另一件事(`unmatchableRuleNameOf` 就是现成的那一只)。
|
|
19
15
|
* 子代的工具名表 `agents[].allowTools` / `denyTools` 不是本文件的面:core 7.45.0 #1377 / #1385 起名字归引擎在开跑前一只判(三来源同判,`spec-fields.ts`
|
|
20
16
|
* 受理口只判形与条数),本仓不对它另做对照。
|
|
21
17
|
* **精确名的工具段归一不在这里判**:包根没有导出工具段的铸法,不手抄 —— 精确名的工具段按字面收,本仓每张表上都不判它。
|
|
22
18
|
*
|
|
23
|
-
* 规则文本里「工具名那一段」怎么取也只有一种读法:{@link ruleEntryToolName}(
|
|
19
|
+
* 规则文本里「工具名那一段」怎么取也只有一种读法:{@link ruleEntryToolName}(配置表读它)。
|
|
24
20
|
*/
|
|
25
|
-
import { type
|
|
21
|
+
import { type RuleToolNameVerdict } from "@sema-agent/core";
|
|
26
22
|
/**
|
|
27
23
|
* 一条**规则文本**里的工具名那一段(判官与旧名判据的主语)= core 包根 `parsePermissionRule` 的 `toolName`,原样 —— 引擎的技能编译器
|
|
28
24
|
* (`compileSkillGrant`)与规则编译器读条目用的就是这一只:`Bash(npm:*)` ⇒ `Bash`;`mcp__srv(*)` / `mcp__srv()` / 带首尾空格的 `mcp__srv ` ⇒ 光杆名 `mcp__srv`。
|
|
29
|
-
*
|
|
25
|
+
* 配置表的规则编译器消费者读它(技能两只清单的名字层 7.118.0 起交引擎的条目读法)。不在这里另写解析、不回落整串:修前用 `parseRuleText`(只认 `工具(内容)` 形,光杆名解析不出就回落整串),
|
|
30
26
|
* 整串带着 `(*)` / 尾空格进判官 ⇒ 合法条目被判「铸不出」(修复验证轮 gpt-6 腿)。条目若是引擎文法本身就拒的形(配置表上 MCP 规则带括号:
|
|
31
27
|
* `unsupported.mcp_paren`),拒由引擎的文法那一问说(配置表的判据链里它排在本判官之前),本判官不抢答。
|
|
32
28
|
*/
|
|
@@ -36,14 +32,11 @@ export declare function ruleEntryToolName(entry: string): string;
|
|
|
36
32
|
* ⇒ 恒为空集。引擎判官、`compileAllowList` 的第三参、会话规则店同读这一只。
|
|
37
33
|
*/
|
|
38
34
|
export declare const NO_DECLARED_TOOL_NAMES: ReadonlySet<string>;
|
|
39
|
-
/** 一个规则名永远匹配不到工具的判词(闭集)
|
|
35
|
+
/** 一个规则名永远匹配不到工具的判词(闭集)= 引擎判官的非现行判词。 */
|
|
40
36
|
export type UnmatchableRuleName = Exclude<RuleToolNameVerdict, {
|
|
41
37
|
kind: "current";
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
readonly ns: ProtocolNamespace;
|
|
45
|
-
};
|
|
46
|
-
/** 判:引擎判官先答(非 `current` ⇒ 原样交回),判官放行的再问引擎读不到的那一形;都过 ⇒ `undefined`。 */
|
|
38
|
+
}>;
|
|
39
|
+
/** 判:引擎判官非 `current` ⇒ 原样交回;`current` ⇒ `undefined`。 */
|
|
47
40
|
export declare function unmatchableRuleNameOf(name: string): UnmatchableRuleName | undefined;
|
|
48
41
|
/**
|
|
49
42
|
* 判词 → 「为什么永远匹配不到 + 怎么写」(不复述条目本身 —— 调用方的句子已点名它)。引擎判词的 `guidance` 原样带出,是改法指引的**唯一**一句
|
|
@@ -51,11 +44,4 @@ export declare function unmatchableRuleNameOf(name: string): UnmatchableRuleName
|
|
|
51
44
|
* 无前缀短名的出路从 core 的 `PROTOCOL_TABLE` 派生。闭集穷尽:判词加一种 ⇒ 编译红。
|
|
52
45
|
*/
|
|
53
46
|
export declare function describeUnmatchableRuleName(v: UnmatchableRuleName, name: string): string;
|
|
54
|
-
/**
|
|
55
|
-
* 工具段为空的协议名(`<ns>__<peer>__`)⇒ 交回它的协议;别的名字 ⇒ `undefined`。判据只读引擎:判官答 `current`(对端段为空 / 铸不出的那些 ——
|
|
56
|
-
* `mcp__`、`mcp____x` —— 是判官自己的判词,不在这里),而引擎自己的两种拆法(精确名 `ns.parse`、覆盖形 `isNamespacedCoveringRuleName`)都不认它。纯字符串运算。
|
|
57
|
-
*/
|
|
58
|
-
export declare function emptyToolSegmentOf(name: string): ProtocolNamespace | undefined;
|
|
59
|
-
/** {@link emptyToolSegmentOf} 的句子(「为什么永远匹配不到 + 怎么写」;不复述条目本身 —— 调用方的句子已点名它)。 */
|
|
60
|
-
export declare function describeEmptyToolSegment(ns: ProtocolNamespace): string;
|
|
61
47
|
//# sourceMappingURL=namespaced-rule-name.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PROTOCOL_TABLE,
|
|
1
|
+
import { PROTOCOL_TABLE, judgeRuleToolName, parsePermissionRule } from "@sema-agent/core";
|
|
2
2
|
import { displayListEntry } from "./list-entry-display.js";
|
|
3
3
|
export function ruleEntryToolName(entry) {
|
|
4
4
|
return parsePermissionRule(entry).toolName;
|
|
@@ -6,10 +6,7 @@ export function ruleEntryToolName(entry) {
|
|
|
6
6
|
export const NO_DECLARED_TOOL_NAMES = new Set();
|
|
7
7
|
export function unmatchableRuleNameOf(name) {
|
|
8
8
|
const verdict = judgeRuleToolName(name, NO_DECLARED_TOOL_NAMES);
|
|
9
|
-
|
|
10
|
-
return verdict;
|
|
11
|
-
const ns = emptyToolSegmentOf(name);
|
|
12
|
-
return ns === undefined ? undefined : { kind: "empty_tool_segment", ns };
|
|
9
|
+
return verdict.kind === "current" ? undefined : verdict;
|
|
13
10
|
}
|
|
14
11
|
export function describeUnmatchableRuleName(v, name) {
|
|
15
12
|
switch (v.kind) {
|
|
@@ -19,25 +16,10 @@ export function describeUnmatchableRuleName(v, name) {
|
|
|
19
16
|
return v.guidance;
|
|
20
17
|
case "unprefixed_namespace":
|
|
21
18
|
return `pre-prefix short form — the live name carries a protocol prefix: ${PROTOCOL_TABLE.map((e) => displayListEntry(`${e.prefix}${name}`)).join(" or ")}`;
|
|
22
|
-
case "empty_tool_segment":
|
|
23
|
-
return describeEmptyToolSegment(v.ns);
|
|
24
19
|
default: {
|
|
25
20
|
const unhandled = v;
|
|
26
21
|
throw new Error(`unhandled rule name verdict: ${JSON.stringify(unhandled)}`);
|
|
27
22
|
}
|
|
28
23
|
}
|
|
29
24
|
}
|
|
30
|
-
export function emptyToolSegmentOf(name) {
|
|
31
|
-
const ns = protocolOf(name);
|
|
32
|
-
if (ns === undefined)
|
|
33
|
-
return undefined;
|
|
34
|
-
if (judgeRuleToolName(name, NO_DECLARED_TOOL_NAMES).kind !== "current")
|
|
35
|
-
return undefined;
|
|
36
|
-
if (ns.parse(name) !== undefined || isNamespacedCoveringRuleName(name))
|
|
37
|
-
return undefined;
|
|
38
|
-
return ns;
|
|
39
|
-
}
|
|
40
|
-
export function describeEmptyToolSegment(ns) {
|
|
41
|
-
return `incomplete ${ns.id} name — the live form is ${ns.prefix}<server>__<tool>, or ${ns.prefix}<server> / ${ns.prefix}<server>__* to cover every tool on that server`;
|
|
42
|
-
}
|
|
43
25
|
//# sourceMappingURL=namespaced-rule-name.js.map
|
|
@@ -407,10 +407,6 @@ export declare const FAIL_OPEN_TAGS: {
|
|
|
407
407
|
readonly cls: "F";
|
|
408
408
|
readonly note: "S-1195(7.119.0;`plugins/snapshot-bucket-presence.ts` 的 `ensureSnapshotBucket`,boot 期核一次快照桶 `SESSION_SNAPSHOT_BUCKET`;detail = `bucket=… endpoint=<buildDisplaySafeUrl 的显示形> <HTTP 状态 | request failed: 错类>`):presigned 列举对 `MINIO_ENDPOINT` **连不上 / 403 / 5xx / 没有 NoSuchBucket 的 404**,或探针到窗尾一次都没答过(detail 写 `probe still pending when the window ended`)⇒ **证明不了桶缺**,不拒启、照常起服(只有 404 + `NoSuchBucket` 才是「缺」,那一形窗内重试、到窗拒启,不走本 tag)。三问:①错误落到哪 —— 本 tag 的计数 / 探针行 / 记录器的一次性 warn,detail 带端点显示形与状态或错类;②谁受害 —— 桶其实不存在、或凭据不能列举的部署:之后每一次快照 offload 写与 SendUserFile 私有 presigned 请求会答 404 / 403,孤儿 sweep 每分钟一条失败,运维读到的是一串失败请求而不是「桶没建」(与 7.118.x 的既有形状同形,不是新损失);③缺席倒向哪边 —— 倒向**放行起服**:没有证据既不拒启、也不伪造「桶在场」或「桶缺」,不是门 / 权限 / 凭证。最坏后果 = 缺桶的部署晚一步才暴露;不放行的代价是对象存储一次抖动 / 一次 403 就让整只服务起不来。计数非零 = 这台部署启动时没能确认快照桶,按 detail 的端点与状态去核对网络 / 凭据 / 桶。";
|
|
409
409
|
};
|
|
410
|
-
readonly "server.config-lkg.landed-path-unresolved": {
|
|
411
|
-
readonly cls: "P-DEBT";
|
|
412
|
-
readonly note: "7.120.0(`config-lkg.ts` 的 `landedPathOf`,`lkgReadDenyRows` 每次铸部署姿态座席时调;detail = `segment=<那一段的路径>`):`CONFIG_LKG_PATH` 覆写路径上有一段**目录在、却解不开**(悬空符号链接 / 链接环 / 读不了的目录:`realpath` 失败而 `lstat` 不说「不存在」)⇒ 这一段之下 LKG 真正会落在哪说不出来,读拒行只剩声明的拼写那一行(照旧在),真实落点那一行缺席。段**不存在**(`ENOENT` / `ENOTDIR`:还没建出来)是常态,不进这一臂;末段(文件本身)是悬空链接也不进(落盘的 rename 换掉的是那条目录项,文件就落在声明的拼写上)。归 P 的理由:这一行守的是 LKG 文件(含凭据),链接之后通了、LKG 写到链接目标下,模型按目标路径读得到它,直到重启重铸座席。归 DEBT 的理由:引擎没有「锚定单文件」的读拒行、座席只在 Runner 构造时铸一次,本服务说不出将来的落点;拿文件名在任意深度拒会把用户仓里同名文件一并挡掉。计数非零 = 去看 detail 点名的那一段(链接指向哪、卷挂了没有),修好后重启。";
|
|
413
|
-
};
|
|
414
410
|
readonly "server.fleet.serving-lease-unconfirmed": {
|
|
415
411
|
readonly cls: "R";
|
|
416
412
|
readonly ruling: "C-R296";
|
|
@@ -367,10 +367,6 @@ export const FAIL_OPEN_TAGS = {
|
|
|
367
367
|
cls: "F",
|
|
368
368
|
note: "S-1195(7.119.0;`plugins/snapshot-bucket-presence.ts` 的 `ensureSnapshotBucket`,boot 期核一次快照桶 `SESSION_SNAPSHOT_BUCKET`;detail = `bucket=… endpoint=<buildDisplaySafeUrl 的显示形> <HTTP 状态 | request failed: 错类>`):presigned 列举对 `MINIO_ENDPOINT` **连不上 / 403 / 5xx / 没有 NoSuchBucket 的 404**,或探针到窗尾一次都没答过(detail 写 `probe still pending when the window ended`)⇒ **证明不了桶缺**,不拒启、照常起服(只有 404 + `NoSuchBucket` 才是「缺」,那一形窗内重试、到窗拒启,不走本 tag)。三问:①错误落到哪 —— 本 tag 的计数 / 探针行 / 记录器的一次性 warn,detail 带端点显示形与状态或错类;②谁受害 —— 桶其实不存在、或凭据不能列举的部署:之后每一次快照 offload 写与 SendUserFile 私有 presigned 请求会答 404 / 403,孤儿 sweep 每分钟一条失败,运维读到的是一串失败请求而不是「桶没建」(与 7.118.x 的既有形状同形,不是新损失);③缺席倒向哪边 —— 倒向**放行起服**:没有证据既不拒启、也不伪造「桶在场」或「桶缺」,不是门 / 权限 / 凭证。最坏后果 = 缺桶的部署晚一步才暴露;不放行的代价是对象存储一次抖动 / 一次 403 就让整只服务起不来。计数非零 = 这台部署启动时没能确认快照桶,按 detail 的端点与状态去核对网络 / 凭据 / 桶。",
|
|
369
369
|
},
|
|
370
|
-
"server.config-lkg.landed-path-unresolved": {
|
|
371
|
-
cls: "P-DEBT",
|
|
372
|
-
note: "7.120.0(`config-lkg.ts` 的 `landedPathOf`,`lkgReadDenyRows` 每次铸部署姿态座席时调;detail = `segment=<那一段的路径>`):`CONFIG_LKG_PATH` 覆写路径上有一段**目录在、却解不开**(悬空符号链接 / 链接环 / 读不了的目录:`realpath` 失败而 `lstat` 不说「不存在」)⇒ 这一段之下 LKG 真正会落在哪说不出来,读拒行只剩声明的拼写那一行(照旧在),真实落点那一行缺席。段**不存在**(`ENOENT` / `ENOTDIR`:还没建出来)是常态,不进这一臂;末段(文件本身)是悬空链接也不进(落盘的 rename 换掉的是那条目录项,文件就落在声明的拼写上)。归 P 的理由:这一行守的是 LKG 文件(含凭据),链接之后通了、LKG 写到链接目标下,模型按目标路径读得到它,直到重启重铸座席。归 DEBT 的理由:引擎没有「锚定单文件」的读拒行、座席只在 Runner 构造时铸一次,本服务说不出将来的落点;拿文件名在任意深度拒会把用户仓里同名文件一并挡掉。计数非零 = 去看 detail 点名的那一段(链接指向哪、卷挂了没有),修好后重启。",
|
|
373
|
-
},
|
|
374
370
|
"server.fleet.serving-lease-unconfirmed": {
|
|
375
371
|
cls: "R",
|
|
376
372
|
ruling: "C-R296",
|
|
@@ -23,7 +23,7 @@ export declare class Metrics {
|
|
|
23
23
|
/** Structured snapshot of the whole registry — the OTLP exporter maps this to OTel data points
|
|
24
24
|
* (counters→Sum monotonic, gauges/dynamic→Gauge, histograms→Histogram). Read-only copy. */
|
|
25
25
|
snapshot(): MetricSnapshot;
|
|
26
|
-
/** Curated health summary (friendly JSON) for a lightweight fleet dashboard — the
|
|
26
|
+
/** Curated health summary (friendly JSON) for a lightweight fleet dashboard — the web-admin's
|
|
27
27
|
* fleet page fetches this per worker and renders cards + computes rates over polls (no Prometheus
|
|
28
28
|
* needed). Counters are cumulative totals; histograms are reported as averages (sum/count). */
|
|
29
29
|
summarize(): MetricsSummary;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Org 记忆准入 resolver — server 侧对接 @sema-agent/core@5.13.0 `RunnerDeps.memoryScopeAdmission` seam。
|
|
3
|
-
* 授权事实来自「目录」抽象:远程腿 =
|
|
3
|
+
* 授权事实来自「目录」抽象:远程腿 = web-admin per-principal caps 响应里的 `orgMemory` 段(形状
|
|
4
4
|
* 同源锚 = registry-core `PrincipalOrgMemoryWire`,zod schema 直接 safeParse);单机腿 = env JSON 静态表
|
|
5
5
|
* (`MEMORY_ORG_DIRECTORY_JSON`,{@link parseOrgDirectoryStatic} 装载,启动期 fail-loud)。
|
|
6
6
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AskState } from "../approval-ask-machine.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { SettleCause } from "../approval-deny-reasons.js";
|
|
3
|
+
import type { AskCallCoordinate, AskRow, AskTerminalClaimIntent, AskTerminalClaimOpts, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, DecideResult, EnsureAskResult, ExpireResult, NewAskRow } from "./approval-ask-store-sql.js";
|
|
3
4
|
/** 数据根下的目录名。**按店命名**,与兄弟 File 店同规(`approval-nonces` / `approval-ask-audit` /
|
|
4
5
|
* `approval-exemptions` / `resume-anchors` / `checkpoint-ctx` / …)—— 首版写的是族名 `approvals`,而那
|
|
5
6
|
* 正是读者会去找**持久 park 行**的地方(它们其实在 `checkpoint-ctx`),且持久数据面的名字按硬 breaking
|
|
@@ -61,6 +62,7 @@ type JournalCall = {
|
|
|
61
62
|
askId: string;
|
|
62
63
|
batchId: string;
|
|
63
64
|
intent: JournalV1ClaimIntent;
|
|
65
|
+
cause?: SettleCause;
|
|
64
66
|
}
|
|
65
67
|
/** NP-2 的部署政策拒(`claimTerminal(…, "refuse")`)—— 新动词而不是老动词带新意图,理由见 {@link JOURNAL_V1_CLAIM_INTENTS}。 */
|
|
66
68
|
| {
|
|
@@ -162,7 +164,7 @@ export declare class FileApprovalAskStore implements ApprovalAskStore {
|
|
|
162
164
|
* 「先编码、编码成功才一次性提交」同一条原子性)。
|
|
163
165
|
*/
|
|
164
166
|
decideAsk(askId: string, batchId: string, decision: DecideAskInput): Promise<DecideResult>;
|
|
165
|
-
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent): Promise<AskTerminalClaimOutcome>;
|
|
167
|
+
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent, opts?: AskTerminalClaimOpts): Promise<AskTerminalClaimOutcome>;
|
|
166
168
|
expireAsk(askId: string, batchId: string): Promise<ExpireResult>;
|
|
167
169
|
bindBatch(batchId: string, askId: string, gate: BindGateInput): Promise<BindResult>;
|
|
168
170
|
abortBatch(batchId: string): Promise<string[]>;
|
|
@@ -182,7 +182,7 @@ export class FileApprovalAskStore {
|
|
|
182
182
|
case "decideAsk":
|
|
183
183
|
return this.core.decideAsk(rec.askId, rec.batchId, rec.decision);
|
|
184
184
|
case "claimTerminal":
|
|
185
|
-
return this.core.claimTerminal(rec.askId, rec.batchId, rec.intent);
|
|
185
|
+
return this.core.claimTerminal(rec.askId, rec.batchId, rec.intent, rec.cause !== undefined ? { cause: rec.cause } : undefined);
|
|
186
186
|
case "claimTerminalRefuse":
|
|
187
187
|
return this.core.claimTerminal(rec.askId, rec.batchId, "refuse");
|
|
188
188
|
case "expireAsk":
|
|
@@ -213,11 +213,11 @@ export class FileApprovalAskStore {
|
|
|
213
213
|
const journalled = decision.updatedInput === undefined ? decision : { ...decision, updatedInput: encodeDecideUpdatedInput(decision.updatedInput) };
|
|
214
214
|
return this.write({ op: "decideAsk", askId, batchId, decision: journalled }, (c) => this.core.decideAsk(c.askId, c.batchId, c.decision));
|
|
215
215
|
}
|
|
216
|
-
async claimTerminal(askId, batchId, intent) {
|
|
216
|
+
async claimTerminal(askId, batchId, intent, opts) {
|
|
217
217
|
switch (intent) {
|
|
218
218
|
case "expire":
|
|
219
219
|
case "cancel":
|
|
220
|
-
return this.write({ op: "claimTerminal", askId, batchId, intent }, (c) => this.core.claimTerminal(c.askId, c.batchId, c.intent));
|
|
220
|
+
return this.write({ op: "claimTerminal", askId, batchId, intent, ...(opts?.cause !== undefined ? { cause: opts.cause } : {}) }, (c) => this.core.claimTerminal(c.askId, c.batchId, c.intent, c.cause !== undefined ? { cause: c.cause } : undefined));
|
|
221
221
|
case "refuse":
|
|
222
222
|
return this.write({ op: "claimTerminalRefuse", askId, batchId }, (c) => this.core.claimTerminal(c.askId, c.batchId, "refuse"));
|
|
223
223
|
default: {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* - resolveProvisional 故意不经 canAskTransition(同 SQL twin 头注:这是版本化补偿的例外通道)。
|
|
26
26
|
*/
|
|
27
27
|
import { type AskState, type BatchState } from "../approval-ask-machine.js";
|
|
28
|
-
import type { AskCallCoordinate, AskDecision, AskRow, AskTerminalClaimIntent, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, EnsureAskResult, DecideResult, ExpireResult, NewAskRow } from "./approval-ask-store-sql.js";
|
|
28
|
+
import type { AskCallCoordinate, AskDecision, AskRow, AskTerminalClaimIntent, AskTerminalClaimOpts, AskTerminalClaimOutcome, AskTransitionPatch, ApprovalAskStore, BatchRow, BindGateInput, BindResult, DecideAskInput, EnsureAskResult, DecideResult, ExpireResult, NewAskRow } from "./approval-ask-store-sql.js";
|
|
29
29
|
/**
|
|
30
30
|
* [ref] 的 `updatedInput` **入店编码**——两 twin 共用的那一只(本函数是唯一真源)。
|
|
31
31
|
*
|
|
@@ -88,8 +88,9 @@ export declare class InMemoryApprovalAskStore implements ApprovalAskStore {
|
|
|
88
88
|
* 论证);await 后读到的行 ≥ CAS 线性化点,而非 pending 态无回边 ⇒ 败方读数自足(与 SQL 侧同一条
|
|
89
89
|
* 单调性论证)。
|
|
90
90
|
*/
|
|
91
|
-
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent): Promise<AskTerminalClaimOutcome>;
|
|
92
|
-
expireAsk(
|
|
91
|
+
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent, opts?: AskTerminalClaimOpts): Promise<AskTerminalClaimOutcome>;
|
|
92
|
+
/** `cause`(可选)= 转 park 的触发成因,赢下 PARKING 的同一步落进 `deniedReason`(SQL twin 同一条 UPDATE 的镜像;接口上的 `expireAsk` 不带它,只有 `claimTerminal(expire, { cause })` 带)。 */
|
|
93
|
+
expireAsk(askId: string, batchId: string, cause?: AskTerminalClaimOpts["cause"]): Promise<ExpireResult>;
|
|
93
94
|
bindBatch(batchId: string, askId: string, gate: BindGateInput): Promise<BindResult>;
|
|
94
95
|
deferReconcile(askId: string, expectedState: AskState, expectedRev: number, nowMs: number): Promise<boolean>;
|
|
95
96
|
abortBatch(batchId: string): Promise<string[]>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { canAskTransition } from "../approval-ask-machine.js";
|
|
2
|
+
import { APPROVAL_ENDING_CAUSES } from "../approval-deny-reasons.js";
|
|
2
3
|
import { askRowOnCall, assertDecideSettledBy, assertIdempotencyKeyShape, assertIntegralEpochMs, ApprovalAskReadAbortedError, claimTargetState, POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./approval-ask-store-sql.js";
|
|
3
4
|
function applyPatch(row, patch) {
|
|
4
5
|
if (patch.decision !== undefined)
|
|
@@ -152,10 +153,10 @@ export class InMemoryApprovalAskStore {
|
|
|
152
153
|
ask.updatedAtMs = now;
|
|
153
154
|
return { ok: true, row: { ...ask } };
|
|
154
155
|
}
|
|
155
|
-
async claimTerminal(askId, batchId, intent) {
|
|
156
|
+
async claimTerminal(askId, batchId, intent, opts) {
|
|
156
157
|
switch (intent) {
|
|
157
158
|
case "expire": {
|
|
158
|
-
const res = await this.expireAsk(askId, batchId);
|
|
159
|
+
const res = await this.expireAsk(askId, batchId, opts?.cause);
|
|
159
160
|
if (res.won)
|
|
160
161
|
return { claimed: true, voidedSiblings: res.voidedSiblings };
|
|
161
162
|
break;
|
|
@@ -164,7 +165,7 @@ export class InMemoryApprovalAskStore {
|
|
|
164
165
|
const scoped = this.asks.get(askId);
|
|
165
166
|
if (scoped !== undefined && scoped.batchId !== batchId)
|
|
166
167
|
return { claimed: false, current: { state: "absent" } };
|
|
167
|
-
const won = await this.transitionAsk(askId, "STREAM_PENDING", "VOID", { updatedAtMs: this.now() });
|
|
168
|
+
const won = await this.transitionAsk(askId, "STREAM_PENDING", "VOID", { updatedAtMs: this.now(), ...(opts?.cause !== undefined ? { deniedReason: opts.cause } : {}) });
|
|
168
169
|
if (won)
|
|
169
170
|
return { claimed: true, voidedSiblings: [] };
|
|
170
171
|
break;
|
|
@@ -195,7 +196,7 @@ export class InMemoryApprovalAskStore {
|
|
|
195
196
|
const cur = this.asks.get(askId);
|
|
196
197
|
return { claimed: false, current: projectAskTerminalClaimTruth(cur !== undefined && cur.batchId === batchId ? { ...cur } : null) };
|
|
197
198
|
}
|
|
198
|
-
async expireAsk(askId, batchId) {
|
|
199
|
+
async expireAsk(askId, batchId, cause) {
|
|
199
200
|
const now = this.now();
|
|
200
201
|
const batch = this.batches.get(batchId);
|
|
201
202
|
if (!batch)
|
|
@@ -204,6 +205,8 @@ export class InMemoryApprovalAskStore {
|
|
|
204
205
|
if (!ask || ask.state !== "STREAM_PENDING" || ask.batchId !== batchId)
|
|
205
206
|
return { won: false, voidedSiblings: [] };
|
|
206
207
|
ask.state = "PARKING";
|
|
208
|
+
if (cause !== undefined)
|
|
209
|
+
ask.deniedReason = cause;
|
|
207
210
|
ask.rev += 1;
|
|
208
211
|
ask.updatedAtMs = now;
|
|
209
212
|
if (batch.state === "OPEN") {
|
|
@@ -215,6 +218,7 @@ export class InMemoryApprovalAskStore {
|
|
|
215
218
|
for (const [id, r] of this.asks) {
|
|
216
219
|
if (r.batchId === batchId && r.state === "STREAM_PENDING" && id !== askId) {
|
|
217
220
|
r.state = "VOID";
|
|
221
|
+
r.deniedReason = APPROVAL_ENDING_CAUSES.BATCH_SIBLING_WITHDRAWN;
|
|
218
222
|
r.rev += 1;
|
|
219
223
|
r.updatedAtMs = now;
|
|
220
224
|
voided.push(id);
|
|
@@ -247,6 +251,7 @@ export class InMemoryApprovalAskStore {
|
|
|
247
251
|
for (const [id, r] of this.asks) {
|
|
248
252
|
if (r.batchId === batchId && r.state === "PARKING" && id !== askId) {
|
|
249
253
|
r.state = "VOID";
|
|
254
|
+
r.deniedReason = APPROVAL_ENDING_CAUSES.BATCH_BOUND_ELSEWHERE;
|
|
250
255
|
r.rev += 1;
|
|
251
256
|
r.updatedAtMs = now;
|
|
252
257
|
voidedSiblings.push(id);
|
|
@@ -274,6 +279,7 @@ export class InMemoryApprovalAskStore {
|
|
|
274
279
|
for (const [id, r] of this.asks) {
|
|
275
280
|
if (r.batchId === batchId && r.state === "STREAM_PENDING") {
|
|
276
281
|
r.state = "VOID";
|
|
282
|
+
r.deniedReason = APPROVAL_ENDING_CAUSES.BATCH_ABORTED;
|
|
277
283
|
r.rev += 1;
|
|
278
284
|
r.updatedAtMs = now;
|
|
279
285
|
voided.push(id);
|
|
@@ -42,6 +42,7 @@ import type { PgQueryFn } from "./pg-query.js";
|
|
|
42
42
|
import { type SqlDriver, type SqlDialect } from "./sql-driver.js";
|
|
43
43
|
import { type AskState, type BatchState } from "../approval-ask-machine.js";
|
|
44
44
|
import type { HostSettledBy } from "../host-decision.js";
|
|
45
|
+
import { type AskRowCause, type SettleCause } from "../approval-deny-reasons.js";
|
|
45
46
|
import { type IndexSpec } from "./ensure-index.js";
|
|
46
47
|
export type AskDecision = "approve" | "deny";
|
|
47
48
|
export interface AskRow {
|
|
@@ -317,6 +318,15 @@ export interface ExpireResult {
|
|
|
317
318
|
* WHERE 谓词 {@link pendingClaimWhere} 兑现,不是把不同 verb 塞进一个函数。
|
|
318
319
|
*/
|
|
319
320
|
export type AskTerminalClaimIntent = "expire" | "cancel" | "refuse";
|
|
321
|
+
/**
|
|
322
|
+
* 终局 claim 的可选实参:`cause` —— **赢下 `cancel`(VOID)/ `expire`(PARKING)时写进这一行 `denied_reason` 列的成因词**(决断口 410 / 晚答 404 / 跨副本的败方读数读同一列,
|
|
323
|
+
* 所以这一行自己记着「为什么」,读面不靠任何进程内的东西)。`cancel` 写终态成因({@link SettleCause} 里的 `run_cancelled` / `run_exited`),
|
|
324
|
+
* `expire` 写转 park 的触发成因({@link ParkTriggerCause}:`ttl_expired` / `broadcast_lost` / `stream_disconnected` / `undeliverable` / `shutdown_before_park`);缺席 ⇒ 列保持 NULL(读面缺席即缺席)。
|
|
325
|
+
* `refuse` 不读它(落的是一条决议,来源位 `policy`,不是结局成因);`expire` 撤兄弟时店自己写 `batch_sibling_withdrawn`(那是这条事务本身的事实)。
|
|
326
|
+
*/
|
|
327
|
+
export interface AskTerminalClaimOpts {
|
|
328
|
+
readonly cause?: SettleCause;
|
|
329
|
+
}
|
|
320
330
|
/**
|
|
321
331
|
* `refuse` 意图落行的决议(NP-2)—— **部署政策拒**:deny + 结算来源 `policy`。来源词的型取 core 的 `HostSettledBy`
|
|
322
332
|
* (core 改词 / 退词 ⇒ 这里 tsc 红);协调器交给 core 的那一只(`tool-approval.ts` 的 `UnattendedPolicyRefusal`)读的是
|
|
@@ -353,6 +363,10 @@ export type AskTerminalClaimCurrent = {
|
|
|
353
363
|
/** S-558:赢家决议的**结算来源**(语义与两态读法见 {@link AskRow.settledBy})。**必填**(不是可选)——
|
|
354
364
|
* 可选会让投影漏挑这一列时静默编译过,而漏挑的后果恰是本批要修的病:CAS 输家把赢家的策略拒读成人拒。 */
|
|
355
365
|
settledBy: HostSettledBy | null;
|
|
366
|
+
/** 行上记着的成因,经问账行成因的唯一读口 `causeOfAskRow` 读出(`kind` 说它在这一行上的意思:VOID / DENIED = 终态成因,PARKING / PARKED = 转 park 的触发成因);
|
|
367
|
+
* **只在读得出时在场**(没写 / 与 state 不配 ⇒ 缺席;DECIDED 的败方读数逐字不变)。CAS 输家据它按**行上那个成因**结算(而不是把别人撤的卡读成一次拒绝);
|
|
368
|
+
* 投影的唯一函数是 {@link projectAskTerminalClaimTruth},三 twin 不各自挑列,原始列值不出店层。 */
|
|
369
|
+
cause?: AskRowCause;
|
|
356
370
|
};
|
|
357
371
|
/**
|
|
358
372
|
* 单次原子往返的答案(语义律的唯一规范陈述点 = core `checkpoint-store.ts` `claimTerminal` 契约 JSDoc,
|
|
@@ -424,7 +438,7 @@ export interface ApprovalAskStore {
|
|
|
424
438
|
* `expireAsk`/`transitionAsk`(InMemory,单线程天然原子)——两向都成立的判据是**没有第二套谓词**。
|
|
425
439
|
* 方法**必备**(本仓自有三形全实现,无 core 那侧的 presence 探测问题)。
|
|
426
440
|
*/
|
|
427
|
-
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent): Promise<AskTerminalClaimOutcome>;
|
|
441
|
+
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent, opts?: AskTerminalClaimOpts): Promise<AskTerminalClaimOutcome>;
|
|
428
442
|
expireAsk(askId: string, batchId: string): Promise<ExpireResult>;
|
|
429
443
|
bindBatch(batchId: string, askId: string, gate: BindGateInput): Promise<BindResult>;
|
|
430
444
|
abortBatch(batchId: string): Promise<string[]>;
|
|
@@ -624,7 +638,7 @@ export declare class SqlApprovalAskStore implements ApprovalAskStore {
|
|
|
624
638
|
* 在状态机上无回边 ⇒ 锁定读读到的恒 ≥ 线性化点,且 DECIDED 决议不可变 —— 答案自足。
|
|
625
639
|
* · 本事务在输臂上除批行 rev 自增外零写,rollback 无痕。
|
|
626
640
|
*/
|
|
627
|
-
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent): Promise<AskTerminalClaimOutcome>;
|
|
641
|
+
claimTerminal(askId: string, batchId: string, intent: AskTerminalClaimIntent, opts?: AskTerminalClaimOpts): Promise<AskTerminalClaimOutcome>;
|
|
628
642
|
/** [ref] 起 = {@link claimTerminal}(expire 意图)的薄投影 —— 律 2「在 claimTerminal 之上实现」的
|
|
629
643
|
* SQL 半场落笔处:谓词/事务/兄弟撤卡全在 claim 里,这里零第二套写路径。败方读数按既有返回形丢弃
|
|
630
644
|
* (`ExpireResult` 不携真相 —— 要真相的调用方直接用 claimTerminal;对账收敛器的 orphan 腿输了本就
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mysqlDriver, pgDriver, dialectJsonEncoder } from "./sql-driver.js";
|
|
2
2
|
import { canAskTransition } from "../approval-ask-machine.js";
|
|
3
|
+
import { APPROVAL_ENDING_CAUSES, causeOfAskRow } from "../approval-deny-reasons.js";
|
|
3
4
|
import { isDupKeyError, isMissingColumnError } from "./sql-errors.js";
|
|
4
5
|
import { decodeJsonColumn, foldJsonColumn, jsonColumnText, readJsonObjectColumn, readTriStateJsonValueColumn } from "./sql-json-column.js";
|
|
5
6
|
import { ensureIndexes } from "./ensure-index.js";
|
|
@@ -70,12 +71,14 @@ export function claimTargetState(intent) {
|
|
|
70
71
|
export function projectAskTerminalClaimTruth(row) {
|
|
71
72
|
if (row === null || row.state === "STREAM_PENDING")
|
|
72
73
|
return { state: "absent" };
|
|
74
|
+
const cause = causeOfAskRow(row);
|
|
73
75
|
return {
|
|
74
76
|
state: row.state,
|
|
75
77
|
rev: row.rev,
|
|
76
78
|
decision: row.decision,
|
|
77
79
|
...(row.updatedInput !== undefined ? { updatedInput: row.updatedInput } : {}),
|
|
78
80
|
settledBy: row.settledBy,
|
|
81
|
+
...(cause !== undefined ? { cause } : {}),
|
|
79
82
|
};
|
|
80
83
|
}
|
|
81
84
|
export function askRowOnCall(row, call) {
|
|
@@ -501,7 +504,7 @@ export class SqlApprovalAskStore {
|
|
|
501
504
|
throw new Error(`decideAsk: row vanished after commit (askId=${askId})`);
|
|
502
505
|
return { ok: true, row };
|
|
503
506
|
}
|
|
504
|
-
async claimTerminal(askId, batchId, intent) {
|
|
507
|
+
async claimTerminal(askId, batchId, intent, opts) {
|
|
505
508
|
const to = claimTargetState(intent);
|
|
506
509
|
if (!canAskTransition("STREAM_PENDING", to)) {
|
|
507
510
|
throw new Error(`approval-ask-store.claimTerminal: illegal terminal claim STREAM_PENDING -> ${to} (askId=${askId})`);
|
|
@@ -522,12 +525,15 @@ export class SqlApprovalAskStore {
|
|
|
522
525
|
}
|
|
523
526
|
const askRes = intent === "refuse"
|
|
524
527
|
? await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)}, decision = ${ph(dialect, 2)}, settled_by = ${ph(dialect, 3)}, decided_at_ms = ${ph(dialect, 4)}, rev = rev + 1, updated_at_ms = ${ph(dialect, 5)} WHERE ${pendingClaimWhere(dialect, 6)}`, [to, POLICY_REFUSAL_DECISION.decision, POLICY_REFUSAL_DECISION.settledBy, now, now, askId, batchId])
|
|
525
|
-
:
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
528
|
+
: (intent === "cancel" || intent === "expire") && opts?.cause !== undefined
|
|
529
|
+
?
|
|
530
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)}, denied_reason = ${ph(dialect, 2)}, rev = rev + 1, updated_at_ms = ${ph(dialect, 3)} WHERE ${pendingClaimWhere(dialect, 4)}`, [to, opts.cause, now, askId, batchId])
|
|
531
|
+
: await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state = ${ph(dialect, 1)}, rev = rev + 1, updated_at_ms = ${ph(dialect, 2)} WHERE ${pendingClaimWhere(dialect, 3)}`, [
|
|
532
|
+
to,
|
|
533
|
+
now,
|
|
534
|
+
askId,
|
|
535
|
+
batchId,
|
|
536
|
+
]);
|
|
531
537
|
if (askRes.affected !== 1) {
|
|
532
538
|
const sel = await conn.query(`SELECT ${askCols(dialect)} FROM ${APPROVAL_ASK_TABLE} WHERE ask_id = ${ph(dialect, 1)} AND batch_id = ${ph(dialect, 2)} FOR UPDATE`, [askId, batchId]);
|
|
533
539
|
await conn.rollback();
|
|
@@ -540,7 +546,7 @@ export class SqlApprovalAskStore {
|
|
|
540
546
|
await conn.query(this.q(`UPDATE ${APPROVAL_BATCH_TABLE} SET state='ROUTING_UNBOUND', rev=rev+1, updated_at_ms=? WHERE batch_id=? AND state='OPEN'`, `UPDATE ${APPROVAL_BATCH_TABLE} SET state='ROUTING_UNBOUND', rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='OPEN'`), [now, batchId]);
|
|
541
547
|
let voidedSiblings;
|
|
542
548
|
if (this.db.dialect === "pg") {
|
|
543
|
-
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='STREAM_PENDING' AND ask_id<>$3 RETURNING ask_id`, [now, batchId, askId]);
|
|
549
|
+
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', denied_reason=$4, rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='STREAM_PENDING' AND ask_id<>$3 RETURNING ask_id`, [now, batchId, askId, APPROVAL_ENDING_CAUSES.BATCH_SIBLING_WITHDRAWN]);
|
|
544
550
|
voidedSiblings = res.rows.map((r) => String(r.ask_id));
|
|
545
551
|
}
|
|
546
552
|
else {
|
|
@@ -548,7 +554,8 @@ export class SqlApprovalAskStore {
|
|
|
548
554
|
voidedSiblings = sel.rows.map((r) => String(r.ask_id));
|
|
549
555
|
if (voidedSiblings.length > 0) {
|
|
550
556
|
const inList = voidedSiblings.map(() => "?").join(", ");
|
|
551
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='STREAM_PENDING'`, [
|
|
557
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', denied_reason=?, rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='STREAM_PENDING'`, [
|
|
558
|
+
APPROVAL_ENDING_CAUSES.BATCH_SIBLING_WITHDRAWN,
|
|
552
559
|
now,
|
|
553
560
|
...voidedSiblings,
|
|
554
561
|
]);
|
|
@@ -593,7 +600,7 @@ export class SqlApprovalAskStore {
|
|
|
593
600
|
}
|
|
594
601
|
let voidedSiblings;
|
|
595
602
|
if (this.db.dialect === "pg") {
|
|
596
|
-
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='PARKING' AND ask_id<>$3 RETURNING ask_id`, [now, batchId, askId]);
|
|
603
|
+
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', denied_reason=$4, rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='PARKING' AND ask_id<>$3 RETURNING ask_id`, [now, batchId, askId, APPROVAL_ENDING_CAUSES.BATCH_BOUND_ELSEWHERE]);
|
|
597
604
|
voidedSiblings = res.rows.map((r) => String(r.ask_id));
|
|
598
605
|
}
|
|
599
606
|
else {
|
|
@@ -601,7 +608,7 @@ export class SqlApprovalAskStore {
|
|
|
601
608
|
voidedSiblings = sel.rows.map((r) => String(r.ask_id));
|
|
602
609
|
if (voidedSiblings.length > 0) {
|
|
603
610
|
const inList = voidedSiblings.map(() => "?").join(", ");
|
|
604
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='PARKING'`, [now, ...voidedSiblings]);
|
|
611
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', denied_reason=?, rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='PARKING'`, [APPROVAL_ENDING_CAUSES.BATCH_BOUND_ELSEWHERE, now, ...voidedSiblings]);
|
|
605
612
|
}
|
|
606
613
|
}
|
|
607
614
|
await conn.commit();
|
|
@@ -631,7 +638,7 @@ export class SqlApprovalAskStore {
|
|
|
631
638
|
}
|
|
632
639
|
let voided;
|
|
633
640
|
if (this.db.dialect === "pg") {
|
|
634
|
-
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='STREAM_PENDING' RETURNING ask_id`, [now, batchId]);
|
|
641
|
+
const res = await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', denied_reason=$3, rev=rev+1, updated_at_ms=$1 WHERE batch_id=$2 AND state='STREAM_PENDING' RETURNING ask_id`, [now, batchId, APPROVAL_ENDING_CAUSES.BATCH_ABORTED]);
|
|
635
642
|
voided = res.rows.map((r) => String(r.ask_id));
|
|
636
643
|
}
|
|
637
644
|
else {
|
|
@@ -639,7 +646,7 @@ export class SqlApprovalAskStore {
|
|
|
639
646
|
voided = sel.rows.map((r) => String(r.ask_id));
|
|
640
647
|
if (voided.length > 0) {
|
|
641
648
|
const inList = voided.map(() => "?").join(", ");
|
|
642
|
-
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='STREAM_PENDING'`, [now, ...voided]);
|
|
649
|
+
await conn.query(`UPDATE ${APPROVAL_ASK_TABLE} SET state='VOID', denied_reason=?, rev=rev+1, updated_at_ms=? WHERE ask_id IN (${inList}) AND state='STREAM_PENDING'`, [APPROVAL_ENDING_CAUSES.BATCH_ABORTED, now, ...voided]);
|
|
643
650
|
}
|
|
644
651
|
}
|
|
645
652
|
await conn.commit();
|
|
@@ -57,16 +57,6 @@ export declare class CachingSessionStore implements SessionStore {
|
|
|
57
57
|
}) => Promise<SessionListItem[]>;
|
|
58
58
|
readonly fork?: (sourceId: string, owner: string | null) => Promise<string | null>;
|
|
59
59
|
readonly deleteSession?: (sessionId: string, owner: string | null) => Promise<boolean>;
|
|
60
|
-
/** K-5c (core 1.155 SessionStore.noteTaskRun seam) — core's Runner calls it at runTask START to record the latest
|
|
61
|
-
* run per session (→ listSessions `lastRunId`). MUST be forwarded: the local backend's Runner store is THIS cache
|
|
62
|
-
* wrapper, so without forwarding `noteTaskRun?.()` silently no-ops and lastRunId stays null (review BLOCKER). Pure
|
|
63
|
-
* pass-through to the inner store's in-mem map — no cache interaction. (TiDB/PG don't implement it → not bound.)
|
|
64
|
-
* Return type matches core's `SessionStore.noteTaskRun?(): void | Promise<void>` (review: don't narrow to void).
|
|
65
|
-
* [ref](core 5.65 增量批):第三参 = engine runId。绑定用的是 `.bind(inner)`(整函数),运行期本就
|
|
66
|
-
* 三参全转 —— 这里把**声明**对齐到 core 的三参形,免得读这行类型的人以为缝上只有两参(fork-routing
|
|
67
|
-
* 的两参形正是在运行期真丢过第三参的那个病,同批修)。内店(LocalSessionStore)今日仍是两参消费,
|
|
68
|
-
* runId 落地候 sessions 列表 wire 键的 spec 节拍(见本批提货报告件1b)。 */
|
|
69
|
-
readonly noteTaskRun?: (sessionId: string, taskId: string, runId?: string) => void | Promise<void>;
|
|
70
60
|
/** Write-once auto-title (SQL twins + local sidecar carry it; pure pass-through). */
|
|
71
61
|
readonly setTitleIfNull?: (sessionId: string, title: string) => Promise<boolean>;
|
|
72
62
|
readonly probeTitle?: (sessionId: string) => Promise<"none" | "untitled" | "titled">;
|
|
@@ -11,7 +11,6 @@ export class CachingSessionStore {
|
|
|
11
11
|
listSessions;
|
|
12
12
|
fork;
|
|
13
13
|
deleteSession;
|
|
14
|
-
noteTaskRun;
|
|
15
14
|
setTitleIfNull;
|
|
16
15
|
probeTitle;
|
|
17
16
|
readInstructionSource;
|
|
@@ -62,8 +61,6 @@ export class CachingSessionStore {
|
|
|
62
61
|
this.recordInstructionSource = ownerAware.recordInstructionSource.bind(inner);
|
|
63
62
|
if (ownerAware.fork)
|
|
64
63
|
this.fork = ownerAware.fork.bind(inner);
|
|
65
|
-
if (ownerAware.noteTaskRun)
|
|
66
|
-
this.noteTaskRun = ownerAware.noteTaskRun.bind(inner);
|
|
67
64
|
if (ownerAware.getLeafId)
|
|
68
65
|
this.getLeafId = ownerAware.getLeafId.bind(inner);
|
|
69
66
|
if (ownerAware.getHead)
|
|
@@ -499,9 +499,15 @@ export class FileRunStore {
|
|
|
499
499
|
const sorted = [...arr].sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime() || (a.taskId < b.taskId ? 1 : a.taskId > b.taskId ? -1 : 0));
|
|
500
500
|
const latest = sorted[0];
|
|
501
501
|
const latestRunId = latest.result?.runId;
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
const
|
|
502
|
+
let last = -Infinity;
|
|
503
|
+
let first = Infinity;
|
|
504
|
+
for (const r of arr) {
|
|
505
|
+
const t = r.createdAt.getTime();
|
|
506
|
+
if (t > last)
|
|
507
|
+
last = t;
|
|
508
|
+
if (t < first)
|
|
509
|
+
first = t;
|
|
510
|
+
}
|
|
505
511
|
summaries.push({
|
|
506
512
|
sessionId,
|
|
507
513
|
owner: latest.owner,
|
|
@@ -12,8 +12,9 @@ export interface LeaderRunRecord {
|
|
|
12
12
|
status: LeaderRunStatus;
|
|
13
13
|
/** BL-4 属主(null = 匿名/单租)。GET 的 404 门读它。 */
|
|
14
14
|
owner: string | null;
|
|
15
|
-
/** 运维列表面的可读预览(**不是**完整 objective —— 名字即语义,见 DDL 列注)
|
|
16
|
-
|
|
15
|
+
/** 运维列表面的可读预览(**不是**完整 objective —— 名字即语义,见 DDL 列注)。一个事实位,与 run 行同形:`""` = 建过、剥完没有用户正文;
|
|
16
|
+
* `null` = 没记录(列 NULL:更早版本 / 手改留下的行;本版写点只写 `""` 或正文)。 */
|
|
17
|
+
objectivePreview: string | null;
|
|
17
18
|
result?: unknown;
|
|
18
19
|
error?: string;
|
|
19
20
|
startedAtMs: number;
|
|
@@ -4,6 +4,7 @@ import { isDupKeyError } from "./sql-errors.js";
|
|
|
4
4
|
import { mysqlDriver, pgDriver, dialectJsonEncoder } from "./sql-driver.js";
|
|
5
5
|
import { decodeNullableJsonColumn, foldJsonColumn, jsonColumnText, readNonNullJsonValueColumn } from "./sql-json-column.js";
|
|
6
6
|
import { ensureIndexes } from "./ensure-index.js";
|
|
7
|
+
import { buildObjectivePreview } from "../user-authored-text.js";
|
|
7
8
|
export const LEADER_RUN_TABLE = "leader_run";
|
|
8
9
|
const LEADER_RUN_STATUSES = new Set(["running", "completed", "failed", "needs_human"]);
|
|
9
10
|
export const LEADER_OBJECTIVE_PREVIEW_CHARS = 160;
|
|
@@ -86,7 +87,7 @@ function mapRow(r) {
|
|
|
86
87
|
id,
|
|
87
88
|
status: statusOf(r.status, id),
|
|
88
89
|
owner: r.owner == null ? null : String(r.owner),
|
|
89
|
-
objectivePreview: r.objective_preview == null ?
|
|
90
|
+
objectivePreview: r.objective_preview == null ? null : String(r.objective_preview),
|
|
90
91
|
...(result === undefined ? {} : { result }),
|
|
91
92
|
...(error === undefined ? {} : { error }),
|
|
92
93
|
startedAtMs: Number(r.started_at_ms),
|
|
@@ -104,7 +105,7 @@ export class SqlLeaderRunStore {
|
|
|
104
105
|
async createRun(input) {
|
|
105
106
|
const id = uuidv7();
|
|
106
107
|
const now = Date.now();
|
|
107
|
-
const preview = input.objective
|
|
108
|
+
const preview = buildObjectivePreview(input.objective, LEADER_OBJECTIVE_PREVIEW_CHARS);
|
|
108
109
|
const params = [id, input.idemKey, input.owner, preview, "running", now];
|
|
109
110
|
try {
|
|
110
111
|
await this.db.query(this.q(`INSERT INTO ${LEADER_RUN_TABLE} (leader_run_id, idem_key, owner, objective_preview, status, started_at_ms) VALUES (?,?,?,?,?,?)`, `INSERT INTO ${LEADER_RUN_TABLE} (leader_run_id, idem_key, owner, objective_preview, status, started_at_ms) VALUES ($1,$2,$3,$4,$5,$6)`), params);
|