@sema-agent/server 7.148.0 → 7.149.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 +429 -0
- package/README.md +16 -1
- package/README.zh-CN.md +4 -0
- package/USAGE.md +89 -55
- package/dist/adoption/wire.d.ts +3 -3
- package/dist/approval-card.d.ts +32 -32
- package/dist/approval-leg-origin.d.ts +33 -0
- package/dist/approval-leg-origin.js +4 -0
- package/dist/auth-bridge.d.ts +9 -1
- package/dist/auth-bridge.js +4 -4
- package/dist/auth-keys.d.ts +10 -1
- package/dist/auth-keys.js +8 -0
- package/dist/boot/execution-env.js +10 -11
- package/dist/boot/execution-lane.d.ts +6 -4
- package/dist/boot/execution-lane.js +3 -1
- package/dist/boot/org-delivery.d.ts +3 -2
- package/dist/boot/resolve-spec.js +6 -4
- package/dist/boot/runner-deps.js +3 -1
- package/dist/boot/stage-01-config.d.ts +1 -0
- package/dist/boot/stage-01-config.js +4 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
- package/dist/boot/stage-02-web-admin-pull.js +10 -2
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -0
- package/dist/boot/stage-06-runners.d.ts +2 -1
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-10-http-server.d.ts +2 -1
- package/dist/boot/stores.d.ts +3 -0
- package/dist/boot/stores.js +22 -19
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +5 -4
- package/dist/capability-facts.js +3 -14
- package/dist/card-settle-stored-scope.d.ts +56 -0
- package/dist/card-settle-stored-scope.js +27 -0
- package/dist/card-void.d.ts +7 -12
- package/dist/card-void.js +2 -7
- package/dist/config-catalog.d.ts +12 -0
- package/dist/config-catalog.js +36 -32
- package/dist/config-invariants.d.ts +5 -4
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +37 -5
- package/dist/config.d.ts +6 -5
- package/dist/config.js +35 -24
- package/dist/context-window-notice.d.ts +31 -0
- package/dist/context-window-notice.js +28 -0
- package/dist/deployment-shape.d.ts +20 -11
- package/dist/deployment-shape.js +1 -0
- package/dist/env-name-allowlist-knobs.d.ts +6 -5
- package/dist/env-name-allowlist-knobs.js +5 -0
- package/dist/execution-lane-caps.d.ts +20 -5
- package/dist/execution-lane-caps.js +18 -4
- package/dist/hooks/command-spawn.d.ts +7 -2
- package/dist/hooks/command-spawn.js +13 -6
- package/dist/hooks/hook-runner.d.ts +5 -0
- package/dist/hooks/hook-runner.js +11 -7
- package/dist/http/admission.js +3 -3
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/claim-heartbeat.d.ts +3 -3
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/claimed-run.d.ts +16 -9
- package/dist/http/claimed-run.js +8 -0
- package/dist/http/dispatch.js +5 -3
- package/dist/http/durable-run-leg.d.ts +8 -1
- package/dist/http/durable-run-leg.js +30 -11
- package/dist/http/execution-context.d.ts +115 -14
- package/dist/http/execution-context.js +130 -40
- package/dist/http/owner-access.d.ts +3 -2
- package/dist/http/owner-access.js +2 -3
- package/dist/http/principal-gate.d.ts +18 -11
- package/dist/http/principal-gate.js +3 -1
- package/dist/http/resume-ctx-read.d.ts +14 -3
- package/dist/http/resume-ctx-read.js +8 -2
- package/dist/http/resume-legs.d.ts +35 -3
- package/dist/http/resume-legs.js +244 -92
- package/dist/http/route-ctx.d.ts +6 -0
- package/dist/http/routes/a2a-serve.js +2 -0
- package/dist/http/routes/approvals-assistant.js +3 -2
- package/dist/http/routes/capabilities.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -1
- package/dist/http/routes/diagnostics.js +30 -5
- package/dist/http/routes/principal-inbox.d.ts +3 -1
- package/dist/http/routes/principal-inbox.js +3 -2
- package/dist/http/routes/runs.js +10 -7
- package/dist/http/routes/session-sync.d.ts +24 -5
- package/dist/http/routes/session-sync.js +46 -34
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/tasks.js +127 -93
- package/dist/http/server.d.ts +4 -5
- package/dist/http/server.js +30 -5
- package/dist/http/submit-ctx.d.ts +1 -0
- package/dist/http/submit-ctx.js +2 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/leg-facts.d.ts +7 -2
- package/dist/leg-facts.js +1 -0
- package/dist/local-store-declaration.d.ts +54 -0
- package/dist/local-store-declaration.js +59 -0
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/mcp-assertion-header.js +1 -1
- package/dist/memory-project-layer.js +1 -1
- package/dist/memory-scope.d.ts +4 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-sync-client.js +2 -2
- package/dist/model-context-window.d.ts +50 -11
- package/dist/model-context-window.js +20 -1
- package/dist/model-entry-refusal.d.ts +5 -4
- package/dist/model-entry-refusal.js +17 -3
- package/dist/model-reach-scope.d.ts +2 -1
- package/dist/observability/fail-open.d.ts +14 -2
- package/dist/observability/fail-open.js +14 -2
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +1 -1
- package/dist/observability/secret-env-scrub.js +1 -1
- package/dist/org-delivery-gate.d.ts +31 -6
- package/dist/org-delivery-gate.js +7 -4
- package/dist/owner-faces.d.ts +3 -2
- package/dist/park-row-commit.d.ts +67 -0
- package/dist/park-row-commit.js +76 -0
- package/dist/parked-decide.d.ts +9 -7
- package/dist/parked-decide.js +25 -6
- package/dist/peer-directory.d.ts +1 -1
- package/dist/plugins/adoption-log-sql.d.ts +3 -3
- package/dist/plugins/adoption-log-sql.js +19 -19
- package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-sql.js +3 -5
- package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
- package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
- package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
- package/dist/plugins/approval-exemption-skill-m46.js +6 -10
- package/dist/plugins/approval-exemption-store.d.ts +26 -1
- package/dist/plugins/approval-exemption-store.js +28 -19
- package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
- package/dist/plugins/ensure-schema-lock-policy.js +75 -9
- package/dist/plugins/file-run-store.d.ts +22 -9
- package/dist/plugins/file-run-store.js +50 -22
- package/dist/plugins/local-checkpoint-store.d.ts +4 -0
- package/dist/plugins/local-checkpoint-store.js +2 -1
- package/dist/plugins/local-data-root-admission.d.ts +52 -0
- package/dist/plugins/local-data-root-admission.js +100 -0
- package/dist/plugins/local-engine-high-water.d.ts +28 -7
- package/dist/plugins/local-engine-high-water.js +27 -22
- package/dist/plugins/local-session-store.d.ts +134 -49
- package/dist/plugins/local-session-store.js +149 -108
- package/dist/plugins/memory-run-store.d.ts +14 -9
- package/dist/plugins/memory-run-store.js +47 -21
- package/dist/plugins/one-time-migration-marker.d.ts +19 -3
- package/dist/plugins/one-time-migration-marker.js +7 -1
- package/dist/plugins/one-time-migrations.d.ts +46 -20
- package/dist/plugins/one-time-migrations.js +102 -79
- package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
- package/dist/plugins/org-delivery-quota-store.js +29 -14
- package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
- package/dist/plugins/permission-rule-store-sql.js +5 -9
- package/dist/plugins/pg-pool.d.ts +1 -1
- package/dist/plugins/pg-pool.js +10 -12
- package/dist/plugins/remote-env-device.d.ts +3 -2
- package/dist/plugins/remote-env-e2b.d.ts +1 -7
- package/dist/plugins/remote-env-e2b.js +10 -7
- package/dist/plugins/remote-env-host.d.ts +50 -9
- package/dist/plugins/remote-env-host.js +77 -20
- package/dist/plugins/remote-env-k8s.js +4 -2
- package/dist/plugins/remote-env-local-docker.d.ts +6 -3
- package/dist/plugins/remote-env-local-docker.js +8 -23
- package/dist/plugins/run-store-sql.d.ts +26 -7
- package/dist/plugins/run-store-sql.js +44 -16
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +3 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +4 -3
- package/dist/plugins/schema-consistency.d.ts +89 -5
- package/dist/plugins/schema-consistency.js +176 -7
- package/dist/plugins/schema-drift-sentence.d.ts +6 -5
- package/dist/plugins/schema-drift-sentence.js +13 -5
- package/dist/plugins/session-placement.d.ts +5 -4
- package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
- package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +16 -0
- package/dist/plugins/stop-then-start-sentence.js +7 -0
- package/dist/plugins/store-backend.d.ts +22 -8
- package/dist/plugins/store-backend.js +58 -24
- package/dist/plugins/store-contracts.d.ts +33 -3
- package/dist/plugins/store-contracts.js +16 -0
- package/dist/plugins/tidb-pool.d.ts +11 -6
- package/dist/plugins/tidb-pool.js +18 -12
- package/dist/plugins/workspace-custody.d.ts +44 -0
- package/dist/plugins/workspace-custody.js +47 -0
- package/dist/project-identity.d.ts +8 -7
- package/dist/project-identity.js +40 -17
- package/dist/project-layer-key.d.ts +13 -2
- package/dist/project-layer-key.js +9 -1
- package/dist/read-deny-floor-notice.d.ts +36 -0
- package/dist/read-deny-floor-notice.js +40 -0
- package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
- package/dist/request-declaration-disposition.js +39 -0
- package/dist/run-cancel-card.d.ts +28 -0
- package/dist/run-cancel-card.js +19 -0
- package/dist/run-cancel-context.d.ts +10 -0
- package/dist/run-cancel-context.js +1 -0
- package/dist/run-local.js +28 -13
- package/dist/runs.d.ts +31 -7
- package/dist/runs.js +34 -16
- package/dist/security.d.ts +2 -2
- package/dist/server-secret-env.d.ts +34 -20
- package/dist/server-secret-env.js +61 -18
- package/dist/session-agent.d.ts +3 -2
- package/dist/session-children-retire.d.ts +6 -3
- package/dist/session-children-retire.js +2 -5
- package/dist/session-workspace.d.ts +3 -3
- package/dist/store-admission.d.ts +33 -0
- package/dist/store-admission.js +49 -0
- package/dist/store-posture.d.ts +5 -0
- package/dist/store-posture.js +18 -1
- package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
- package/dist/stores-sql/checkpoint-store-sql.js +3 -5
- package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
- package/dist/stores-sql/file-history-store-sql.js +3 -5
- package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
- package/dist/stores-sql/tool-result-store-sql.js +4 -6
- package/dist/task-a2a.d.ts +3 -8
- package/dist/task-a2a.js +25 -27
- package/dist/task-cwd.d.ts +23 -7
- package/dist/task-cwd.js +3 -0
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +1 -1
- package/dist/task-settings.js +1 -0
- package/dist/terminal.d.ts +2 -0
- package/dist/terminal.js +21 -6
- package/dist/tool-approval.d.ts +44 -36
- package/dist/tool-approval.js +66 -47
- package/dist/trace/engine-notice-wire.d.ts +24 -21
- package/dist/trace/engine-notice-wire.js +7 -3
- package/dist/trace/ledger-sink.d.ts +3 -1
- package/dist/trace/project.d.ts +4 -2
- package/dist/trace/project.js +8 -7
- package/dist/trace/redact.d.ts +12 -0
- package/dist/trace/redact.js +5 -1
- package/dist/trace/self-minted-wire.d.ts +131 -52
- package/dist/trace/self-minted-wire.js +71 -39
- package/dist/web-admin-client/apply-effective.js +22 -9
- package/docs/error-text-lexicon.json +317 -0
- package/package.json +3 -1
- package/scripts/embed-minimal.mjs +183 -0
- package/wire-changes/server@7.149.0.json +372 -0
- package/dist/plain-string-record.js +0 -70
package/dist/tool-approval.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ApprovalLegOrigin } from "./approval-leg-origin.js";
|
|
2
2
|
import { type ApprovalDecider, type HostSettledBy, type HostSource, type RetiredDecisionKeyFacts } from "./host-decision.js";
|
|
3
3
|
import type { IncomingMessage } from "node:http";
|
|
4
4
|
import { type AskClass, type AskRequest, type AskOutcome, type PermissionResult, type CheckpointGate, type PendingAction, type PersistedRuleMandate, type ReadRootGrantCandidate, type RuleOffer, type AutoModeFallbackCause, type BoundGrantAbsence, type BoundSkillGrants, type ToolApprovalCard, type ReopenReason } from "@sema-agent/core";
|
|
@@ -26,6 +26,8 @@ interface OpenAskAdoption {
|
|
|
26
26
|
/** 待决行多于 {@link ADOPT_OPEN_ASKS_MAX}:只接管了最先的那么多只。 */
|
|
27
27
|
readonly capped: boolean;
|
|
28
28
|
}
|
|
29
|
+
/** Bound on the remembered allow-all grants (insertion-order evict — a long-lived worker must not grow unbounded). */
|
|
30
|
+
export declare const MAX_ALLOW_SESSIONS = 4096;
|
|
29
31
|
/**
|
|
30
32
|
* 耐久回决口 `POST /v1/approvals/:sessionId/decide` 的路径串 —— [ref]:迟到回决口 PARKING 臂 202 体的机读指路 `decidePath`。
|
|
31
33
|
* 路由表那一行(`http/routes/approvals-assistant.ts` 的 `approval-decide`)按 pattern 匹配它;两者同形由往返钉守
|
|
@@ -471,7 +473,7 @@ export interface ToolApprovalFrame {
|
|
|
471
473
|
* (`finishRespond`)读的是同一份事实 ⇒ 帧说不可记 ⇔ 点了 `allow_session` 回执 `rememberApplied:false`。壳读这一位决定渲不渲
|
|
472
474
|
* 「本会话放行」,不再从 `requiresRealApproval` / `mandated` / `governanceForced` 三位自己推断(那一推断漏掉第四个理由:core 7.41.0
|
|
473
475
|
* 的 `Skill` 卡批准即授予清单,三位全无)。`card_json` 卡面、`livePending` 行、运维队列行同名同义。
|
|
474
|
-
* 🔴 **真才带,缺席绝不编 `false`**:缺席 = 可记(有会话时)
|
|
476
|
+
* 🔴 **真才带,缺席绝不编 `false`**:缺席 = 可记(有会话时)或老服务端。没有会话的腿上、或读不出会话住客的腿上点了照样只放行一次(回执说明),本位不管那两形。
|
|
475
477
|
*/
|
|
476
478
|
rememberRefused?: true;
|
|
477
479
|
/**
|
|
@@ -890,12 +892,10 @@ export type ApprovalLegFamily = {
|
|
|
890
892
|
readonly transport: HitlTransport<ToolApprovalFrame>;
|
|
891
893
|
};
|
|
892
894
|
/** 两族共有的腿身份与腿轴。 */
|
|
893
|
-
interface ToolApprovalRunContextBase {
|
|
895
|
+
interface ToolApprovalRunContextBase extends ApprovalLegOrigin {
|
|
894
896
|
taskId: string;
|
|
895
897
|
sessionId?: string;
|
|
896
898
|
owner: string | null;
|
|
897
|
-
/** 这条腿的执行车道 —— 装配点写所在边界执行上下文的 `ctx.lane`(`http/execution-context.ts`)。出处带车道:这只席造的问在铸行时记下它。 */
|
|
898
|
-
executionLane: ExecutionLane;
|
|
899
899
|
abortSignal?: AbortSignal;
|
|
900
900
|
/** [ref]([ref] §3.1 askId 派生的腿轴;车3 刀 3a 换轴:原 `leg?: number` → `legKey?: string`)。
|
|
901
901
|
* = `sha256(resume checkpoint token)` 的 hex,**首腿缺席折空串**(空串是首腿的真值,不是「未知」)。
|
|
@@ -1342,7 +1342,7 @@ export declare class ToolApprovalCoordinator {
|
|
|
1342
1342
|
private readonly pendingByAskId;
|
|
1343
1343
|
/** preamble 呈出的卡的消卡订阅(键 = askId;见 {@link watchPresentedCards})。只订本副本上此刻在等的 ask,落定即清 ⇒ 有界于活登记数。 */
|
|
1344
1344
|
private readonly presentedCardWatchers;
|
|
1345
|
-
/** Per-capability session grants — keys = sessionAllowKey(owner, sessionId, category, grant binding) (修2; bounded). */
|
|
1345
|
+
/** Per-capability session grants — keys = sessionAllowKey(owner, sessionId, session incarnation, category, grant binding) (修2; bounded). */
|
|
1346
1346
|
private readonly allowAllSessions;
|
|
1347
1347
|
/** [ref] HIGH-1(broker)→[ref]四 core 产品裁定「多活集合+广播+首决胜出」:per-(owner, host-session)
|
|
1348
1348
|
* 的**当前活跃连接集合**——boundAsk 闭包只携身份,emit 时广播给该 key 下**全部**活连接(宿主重连/
|
|
@@ -1777,8 +1777,7 @@ export declare class ToolApprovalCoordinator {
|
|
|
1777
1777
|
owner: string | null;
|
|
1778
1778
|
taskId: string;
|
|
1779
1779
|
sessionId?: string;
|
|
1780
|
-
|
|
1781
|
-
}, why: LegUnattended) => ((req: AskRequest) => Promise<AskOutcome>);
|
|
1780
|
+
} & ApprovalLegOrigin, why: LegUnattended) => ((req: AskRequest) => Promise<AskOutcome>);
|
|
1782
1781
|
/**
|
|
1783
1782
|
* 🔴 session grant 短路前的**持久出处复核**([ref] 的 codex R1-[high] 补丁;[ref] 换判据;[ref] / SN-C1 换读口)。
|
|
1784
1783
|
*
|
|
@@ -1966,7 +1965,7 @@ export declare class ToolApprovalCoordinator {
|
|
|
1966
1965
|
* emit 时经 broker 取该 (owner, session) 的「当前」活跃流(宿主重连/续聊的新 SSE 自动接卡;
|
|
1967
1966
|
* internalsSnapshot 冻结的闭包因此永不携死流)。查无活流 = "unavailable"(G1 回路:durable 部署
|
|
1968
1967
|
* park;inherited plain-ask 的 park 回路 = core [ref]①,落地前该臂 = deny,与 1.257 前行为一致)。 */
|
|
1969
|
-
boundAsk: (identity: {
|
|
1968
|
+
boundAsk: (identity: ApprovalLegOrigin & {
|
|
1970
1969
|
owner: string | null;
|
|
1971
1970
|
taskId: string;
|
|
1972
1971
|
sessionId?: string;
|
|
@@ -1974,8 +1973,6 @@ export declare class ToolApprovalCoordinator {
|
|
|
1974
1973
|
/** [ref] 车3 刀 3b(§7.3):本腿的 walltime deadline —— 与 `legKey` 同源同理由,随**出处**走
|
|
1975
1974
|
* (子代经继承链拿到的是宿主腿的闭包,窗必须按宿主腿的剩余 walltime 算)。 */
|
|
1976
1975
|
legDeadlineMonotonic?: number;
|
|
1977
|
-
/** 宿主腿的执行车道(装配点写执行上下文的 `ctx.lane`);子代经继承链冻同一闭包 ⇒ 子代的问记宿主腿的车道。 */
|
|
1978
|
-
executionLane: ExecutionLane;
|
|
1979
1976
|
}) => ((req: AskRequest, signal?: AbortSignal) => Promise<AskOutcome>);
|
|
1980
1977
|
/** 广播版裁决路径——`ask()`(ALS,恒单元素数组)与 `boundAsk`([ref]四多活集合,可能多元素)共用。
|
|
1981
1978
|
* 全体 `ctxs` 保证同一 (owner, sessionId)(streamKey 分组不变式;单元素数组平凡成立)。
|
|
@@ -2068,10 +2065,10 @@ export declare class ToolApprovalCoordinator {
|
|
|
2068
2065
|
/**
|
|
2069
2066
|
* `GET /v1/tool-approvals/:approvalId` —— **按问读口**:一只 ask 此刻在哪一态({@link TOOL_APPROVAL_READ_STATES})。与 {@link respond} 同根同门
|
|
2070
2067
|
* (HTTP 层的鉴权 / 属主身份同一只 `gatedSubject`;看不见这只问 —— 属主不过 / 查无 / 行读不出 / 没有问账 —— 与应答口同答 404 `not_found.ask`({@link askNotVisible}),
|
|
2071
|
-
* 无存在性 / 状态谕示)
|
|
2072
|
-
*
|
|
2073
|
-
*
|
|
2074
|
-
* 与晚答口同答 404 `tool_approval.not_pending` + `unknown_or_other_replica`(那里才有兑现它的闭包;属主看得见的态)
|
|
2068
|
+
* 无存在性 / 状态谕示)。看不看得见只有一个来源:有行的问 = 店答出的行上当下的属主(按 id 读行,{@link askRowFor} + {@link askRowVisibleTo});
|
|
2069
|
+
* 店答不出 ⇒ 看不见,本副本登记上记下的那一位(行上属主的读缓存)不替店作答。没有行的问(问账没上场 / 旧族腿)= 登记记下的那一位(唯一可读的属主事实)。
|
|
2070
|
+
* 读到的行仍 `STREAM_PENDING`:本副本有在等它的登记 ⇒ `pending`(行投影 = 列表面 `livePending[]` 的同一只投影);没有 ⇒ 它活在别的副本上,
|
|
2071
|
+
* 与晚答口同答 404 `tool_approval.not_pending` + `unknown_or_other_replica`(那里才有兑现它的闭包;属主看得见的态);其余行态 → 读态与晚答口的分派同一张表。
|
|
2075
2072
|
* 纯读:零写、零结算、不碰本地登记(晚答口的 DECIDED 臂会顺手同步本副本的活登记,读口不做)。
|
|
2076
2073
|
*/
|
|
2077
2074
|
readApproval(id: string, principal: string | undefined): {
|
|
@@ -2082,10 +2079,9 @@ export declare class ToolApprovalCoordinator {
|
|
|
2082
2079
|
body: unknown;
|
|
2083
2080
|
}>;
|
|
2084
2081
|
/**
|
|
2085
|
-
*
|
|
2086
|
-
*
|
|
2087
|
-
* (
|
|
2088
|
-
* 属主跟着行走,登记上那一格不是权威 —— 应答口对它恒读行判、读不出 ⇒ 404,读口同样 404(两口同答;7.135.x 两口都 404)。读得出的「没有这一行」不回落(那是行的真相)。
|
|
2082
|
+
* 有行的登记的按问读口 —— 行可见且仍 `STREAM_PENDING` ⇒ `pending`(列表面同一只行投影);否则按行的态答(与读行半场同一张表)。
|
|
2083
|
+
* 行读不出(店抛 / 超时)与查无同答 404 —— 活登记与接管登记一样:登记上那一格只是行上属主的读缓存,店答不出时它不替店说「你看得见」
|
|
2084
|
+
* (应答口同律:属主门那一读读不出 ⇒ 同一句 404;决议写失败之后读不回行 ⇒ 500,那是「不知道落没落」,不是看得见)。
|
|
2089
2085
|
*/
|
|
2090
2086
|
private readByRow;
|
|
2091
2087
|
/** {@link readApproval} 的读行半场。 */
|
|
@@ -2136,12 +2132,15 @@ export declare class ToolApprovalCoordinator {
|
|
|
2136
2132
|
/** {@link respondLate} 的读行:按 id 读出行,交 {@link dispatchRowTruth}。 */
|
|
2137
2133
|
private dispatchLateByRow;
|
|
2138
2134
|
/**
|
|
2139
|
-
* 按 wire 身份(= 行的键)
|
|
2140
|
-
*
|
|
2141
|
-
* 不知道 ⇒ 回那句 404,绝不把未知说成受理;D5 的 fail-open 只覆盖「不挡人的真实回决」那一面,这条腿方向相反),按问读口对本协调器自己铸的活登记回落那一份登记
|
|
2142
|
-
* (接管登记不回落,{@link readByRow})。
|
|
2135
|
+
* 按 wire 身份(= 行的键)读行,给属主门用(应答口 / 晚答口 / 按问读口):读到了 ⇒ 那一行;读得出的「没有这一行」与读不出(店抛或超时,记账)同答 `null`。
|
|
2136
|
+
* 读不出 = **不知道**属主是谁、这只 ask 落在哪一态 ⇒ 调用方看不见它(与查无同答 404):属主门 fail-closed,受理臂不把未知说成受理,读口不把未知说成待决。
|
|
2143
2137
|
*/
|
|
2144
2138
|
private askRowFor;
|
|
2139
|
+
/**
|
|
2140
|
+
* 一只有行的问**此刻的行** —— 应答口 / 按问读口 / 列表面读行的**唯一**入口:{@link askRowFor} 点读(读不出 ⇒ `null` ⇒ 看不见),读到仍待决的行就把这只问在本副本上的登记
|
|
2141
|
+
* 对齐到行上当下的属主([ref];先于各口的门判:门判的是调用方,不是这次对齐)。读序号在**发起读之前**取({@link nextRowReadSeq}):晚回来的旧读盖不掉之后发起的读。
|
|
2142
|
+
*/
|
|
2143
|
+
private askRowFollowingOwner;
|
|
2145
2144
|
/**
|
|
2146
2145
|
* 一条行(的此刻真相)→ 应答口的答案:属主门 + 受理回执 + 六态穷举分派(闭集:新增 `AskState` 而不在此表态 = **编译错**)。两个入口:本副本没有在等
|
|
2147
2146
|
* 这只 ask 的登记({@link dispatchLateByRow} 读出行),以及有登记但回决的 CAS 干净地输(行已有终局,`decideAsk` 带回的那条行)—— 一只 ask 的
|
|
@@ -2229,20 +2228,10 @@ export declare class ToolApprovalCoordinator {
|
|
|
2229
2228
|
/** 回决收尾(D1 现行为逐字不变的那一半)——session allow-all 记账 + settle + 200 响应体。原 `respond()`
|
|
2230
2229
|
* 方法体的逐字搬运([ref] 车2 拆分,行为零改动)。 */
|
|
2231
2230
|
private finishRespond;
|
|
2232
|
-
/** [ref]([ref] 案):live pending 的**列表读面**——`GET /v1/approvals` 响应第二顶层键 `livePending`
|
|
2233
|
-
* 的唯一数据源,**同时**是 `/v1/approvals/stream` 的 live 半场 diff 源(推与拉必须同源:feed 收到
|
|
2234
|
-
* `live_pending` 事件就会去 `list()`,两处各读各的会给出一条列不出来的事件)。纯读投影,零锁/零结算
|
|
2235
|
-
* 语义。
|
|
2236
|
-
* 🔴 **[ref] 起行上带整只活卡帧**(`frame`,见 {@link LivePendingRow.frame}):旧文那句「input/args
|
|
2237
|
-
* 不上列表,详情走流帧」对**悬挂 ask 结构上不成立**(它永远没有流帧),而 `frame` 是 `askBroadcast`
|
|
2238
|
-
* 那一处构造的同一个对象 ⇒ 仍然只有**一个**脱敏属主、零第二投影。`scope` 与 durable 面同一个值(checkpoint scope):`undefined` = operator 全量(含 owner null 的
|
|
2239
|
-
* 条目),`_`(`CHECKPOINT_PUBLIC_SCOPE`)= 匿名那一组 = owner null 的条目(R7:不带主体的调用方列得出它答得了的那几张),
|
|
2240
|
-
* 其余串 = 只见 `owner === scope` 的条目(null-owner 行对具名主体不列,宁少列不超范围)。行的 `approvalId` 就是 `respond()` 收的 id
|
|
2241
|
-
* (同源可达,[ref] 判据);`expiresAtMs` 照抄登记时单点铸定的窗死线([ref] 三键同一个数)。 */
|
|
2242
2231
|
/**
|
|
2243
2232
|
* 🔴 [ref] —— **起服接管**:把问账里仍 `STREAM_PENDING` 的问接进本审批机的活集合,让 `livePending[]`(及 `/v1/approvals/stream` 的 live 半场、
|
|
2244
|
-
* 按问读口、应答口)
|
|
2245
|
-
* 同一只 {@link livePendingRowOf} 投影,卡帧 = `buildReplayFrame`(开流 preamble 同一只构造)—— 不是 GET
|
|
2233
|
+
* 按问读口、应答口)在重启之后不重开流也看得见、答得了它们。审批机仍是这些读面**唯一**的候选源(哪些问在本副本上有登记):扫问账找待决行的只有这里(起服一次),之后列表行由
|
|
2234
|
+
* 同一只 {@link livePendingRowOf} 投影,卡帧 = `buildReplayFrame`(开流 preamble 同一只构造)—— 不是 GET 上按属主扫表的第二 reader;列表面对候选逐只点读行(见 {@link listLivePending}),候选集之外的问它不认识。
|
|
2246
2235
|
*
|
|
2247
2236
|
* 律(设计稿 `design-[ref].md` §2):接管登记**没有引擎腿在等它**(铸它的进程没了,或它活在别的副本上),与活登记同一只状态机 ——
|
|
2248
2237
|
* 应答 = 同一把 `decideAsk` CAS({@link answerRegistration}),收敛 = 同一条悬挂轮询腿读行({@link pollSuspendedDecisions});它活多久只由行说了算,
|
|
@@ -2290,7 +2279,26 @@ export declare class ToolApprovalCoordinator {
|
|
|
2290
2279
|
}>;
|
|
2291
2280
|
/** 这只 askId 在本副本上有几条**有引擎腿在等**的登记(接管登记不算)—— 轮询腿的「被唤醒数」读它。 */
|
|
2292
2281
|
private waitingRegistrationCount;
|
|
2293
|
-
|
|
2282
|
+
/**
|
|
2283
|
+
* [ref]([ref] 案):live pending 的**列表读面** —— `GET /v1/approvals` 响应第二顶层键 `livePending` 的唯一数据源,**同时**是 `/v1/approvals/stream` 的 live 半场 diff 源
|
|
2284
|
+
* (推与拉必须同源:feed 收到 `live_pending` 事件就会去 `list()`,两处各读各的会给出一条列不出来的事件)。纯读投影,零锁 / 零结算语义。
|
|
2285
|
+
* 🔴 **[ref] 起行上带整只活卡帧**(`frame`,见 {@link LivePendingRow.frame}):旧文那句「input/args 不上列表,详情走流帧」对**悬挂 ask 结构上不成立**(它永远没有流帧),
|
|
2286
|
+
* 而 `frame` 是 `askBroadcast` 那一处构造的同一个对象 ⇒ 仍然只有**一个**脱敏属主、零第二投影。
|
|
2287
|
+
* `scope` 与 durable 面同一个值(checkpoint scope):`undefined` = operator 全量(含 owner null 的条目),`_`(`CHECKPOINT_PUBLIC_SCOPE`)= 匿名那一组 = owner null 的条目
|
|
2288
|
+
* (R7:不带主体的调用方列得出它答得了的那几张),其余串 = 只见 `owner === scope` 的条目(null-owner 行对具名主体不列,宁少列不超范围)。
|
|
2289
|
+
* 行的 `approvalId` 就是 `respond()` 收的 id(同源可达,[ref] 判据);`expiresAtMs` 照抄登记时单点铸定的窗死线([ref] 三键同一个数)。
|
|
2290
|
+
*
|
|
2291
|
+
* 🔴 **有行的问,列表只列按问读口会答 `pending` 的**(看不看得见只有一个来源,{@link readApproval} 同一条律):本副本此刻的登记只是**候选**(哪些问在本副本上有登记);
|
|
2292
|
+
* 有行的问,列不列它、列给谁只由店答出的行说了算 —— 对每只候选点读行({@link askRowFollowingOwner},与读口 / 应答口同一只 {@link askRowFor}):行读不出(店抛 / 超时)⇒ 看不见 ⇒ 不列
|
|
2293
|
+
* (与读口的 `404 not_found.ask` 同隐;店恢复后下一次列表即回),行已离开 `STREAM_PENDING`(别处答了 / 收走了,本副本的登记还没闻讯)⇒ 不列(读口答的是它此刻的态),
|
|
2294
|
+
* 行上当下的属主不在 `scope` 内 ⇒ 不列(登记上记下的那一位只是行上属主的读缓存,不替店作答)。没有行的问(问账没上场 / 旧族腿)登记记下的属主是唯一可读的属主事实 ⇒ 照登记列。
|
|
2295
|
+
* 读行并发发起、各自带 {@link DURABLE_CONVERGE_READ_TIMEOUT_MS} 的墙钟 ⇒ 一次列表至多等一个期限;行体的投影取在读完之后、对每个列出的 wire 身份重取此刻代表它的那条登记
|
|
2296
|
+
* ({@link liveEntryFor}):读行期间已结算的不列,读行期间被活登记接替的接管登记按活登记的样子列。
|
|
2297
|
+
* 读行的次数 = 本副本此刻**有行的不同 ask 数**(重复登记共用一次读,没有行的问不读),**不按 `scope` 先筛**(登记上的属主只是读缓存,不替店判谁看得见 —— scope 之外的卡也要读一次行才判得出);
|
|
2298
|
+
* 登记数的上界是每个任务 / 每个属主各一个未决帽(`STREAM_APPROVAL_ADMIT_MAX_PER_TASK` / `_PER_OWNER`)加起服接管上限 {@link ADOPT_OPEN_ASKS_MAX},本副本的总数没有全局帽。
|
|
2299
|
+
* 列表行 ⊆ 按问读口对同一调用方答 `pending` 的那些;反过来不然 —— `scope` 比读口窄:具名主体的列表不含无主的卡(宁少列),运维列表按 `?owner=` / 全量列、含读口对运维不放行的卡。
|
|
2300
|
+
*/
|
|
2301
|
+
listLivePending(scope: string | undefined): Promise<LivePendingRow[]>;
|
|
2294
2302
|
/**
|
|
2295
2303
|
* [ref]:某只委派子代此刻有没有**待决**的活卡 —— fleet 对账腿「子代活性由属主说了算」的属主②读口(另一只是
|
|
2296
2304
|
* bg registry 账)。子代卡在一张没人答的卡上时当然不出帧,只看「静默」就会把它当孤儿扫下面板(报案的真形)。
|
package/dist/tool-approval.js
CHANGED
|
@@ -37,7 +37,7 @@ const ADOPT_OPEN_ASKS_MAX = 1_000;
|
|
|
37
37
|
const EDITED_DECISION_MARK_CAP_MS = 10_000;
|
|
38
38
|
const DEFAULT_WINDOW_MARGIN_MS = 10_000;
|
|
39
39
|
const SHUTDOWN_DRAIN_POLL_MS = 50;
|
|
40
|
-
const MAX_ALLOW_SESSIONS = 4096;
|
|
40
|
+
export const MAX_ALLOW_SESSIONS = 4096;
|
|
41
41
|
const DEFAULT_ADMIT_MAX_PER_TASK = 32;
|
|
42
42
|
const DEFAULT_ADMIT_MAX_PER_OWNER = 256;
|
|
43
43
|
const DEFAULT_PARK_REDEMPTION_MAX = 2000;
|
|
@@ -115,8 +115,10 @@ const FS_WRITE_TOOLS = pathConfinableWriteToolNames();
|
|
|
115
115
|
function sessionAllowCategory(toolName) {
|
|
116
116
|
return FS_WRITE_TOOLS.has(toolName) ? "fs-write" : `tool:${toolName}`;
|
|
117
117
|
}
|
|
118
|
-
function sessionAllowKey(owner, sessionId, category, binding) {
|
|
119
|
-
|
|
118
|
+
function sessionAllowKey(owner, sessionId, incarnation, category, binding) {
|
|
119
|
+
if (!sessionId || !incarnation)
|
|
120
|
+
return undefined;
|
|
121
|
+
return JSON.stringify([owner, sessionId, incarnation, category, binding.kind === "bound" ? binding.digest : null]);
|
|
120
122
|
}
|
|
121
123
|
function askStandingAnswerFacts(req, governanceForced, deploymentListAsks) {
|
|
122
124
|
const classes = screenAskClassMembers(req.askClass, req.classes)?.classes;
|
|
@@ -227,9 +229,6 @@ function mandatedFromSeat(seat) {
|
|
|
227
229
|
return false;
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
|
-
function rowOrUnknown(read) {
|
|
231
|
-
return read.kind === "row" ? read.row : null;
|
|
232
|
-
}
|
|
233
232
|
function askRowVisibleTo(row, principal) {
|
|
234
233
|
return row !== null && askOwnerAdmitsAnswer(row.owner, principal);
|
|
235
234
|
}
|
|
@@ -960,7 +959,8 @@ export class ToolApprovalCoordinator {
|
|
|
960
959
|
const sessionId = origin.sessionId;
|
|
961
960
|
if (!sessionId)
|
|
962
961
|
return false;
|
|
963
|
-
const
|
|
962
|
+
const liveKey = sessionAllowKey(origin.owner, sessionId, origin.incarnation, sessionAllowCategory(req.toolName), facts.grantBinding);
|
|
963
|
+
const live = liveKey !== undefined && this.allowAllSessions.has(liveKey);
|
|
964
964
|
const durable = !live && facts.grantBinding.kind === "none" && (await this.durableGrantHas(sessionId, req.toolName));
|
|
965
965
|
if (!live && !durable)
|
|
966
966
|
return false;
|
|
@@ -984,7 +984,14 @@ export class ToolApprovalCoordinator {
|
|
|
984
984
|
}
|
|
985
985
|
boundUnattendedAsk = (identity, why) => {
|
|
986
986
|
return async (req) => {
|
|
987
|
-
const origin = {
|
|
987
|
+
const origin = {
|
|
988
|
+
owner: identity.owner,
|
|
989
|
+
taskId: identity.taskId,
|
|
990
|
+
...(identity.sessionId !== undefined ? { sessionId: identity.sessionId } : {}),
|
|
991
|
+
legKey: "",
|
|
992
|
+
executionLane: identity.executionLane,
|
|
993
|
+
...(identity.incarnation !== undefined ? { incarnation: identity.incarnation } : {}),
|
|
994
|
+
};
|
|
988
995
|
if (await this.standingGrantSettles(origin, req, this.governanceForcedOf(origin, req)))
|
|
989
996
|
return true;
|
|
990
997
|
return this.unattendedAskOutcome({ ...why, taskId: identity.taskId, owner: identity.owner, toolName: req.toolName });
|
|
@@ -1230,6 +1237,7 @@ export class ToolApprovalCoordinator {
|
|
|
1230
1237
|
...(ctx.sessionId !== undefined ? { sessionId: ctx.sessionId } : {}),
|
|
1231
1238
|
legKey: ctx.legKey ?? "",
|
|
1232
1239
|
executionLane: ctx.executionLane,
|
|
1240
|
+
...(ctx.incarnation !== undefined ? { incarnation: ctx.incarnation } : {}),
|
|
1233
1241
|
...(ctx.legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic: ctx.legDeadlineMonotonic } : {}),
|
|
1234
1242
|
}, [ctx], req, signal);
|
|
1235
1243
|
};
|
|
@@ -1243,6 +1251,7 @@ export class ToolApprovalCoordinator {
|
|
|
1243
1251
|
...(identity.sessionId !== undefined ? { sessionId: identity.sessionId } : {}),
|
|
1244
1252
|
legKey: identity.legKey ?? "",
|
|
1245
1253
|
executionLane: identity.executionLane,
|
|
1254
|
+
...(identity.incarnation !== undefined ? { incarnation: identity.incarnation } : {}),
|
|
1246
1255
|
...(identity.legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic: identity.legDeadlineMonotonic } : {}),
|
|
1247
1256
|
}, live, req, signal);
|
|
1248
1257
|
};
|
|
@@ -1902,6 +1911,7 @@ export class ToolApprovalCoordinator {
|
|
|
1902
1911
|
...(reachability === "unreached" ? { suspended: true } : {}),
|
|
1903
1912
|
...(child ? { originTaskId: req.sourceSessionId } : primary ? { targetCtxs: new Set(aliveCtxs), onTargetGone } : {}),
|
|
1904
1913
|
...(origin.sessionId ? { sessionId: origin.sessionId } : {}),
|
|
1914
|
+
...(origin.incarnation !== undefined ? { incarnation: origin.incarnation } : {}),
|
|
1905
1915
|
frame,
|
|
1906
1916
|
...(cardFrame !== undefined ? { cardFrame } : {}),
|
|
1907
1917
|
approvalId: wireApprovalId,
|
|
@@ -2058,10 +2068,7 @@ export class ToolApprovalCoordinator {
|
|
|
2058
2068
|
const store = this.askStore;
|
|
2059
2069
|
if (!store)
|
|
2060
2070
|
return this.askNotVisible();
|
|
2061
|
-
const
|
|
2062
|
-
const row = rowOrUnknown(await this.askRowFor(store, id, "getAsk(respond-by-row)"));
|
|
2063
|
-
if (row?.state === "STREAM_PENDING")
|
|
2064
|
-
this.followRowOwner(row.askId, row.owner, readSeq);
|
|
2071
|
+
const row = await this.askRowFollowingOwner(store, id, "getAsk(respond-by-row)");
|
|
2065
2072
|
if (!askRowVisibleTo(row, principal))
|
|
2066
2073
|
return this.askNotVisible();
|
|
2067
2074
|
if (row.state !== "STREAM_PENDING")
|
|
@@ -2175,17 +2182,7 @@ export class ToolApprovalCoordinator {
|
|
|
2175
2182
|
const store = this.askStore;
|
|
2176
2183
|
if (!store)
|
|
2177
2184
|
return this.askNotVisible();
|
|
2178
|
-
const
|
|
2179
|
-
const read = await this.askRowFor(store, id, "getAsk(read-by-row)");
|
|
2180
|
-
if (read.kind === "unreadable") {
|
|
2181
|
-
if (entry.adopted === true || !askOwnerAdmitsAnswer(entry.owner, principal))
|
|
2182
|
-
return this.askNotVisible();
|
|
2183
|
-
const body = { state: "pending", ...livePendingRowOf(entry) };
|
|
2184
|
-
return { status: 200, body };
|
|
2185
|
-
}
|
|
2186
|
-
const row = rowOrUnknown(read);
|
|
2187
|
-
if (row?.state === "STREAM_PENDING")
|
|
2188
|
-
this.followRowOwner(row.askId, row.owner, readSeq);
|
|
2185
|
+
const row = await this.askRowFollowingOwner(store, id, "getAsk(read-by-row)");
|
|
2189
2186
|
if (askRowVisibleTo(row, principal) && row.state === "STREAM_PENDING") {
|
|
2190
2187
|
const body = { state: "pending", ...livePendingRowOf(entry) };
|
|
2191
2188
|
return { status: 200, body };
|
|
@@ -2193,7 +2190,7 @@ export class ToolApprovalCoordinator {
|
|
|
2193
2190
|
return this.readStateOfRow(row, principal);
|
|
2194
2191
|
}
|
|
2195
2192
|
async readAskRowState(store, id, principal) {
|
|
2196
|
-
return this.readStateOfRow(
|
|
2193
|
+
return this.readStateOfRow(await this.askRowFor(store, id, "getAsk(read)"), principal);
|
|
2197
2194
|
}
|
|
2198
2195
|
async readParkedGate(row) {
|
|
2199
2196
|
const gate = this.parkedGate;
|
|
@@ -2350,18 +2347,24 @@ export class ToolApprovalCoordinator {
|
|
|
2350
2347
|
return undefined;
|
|
2351
2348
|
}
|
|
2352
2349
|
async dispatchLateByRow(store, id, parsed, httpReq, principal) {
|
|
2353
|
-
return this.dispatchRowTruth(
|
|
2350
|
+
return this.dispatchRowTruth(await this.askRowFor(store, id, "getAsk(respond-late)"), id, parsed, httpReq, principal);
|
|
2354
2351
|
}
|
|
2355
2352
|
async askRowFor(store, id, label) {
|
|
2356
2353
|
try {
|
|
2357
|
-
|
|
2358
|
-
return row === null ? { kind: "absent" } : { kind: "row", row };
|
|
2354
|
+
return await this.withStoreDeadline(store.getAsk(id), label, DURABLE_CONVERGE_READ_TIMEOUT_MS);
|
|
2359
2355
|
}
|
|
2360
2356
|
catch (err) {
|
|
2361
2357
|
this.noteStoreError(err, label);
|
|
2362
|
-
return
|
|
2358
|
+
return null;
|
|
2363
2359
|
}
|
|
2364
2360
|
}
|
|
2361
|
+
async askRowFollowingOwner(store, id, label) {
|
|
2362
|
+
const readSeq = this.nextRowReadSeq();
|
|
2363
|
+
const row = await this.askRowFor(store, id, label);
|
|
2364
|
+
if (row?.state === "STREAM_PENDING")
|
|
2365
|
+
this.followRowOwner(row.askId, row.owner, readSeq);
|
|
2366
|
+
return row;
|
|
2367
|
+
}
|
|
2365
2368
|
async dispatchRowTruth(row, id, parsed, httpReq, principal) {
|
|
2366
2369
|
if (!askRowVisibleTo(row, principal))
|
|
2367
2370
|
return this.askNotVisible();
|
|
@@ -2793,15 +2796,20 @@ export class ToolApprovalCoordinator {
|
|
|
2793
2796
|
throw new Error(`unhandled standing-answer home: ${String(unhandled)}`);
|
|
2794
2797
|
}
|
|
2795
2798
|
}
|
|
2796
|
-
if (parsed.value === "allow_session")
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
if (
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2799
|
+
if (parsed.value === "allow_session") {
|
|
2800
|
+
const grantKey = grantable ? sessionAllowKey(judgedOwner, entry.sessionId, entry.incarnation, sessionAllowCategory(entry.toolName), entry.grantBinding) : undefined;
|
|
2801
|
+
rememberApplied = grantKey !== undefined;
|
|
2802
|
+
if (grantKey !== undefined) {
|
|
2803
|
+
if (this.allowAllSessions.size >= MAX_ALLOW_SESSIONS) {
|
|
2804
|
+
const oldest = this.allowAllSessions.values().next().value;
|
|
2805
|
+
if (oldest !== undefined)
|
|
2806
|
+
this.allowAllSessions.delete(oldest);
|
|
2807
|
+
}
|
|
2808
|
+
this.allowAllSessions.add(grantKey);
|
|
2809
|
+
}
|
|
2810
|
+
else if (grantable && entry.sessionId) {
|
|
2811
|
+
defaultLogger.warn("session_grant_refused_occupant_unreadable", { sessionId: entry.sessionId, toolName: entry.toolName });
|
|
2803
2812
|
}
|
|
2804
|
-
this.allowAllSessions.add(sessionAllowKey(judgedOwner, entry.sessionId, sessionAllowCategory(entry.toolName), entry.grantBinding));
|
|
2805
2813
|
}
|
|
2806
2814
|
const allowed = parsed.value !== "deny";
|
|
2807
2815
|
const settleArgs = opts?.settleOutcome !== undefined
|
|
@@ -2979,18 +2987,29 @@ export class ToolApprovalCoordinator {
|
|
|
2979
2987
|
n += 1;
|
|
2980
2988
|
return n;
|
|
2981
2989
|
}
|
|
2982
|
-
listLivePending(scope) {
|
|
2983
|
-
const rows = [];
|
|
2990
|
+
async listLivePending(scope) {
|
|
2984
2991
|
const owner = scope === undefined ? undefined : ownerOfCheckpointScope(scope);
|
|
2985
|
-
const
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2992
|
+
const inScope = (rowOwner) => owner === undefined || rowOwner === owner;
|
|
2993
|
+
const candidates = new Map();
|
|
2994
|
+
for (const e of this.pending.values())
|
|
2995
|
+
if (!candidates.has(e.approvalId))
|
|
2996
|
+
candidates.set(e.approvalId, e);
|
|
2997
|
+
const store = this.askStore;
|
|
2998
|
+
const ids = [...candidates.keys()];
|
|
2999
|
+
const listed = await Promise.all([...candidates.values()].map(async (entry) => {
|
|
3000
|
+
if (store === undefined || !this.registrationHasRow(entry))
|
|
3001
|
+
return inScope(entry.owner);
|
|
3002
|
+
const ask = await this.askRowFollowingOwner(store, entry.askId, "getAsk(list-live)");
|
|
3003
|
+
return ask?.state === "STREAM_PENDING" && inScope(ask.owner);
|
|
3004
|
+
}));
|
|
3005
|
+
const rows = [];
|
|
3006
|
+
ids.forEach((id, i) => {
|
|
3007
|
+
if (!listed[i])
|
|
3008
|
+
return;
|
|
3009
|
+
const current = this.liveEntryFor(id);
|
|
3010
|
+
if (current !== undefined)
|
|
3011
|
+
rows.push(livePendingRowOf(current));
|
|
3012
|
+
});
|
|
2994
3013
|
return rows;
|
|
2995
3014
|
}
|
|
2996
3015
|
hasLivePendingFromLeg(names) {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* 同文件 G1 e2e 的全码扇出夹具、以及契约文档附录 D.3 那张表(含**小节标题里的码数** —— 那道门本批
|
|
17
17
|
* 刚立,立完就在下一次加码时自己咬住了)。
|
|
18
18
|
*/
|
|
19
|
-
export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable", "task.interrupt_unconsumed", "approval.read_root_granted", "approval.read_root_grant_rejected", "instructions.source_changed", "session.lineage_rerooted", "server.model_unreachable", "permission.entry_mode_clamped", "classifier.unavailable", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "permission.allowed_tool_not_granted", "task.tool_turn_incomplete", "route.finish_reason_unknown", "route.stream_end_ignored", "route.credential_origin_mismatch", "mods.registration_refused", "config.session_rules_earlier_grammar", "advisor.not_attached", "inherit_env.names_withheld", "model.capability_downgraded", "context.media_removed", "mcp.authorization_required", "classifier.seat_rate_limited", "context.tool_schema_removed", "memory.harvest_refused", "memory.harvest_conflict", "config.legacy_tool_name"];
|
|
19
|
+
export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable", "task.interrupt_unconsumed", "approval.read_root_granted", "approval.read_root_grant_rejected", "instructions.source_changed", "session.lineage_rerooted", "server.model_unreachable", "permission.entry_mode_clamped", "classifier.unavailable", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "permission.allowed_tool_not_granted", "task.tool_turn_incomplete", "route.finish_reason_unknown", "route.stream_end_ignored", "route.credential_origin_mismatch", "mods.registration_refused", "config.session_rules_earlier_grammar", "advisor.not_attached", "inherit_env.names_withheld", "model.capability_downgraded", "context.media_removed", "mcp.authorization_required", "classifier.seat_rate_limited", "context.tool_schema_removed", "memory.harvest_refused", "memory.harvest_conflict", "config.legacy_tool_name", "config.read_deny_floor_unkept"];
|
|
20
20
|
export type EngineNoticeWireCode = (typeof ENGINE_NOTICE_WIRE_CODES)[number];
|
|
21
21
|
/** 白名单谓词(单点):路由与门都读这一个,不许第二处手抄码串。 */
|
|
22
22
|
export declare function isEngineNoticeWireCode(code: string): code is EngineNoticeWireCode;
|
|
@@ -121,6 +121,17 @@ export declare function engineNoticeEventData(notice: {
|
|
|
121
121
|
export type EngineNoticeWireSink = (row: EngineNoticeWireRow) => unknown;
|
|
122
122
|
/** 口的槽位(闭集):`live` = 流上的人(SSE),`durable` = 这条 run 的事件账。{@link EngineNoticeRouter.routeConfirmed} 只数 `durable` 槽的落账确认。 */
|
|
123
123
|
export type EngineNoticeSlot = "live" | "durable";
|
|
124
|
+
/**
|
|
125
|
+
* 分流器收的通告形:引擎的四键(`code` / `message` / `detail` / 顶层 `sessionId`)加本服务的一只**投递键** `taskId` ——
|
|
126
|
+
* 在场 = 这条通告说的是哪一条 run(run 资源 id),只投给登记了同一条 run 的腿;缺席 = 按会话投(引擎的通告都不带它)。投递键不上 wire(行里没有它)。
|
|
127
|
+
*/
|
|
128
|
+
export interface RoutedNotice {
|
|
129
|
+
readonly code: string;
|
|
130
|
+
readonly message: string;
|
|
131
|
+
readonly detail?: Record<string, unknown>;
|
|
132
|
+
readonly sessionId?: unknown;
|
|
133
|
+
readonly taskId?: unknown;
|
|
134
|
+
}
|
|
124
135
|
/** 一条腿的两只具名口(各自可缺席:bg 腿没有 live SSE,ephemeral sync 腿没有账本)。 */
|
|
125
136
|
export interface EngineNoticeLegSlots {
|
|
126
137
|
readonly live?: EngineNoticeWireSink;
|
|
@@ -142,6 +153,11 @@ export interface EngineNoticeLegSlots {
|
|
|
142
153
|
* 药:每次 `registerLeg` 铸一个单调 legId,`route` **只投最新代**;旧代的口留在表里(它自己的注销仍
|
|
143
154
|
* 按身份精确删,不会误删新代),但一帧都收不到。方向 = fail-closed(宁可旧腿少一帧,不可新腿的事实
|
|
144
155
|
* 写进旧腿的账)。
|
|
156
|
+
*
|
|
157
|
+
* 🔴 **反方向同一条:点名了 run 的通告不进别的 run 的账**(投递键 `taskId`,{@link RoutedNotice})。本服务按腿作用域定归属的通告
|
|
158
|
+
* (`read-deny-floor-notice.ts`:腿派出去的 run 的那一帧)带上这条腿的 run;腿的作用域可以被续延留住(后台子代在腿收场之后才准备),
|
|
159
|
+
* 那一刻同会话的最新一代可能已是下一条 run ⇒ 最新一代登记的 run 不是点名的那一条 ⇒ 不投。腿登记时带它写的那条 run(`registerEngineNoticeLeg` 的 `taskId`);
|
|
160
|
+
* 引擎的通告不带投递键,照旧按会话投。
|
|
145
161
|
*/
|
|
146
162
|
export declare class EngineNoticeRouter {
|
|
147
163
|
private readonly legs;
|
|
@@ -150,7 +166,7 @@ export declare class EngineNoticeRouter {
|
|
|
150
166
|
*
|
|
151
167
|
* 每只口各自 try 隔离在 {@link route} 里,单口抛不牵连同腿另一口。
|
|
152
168
|
*/
|
|
153
|
-
registerLeg(sessionId: string, slots: EngineNoticeLegSlots): () => void;
|
|
169
|
+
registerLeg(sessionId: string, slots: EngineNoticeLegSlots, taskId?: string): () => void;
|
|
154
170
|
/** 单口腿的便捷形(测试用):登记为 **durable** 槽 —— 这样 `route()` 与 `routeConfirmed()` 两条路都能用一只口测到(live 槽对后者结构上恒不计)。 */
|
|
155
171
|
register(sessionId: string, sink: EngineNoticeWireSink): () => void;
|
|
156
172
|
/** 诊断/门用:某会话此刻**最新代**有几只口在听(旧代不计——它们收不到帧)。 */
|
|
@@ -158,28 +174,18 @@ export declare class EngineNoticeRouter {
|
|
|
158
174
|
/** 诊断/门用:某会话此刻有几代腿在表里(>1 = 正处在换代窗内)。 */
|
|
159
175
|
legCount(sessionId: string): number;
|
|
160
176
|
/**
|
|
161
|
-
* 分流器的 wire 半场。返回**真投出去的口数**(0 = 没投:非白名单码 / 缺 sessionId / 该会话无活跃腿)。
|
|
177
|
+
* 分流器的 wire 半场。返回**真投出去的口数**(0 = 没投:非白名单码 / 缺 sessionId / 该会话无活跃腿 / 点名的 run 不是最新一代登记的那一条)。
|
|
162
178
|
*
|
|
163
179
|
* 单只口抛错**不吃掉同腿的其它口**(fleet bus 订阅者隔离同理由),并按 F 类登记留痕。
|
|
164
180
|
*/
|
|
165
|
-
route(notice:
|
|
166
|
-
code: string;
|
|
167
|
-
message: string;
|
|
168
|
-
detail?: Record<string, unknown>;
|
|
169
|
-
sessionId?: unknown;
|
|
170
|
-
}, nowMs?: number): number;
|
|
181
|
+
route(notice: RoutedNotice, nowMs?: number): number;
|
|
171
182
|
/**
|
|
172
183
|
* [ref](codex r1-F2 / r2-F1;[ref] opus 腿 L2 改按槽判):同一只扇出,但**等**每只口交回的持久化结果 —— 返回**确认落账**的口数:
|
|
173
184
|
* 只数 **`durable` 槽**里交回 thenable 且兑现 `true` 的口;兑现 `false` / 拒绝不算;`live` 槽**结构上不计**(不管它返回什么 —— 流上的人收没收到说明不了落账;
|
|
174
185
|
* 修前按「交回 thenable」反推是不是 durable 口,哪天 live 口改成 async 返回 `true` 就会被计成落账)。给「投出之后要记一笔『告知过』」的铸点用:
|
|
175
186
|
* 记账必须跟在**落账**之后,不能跟在「调用了口」之后(后台腿唯一的口是事件账 append,写失败时 `route()` 的计数照样是 1)。判据(白名单 / 归属 / 最新代 / 隔离)与 `route()` 逐字同一条。
|
|
176
187
|
*/
|
|
177
|
-
routeConfirmed(notice:
|
|
178
|
-
code: string;
|
|
179
|
-
message: string;
|
|
180
|
-
detail?: Record<string, unknown>;
|
|
181
|
-
sessionId?: unknown;
|
|
182
|
-
}, nowMs?: number): Promise<number>;
|
|
188
|
+
routeConfirmed(notice: RoutedNotice, nowMs?: number): Promise<number>;
|
|
183
189
|
/** 两只入口共用的扇出:返回每只**没抛**的口的持久化结果(promise 形一律先接住拒绝 ⇒ 绝不留未处理拒绝)。 */
|
|
184
190
|
private fanOut;
|
|
185
191
|
}
|
|
@@ -197,6 +203,8 @@ export declare const defaultEngineNoticeRouter: EngineNoticeRouter;
|
|
|
197
203
|
*/
|
|
198
204
|
export declare function registerEngineNoticeLeg(opts: {
|
|
199
205
|
sessionId: string | undefined;
|
|
206
|
+
/** 这条腿写的那条 run(run 资源 id = 本腿 `spec.taskId`;没有 run 资源 ⇒ 缺席)—— 点名了 run 的通告只投给登记了同一条 run 的腿。 */
|
|
207
|
+
taskId?: string;
|
|
200
208
|
live?: EngineNoticeWireSink;
|
|
201
209
|
durable?: EngineNoticeWireSink;
|
|
202
210
|
router?: EngineNoticeRouter;
|
|
@@ -210,11 +218,6 @@ export declare function registerEngineNoticeLeg(opts: {
|
|
|
210
218
|
* `route()` 恒返 0 —— 一条结构上永远投不出去的用户面披露,就是本仓 `task.user_steer_undrained` 陈腐明拒
|
|
211
219
|
* 那一族的病。缺席/空数组 ⇒ 一个字节不投(既有腿逐字不变)。
|
|
212
220
|
*/
|
|
213
|
-
pending?: readonly
|
|
214
|
-
code: string;
|
|
215
|
-
message: string;
|
|
216
|
-
detail?: Record<string, unknown>;
|
|
217
|
-
sessionId?: unknown;
|
|
218
|
-
}[];
|
|
221
|
+
pending?: readonly RoutedNotice[];
|
|
219
222
|
}): () => void;
|
|
220
223
|
//# sourceMappingURL=engine-notice-wire.d.ts.map
|
|
@@ -54,6 +54,7 @@ export const ENGINE_NOTICE_WIRE_CODES = [
|
|
|
54
54
|
"memory.harvest_refused",
|
|
55
55
|
"memory.harvest_conflict",
|
|
56
56
|
"config.legacy_tool_name",
|
|
57
|
+
"config.read_deny_floor_unkept",
|
|
57
58
|
];
|
|
58
59
|
const WIRE_CODES = new Set(ENGINE_NOTICE_WIRE_CODES);
|
|
59
60
|
export function isEngineNoticeWireCode(code) {
|
|
@@ -149,9 +150,9 @@ const isThenableResult = (v) => typeof v === "object" && v !== null && typeof v.
|
|
|
149
150
|
let nextLegId = 1;
|
|
150
151
|
export class EngineNoticeRouter {
|
|
151
152
|
legs = new Map();
|
|
152
|
-
registerLeg(sessionId, slots) {
|
|
153
|
+
registerLeg(sessionId, slots, taskId) {
|
|
153
154
|
const sinks = [...(slots.live ? [{ slot: "live", sink: slots.live }] : []), ...(slots.durable ? [{ slot: "durable", sink: slots.durable }] : [])];
|
|
154
|
-
const leg = { legId: nextLegId++, sinks };
|
|
155
|
+
const leg = { legId: nextLegId++, sinks, ...(taskId !== undefined && taskId.length > 0 ? { taskId } : {}) };
|
|
155
156
|
const list = this.legs.get(sessionId) ?? [];
|
|
156
157
|
list.push(leg);
|
|
157
158
|
this.legs.set(sessionId, list);
|
|
@@ -197,6 +198,9 @@ export class EngineNoticeRouter {
|
|
|
197
198
|
const leg = list && list.length > 0 ? list[list.length - 1] : undefined;
|
|
198
199
|
if (!leg || leg.sinks.length === 0)
|
|
199
200
|
return [];
|
|
201
|
+
const named = notice.taskId;
|
|
202
|
+
if (typeof named === "string" && named.length > 0 && leg.taskId !== named)
|
|
203
|
+
return [];
|
|
200
204
|
const row = engineNoticeEventData(notice, sessionId, nowMs, uuidv7());
|
|
201
205
|
const outcomes = [];
|
|
202
206
|
for (const { slot, sink } of leg.sinks) {
|
|
@@ -219,7 +223,7 @@ export function registerEngineNoticeLeg(opts) {
|
|
|
219
223
|
if (live === undefined && durable === undefined)
|
|
220
224
|
return () => undefined;
|
|
221
225
|
const router = opts.router ?? defaultEngineNoticeRouter;
|
|
222
|
-
const unregister = router.registerLeg(sessionId, { ...(live ? { live } : {}), ...(durable ? { durable } : {}) });
|
|
226
|
+
const unregister = router.registerLeg(sessionId, { ...(live ? { live } : {}), ...(durable ? { durable } : {}) }, opts.taskId);
|
|
223
227
|
for (const notice of opts.pending ?? [])
|
|
224
228
|
router.route(notice);
|
|
225
229
|
return unregister;
|
|
@@ -69,7 +69,9 @@ export interface LedgerSink {
|
|
|
69
69
|
* The redaction owner is NOT this writer: it is `redactLedgerEventData` — the one confluence every ledger row
|
|
70
70
|
* crosses at the three store twins' `appendEvent` AND again on the read face (idempotent). Redacting here too
|
|
71
71
|
* would put two writers on one semantic surface; the other park writers (`http/server.ts`'s two resume legs)
|
|
72
|
-
* would still need it, and a per-writer arm is exactly the shape that drifts.
|
|
72
|
+
* would still need it, and a per-writer arm is exactly the shape that drifts.
|
|
73
|
+
* Never rejects: the park is already committed by the engine (its card is in the checkpoint store) and only the run row's park write
|
|
74
|
+
* decides the run (`park-row-commit.ts`); an unwritable park / usage row is a loud log gap (`appendParkRow`), not a verdict. */
|
|
73
75
|
appendParked(kind: ParkLedgerEventType, result: unknown): Promise<void>;
|
|
74
76
|
/** Terminal `done` event. `result` must already be checkpoint-token-stripped (and, on the bg leg,
|
|
75
77
|
* model-usage-attached) by the caller. */
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -440,8 +440,10 @@ export interface ModelUsageSeat {
|
|
|
440
440
|
* 终局由 {@link attachModelUsage} 先结清最后一拍再落 `done`,停驻由本函数先 drain 再落停驻行。顺序属于写口、不属于调用点:
|
|
441
441
|
* 只回结果的 verify 腿没有逐 turn 落账的流(无 `turn_end` 帧),挂起前的用量只有停驻这一拍才落账;若各调用点各自记得「先结清」,
|
|
442
442
|
* 这条腿的账本尾帧就会是 `model_usage`,与不带 `verify` 的停驻(用量在 `turn_end` 就结清了)两形不同序(`GET /v1/runs/:id/events` 的尾帧)。
|
|
443
|
-
*
|
|
444
|
-
*
|
|
443
|
+
*
|
|
444
|
+
* **不抛**:这两行是一次**已提交**停驻的投影(卡在引擎交回之前已落 checkpoint 店;停驻成立与否只由 run 行的停驻写回答,`park-row-commit.ts`)。
|
|
445
|
+
* 写不下 ⇒ 响亮留痕(`server.runs.terminal-ledger-write-failed`,`arm=park-usage` / `arm=park-row`,与终局帧写不下同一只 tag:run 行是 durable truth,
|
|
446
|
+
* 读面与收割器容忍账本尾巴缺席),调用方照常往下提交行 —— 账本写不下从不改这条 run 的判词。用量行落不下 ⇒ 停驻行照落(两笔各自留痕)。
|
|
445
447
|
*/
|
|
446
448
|
export declare function appendParkRow(append: AppendFn, usage: ModelUsageSeat | undefined, word: ParkLedgerEventType, result: unknown, reopened?: string | null): Promise<void>;
|
|
447
449
|
/**
|
package/dist/trace/project.js
CHANGED
|
@@ -2,6 +2,7 @@ import { admitProviderEcho, redactErrorMessage, redactModelText } from "../obser
|
|
|
2
2
|
import { isInputAuthor, isRunOrigin, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, TEAM_ROLES, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
|
+
import { errorText } from "../observability/err-text.js";
|
|
5
6
|
import { redactSecrets, redactDeep } from "./redact.js";
|
|
6
7
|
import { seatText } from "./exit-seat.js";
|
|
7
8
|
import { sanitizeWireText } from "./engine-notice-wire.js";
|
|
@@ -328,20 +329,20 @@ export function parkEventData(result, reopened) {
|
|
|
328
329
|
};
|
|
329
330
|
}
|
|
330
331
|
export async function appendParkRow(append, usage, word, result, reopened) {
|
|
331
|
-
let drainFailed = false;
|
|
332
|
-
let drainFailure;
|
|
333
332
|
if (usage !== undefined) {
|
|
334
333
|
try {
|
|
335
334
|
await appendModelUsageDelta(append, usage.modelUsage, usage.taskId);
|
|
336
335
|
}
|
|
337
336
|
catch (e) {
|
|
338
|
-
|
|
339
|
-
drainFailure = e;
|
|
337
|
+
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=park-usage ${errorText(e)}`);
|
|
340
338
|
}
|
|
341
339
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
340
|
+
try {
|
|
341
|
+
await append(word, parkEventData(result, reopened));
|
|
342
|
+
}
|
|
343
|
+
catch (e) {
|
|
344
|
+
recordFailOpen("server.runs.terminal-ledger-write-failed", `arm=park-row ${errorText(e)}`);
|
|
345
|
+
}
|
|
345
346
|
}
|
|
346
347
|
export function taskStartedEventData(ev) {
|
|
347
348
|
return {
|
package/dist/trace/redact.d.ts
CHANGED
|
@@ -266,6 +266,18 @@ export declare function redactSecrets(text: string, opts?: {
|
|
|
266
266
|
json?: boolean;
|
|
267
267
|
before?: string;
|
|
268
268
|
}): string;
|
|
269
|
+
/**
|
|
270
|
+
* **一个孤立的标识符(目录条目名)本身是不是一枚凭据形** —— 与 {@link redactSecretsWithArms} 的强臂读法是**两个问题**:那一个问「这段自由文本里有没有一枚凭据」
|
|
271
|
+
* (规则素材闸:整条命令),这一个问「这个孤立的值**本身**是不是一枚凭据」。三条律,都不带一条自己的正则,读的是同一个候选池、同一张臂表:
|
|
272
|
+
* ① **档 `"bounded-unit"`**([ref],{@link RedactionScope}):标识符不是自由文本,词法关键字臂出局 —— `tokenizer-model-2026-11-08` 里的 `token` 不是「令牌关键字 + 值」
|
|
273
|
+
* (自由文本档对它的读数是 `token «redacted»`);值形臂〔前缀 + 值形 + 长度下限〕与结构锚臂留在档里;
|
|
274
|
+
* ② **只认强证据臂**(`full` 档;弱证据残片臂是为兜上游截断过的残片而宁多脱的短前缀启发式,被判的是运维写的完整串,它们的前提不成立);
|
|
275
|
+
* ③ **凭据形在串首**(**同一条**强认领起点 = 0 —— 串首是弱认领、强认领嵌在后面的不算,如 `ASIAPACIFIC1.mask-rcnn-…`):「名字**就是**一枚凭据」是把密钥误贴进名字位的形;名字里嵌着的 `sk-` + 长体(`mask-rcnn-resnet50-fpn-1x-coco` 里的 `sk-rcnn-…`,
|
|
276
|
+
* 脱敏器在自由文本里为真钥紧贴普通词字符也遮,宁多脱)不是 —— 拒收一个现实名字的代价(模型不可用)与多遮一截日志的代价不是一个量级。
|
|
277
|
+
* 只问不出门(`observe: false`,不计「已脱」读数)。实际判别力 = 「值段带已知凭据前缀」({@link unitCarriesCredential} 顶注的 🚧):没有前缀的高熵串不认 ——
|
|
278
|
+
* 是「认得出的凭据形不收」,不是「名字里不会有秘密」。读者:目录条目名的入口判据(`model-entry-refusal.ts`)。
|
|
279
|
+
*/
|
|
280
|
+
export declare function isCredentialShapedUnit(unit: string): boolean;
|
|
269
281
|
/**
|
|
270
282
|
* 脱敏 + **这一遍命中了哪些档位的臂**({@link RedactionArm} 闭集两词)—— 与 {@link redactSecrets} 同一只
|
|
271
283
|
* 脱敏器、同一张表、同一遍扫描的另一个出口。
|