@sema-agent/server 7.128.0 → 7.129.1

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.
Files changed (105) hide show
  1. package/MIGRATION.md +140 -0
  2. package/USAGE.md +114 -18
  3. package/dist/approval-card.d.ts +53 -26
  4. package/dist/approval-card.js +40 -11
  5. package/dist/approval-crash-convergence.js +4 -4
  6. package/dist/bake-runner/main.js +2 -1
  7. package/dist/boot/execution-env.js +1 -0
  8. package/dist/boot/memory-consolidation.d.ts +46 -16
  9. package/dist/boot/memory-consolidation.js +15 -8
  10. package/dist/boot/side-query-lane.d.ts +7 -20
  11. package/dist/boot/side-query-lane.js +0 -24
  12. package/dist/boot/stage-01-config.js +3 -0
  13. package/dist/boot/stage-06-runners.js +1 -1
  14. package/dist/boot/stores.js +2 -2
  15. package/dist/boot/web-admin.js +17 -10
  16. package/dist/boot/webfetch-summarize-lane.d.ts +10 -7
  17. package/dist/boot/webfetch-summarize-lane.js +2 -3
  18. package/dist/brain.js +6 -9
  19. package/dist/capabilities/builtin-tools.d.ts +2 -2
  20. package/dist/capabilities/engine-capabilities.d.ts +14 -0
  21. package/dist/capabilities/engine-capabilities.js +12 -0
  22. package/dist/capability-facts.d.ts +3 -1
  23. package/dist/capability-facts.js +1 -0
  24. package/dist/config-catalog.js +5 -1
  25. package/dist/config-types.d.ts +7 -3
  26. package/dist/config.js +7 -1
  27. package/dist/egress-redirect.d.ts +12 -0
  28. package/dist/egress-redirect.js +7 -0
  29. package/dist/entry-mode-clamp-notice.d.ts +30 -0
  30. package/dist/entry-mode-clamp-notice.js +13 -0
  31. package/dist/exec-bounds.d.ts +69 -0
  32. package/dist/exec-bounds.js +37 -0
  33. package/dist/fleet/fleet-bus.d.ts +7 -0
  34. package/dist/fleet/fleet-bus.js +1 -0
  35. package/dist/hooks/hook-llm.js +6 -2
  36. package/dist/host-lsp-manager.d.ts +3 -3
  37. package/dist/http/admission.js +5 -2
  38. package/dist/http/resume-legs.js +46 -27
  39. package/dist/http/route-ctx.d.ts +1 -1
  40. package/dist/http/routes/approvals-assistant.js +6 -4
  41. package/dist/http/routes/capabilities.js +1 -0
  42. package/dist/http/routes/session-sync.js +3 -4
  43. package/dist/http/routes/sessions.js +4 -17
  44. package/dist/http/send.d.ts +1 -1
  45. package/dist/http/send.js +4 -3
  46. package/dist/http/wire-types.d.ts +3 -2
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.js +1 -1
  49. package/dist/observability/fail-open.d.ts +7 -3
  50. package/dist/observability/fail-open.js +7 -3
  51. package/dist/observability/secret-env-scrub.d.ts +37 -3
  52. package/dist/observability/secret-env-scrub.js +2 -2
  53. package/dist/parked-decide.js +5 -2
  54. package/dist/plugins/memory-embedder.js +5 -0
  55. package/dist/plugins/one-time-migrations.d.ts +180 -9
  56. package/dist/plugins/one-time-migrations.js +315 -3
  57. package/dist/plugins/pg-pool.js +3 -1
  58. package/dist/plugins/remote-env-e2b.d.ts +31 -9
  59. package/dist/plugins/remote-env-e2b.js +77 -26
  60. package/dist/plugins/remote-env-host.d.ts +17 -20
  61. package/dist/plugins/remote-env-host.js +20 -30
  62. package/dist/plugins/remote-env-k8s.d.ts +12 -4
  63. package/dist/plugins/remote-env-k8s.js +22 -31
  64. package/dist/plugins/session-policy-store-sql.d.ts +16 -4
  65. package/dist/plugins/session-policy-store-sql.js +17 -20
  66. package/dist/plugins/session-rules-column.d.ts +16 -0
  67. package/dist/plugins/session-rules-column.js +6 -0
  68. package/dist/plugins/tidb-pool.js +4 -1
  69. package/dist/read-face-posture.d.ts +2 -1
  70. package/dist/request-value-closure.js +1 -1
  71. package/dist/retired-card-words.d.ts +17 -0
  72. package/dist/retired-card-words.js +49 -0
  73. package/dist/rule-entry-list.js +2 -0
  74. package/dist/run-local.js +10 -3
  75. package/dist/server-secret-env.d.ts +77 -85
  76. package/dist/server-secret-env.js +40 -26
  77. package/dist/session-policy-wire.d.ts +61 -124
  78. package/dist/session-policy-wire.js +59 -121
  79. package/dist/session-sync.d.ts +8 -6
  80. package/dist/session-sync.js +6 -5
  81. package/dist/spec-fields.d.ts +3 -2
  82. package/dist/standing-answer-grant.d.ts +17 -9
  83. package/dist/standing-answer-grant.js +11 -8
  84. package/dist/task-settings.d.ts +6 -1
  85. package/dist/task-settings.js +1 -1
  86. package/dist/tool-approval.d.ts +14 -7
  87. package/dist/tool-approval.js +23 -18
  88. package/dist/trace/core-keyset-guard.d.ts +3 -3
  89. package/dist/trace/engine-notice-wire.d.ts +1 -1
  90. package/dist/trace/engine-notice-wire.js +1 -0
  91. package/dist/trace/project.d.ts +7 -4
  92. package/dist/trace/project.js +6 -75
  93. package/dist/trace/tool-output-media.d.ts +2 -1
  94. package/dist/trace/tool-output-media.js +3 -25
  95. package/dist/web-admin-client/apply-effective.js +28 -11
  96. package/dist/web-admin-client/facade.d.ts +1 -1
  97. package/dist/web-admin-client/facade.js +1 -1
  98. package/dist/web-admin-client/read-face.d.ts +73 -20
  99. package/dist/web-admin-client/read-face.js +76 -36
  100. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  101. package/dist/web-admin-client/skills-mcp.js +1 -1
  102. package/dist/web-admin-client/types.d.ts +3 -3
  103. package/package.json +3 -3
  104. package/dist/mcp-tool-axes.d.ts +0 -62
  105. package/dist/mcp-tool-axes.js +0 -47
@@ -21,7 +21,7 @@
21
21
  * 没有方法、没有捕获的行为。
22
22
  */
23
23
  import { z } from "zod";
24
- import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type AskRequest as CoreAskRequest, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type RuleOffer, type SteerReplayFacet } from "@sema-agent/core";
24
+ import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type ResumeStartupCause, type RuleOffer, type RuleOffersAbsence as CoreRuleOffersAbsence, type SteerReplayFacet } from "@sema-agent/core";
25
25
  import type { AskRow } from "./plugins/approval-ask-store-sql.js";
26
26
  /** 模型自由文本(`sourceAgentName` / `delegation.agentName`)的限长(设计稿 §6.2)。设计 §3.1 把
27
27
  * 「限长 + 脱敏」写成 **server 新增责任**(引擎无此层):spawning model 挑的名字是自由文本,
@@ -384,22 +384,19 @@ export declare function readAllowRuleShadowed(req: unknown): AllowRuleShadowProj
384
384
  */
385
385
  export declare function readRuleEvidence(req: unknown): RuleEvidenceProjection | undefined;
386
386
  /**
387
- * [ref] 第五单(core [ref] 修②)—— `ruleOffers` 缺席因由的**闭三词集**。
387
+ * [ref] 第五单(core [ref] 修②)—— `ruleOffers` 缺席因由的**闭集**。
388
388
  *
389
- * 🔴 **型从 core 派生,不手抄**(S-249):core 刻意**不导出**这个名字,也不导出运行期常量
390
- * (`permission-rule-lanes.d.ts` 顶注逐字:「Deliberately not exported: this is a wire vocabulary, and its
391
- * two faces declare it literally … so a consumer reads the closed set on the type it is holding」)——
392
- * 于是本仓**必须**自持一份运行期词表(zod 要字面元组),但**不必**自持一份型。做法:型 =
393
- * `AskRequest["ruleOffersAbsence"]` 的联合(那正是 core 要我们读的那张脸),运行期词表另立一行,
394
- * 两者之间架**两向编译围栏** ⇒ core 加词 / 改词 / 退役任一,本文件当场 tsc 红。
395
- * (对照 {@link AskEvidenceAbsenceSchema}:那一族 core **给了**运行期常量,所以那边零词表、用 `z.custom`。
396
- * 两族的姿势不同不是分歧,是「上游给什么就用什么」的同一条纪律的两种兑现。)
389
+ * 🔴 **型与运行期词表都读 core 的导出**(core 7.51.0 #1515 起 core 导出 `RULE_OFFERS_ABSENCES` 与 `RuleOffersAbsence`):
390
+ * 此前 core 刻意不导出这张词表,本仓只能自持一份手抄运行期表(zod 要字面元组)+ 两向编译围栏;core 给了常量之后
391
+ * 那份手抄表与围栏退役(一个事实一个来源)—— 与 {@link AskEvidenceAbsenceSchema}「上游给了运行期常量就零词表」同一条纪律。
392
+ * 7.51.0 的词:`mandated` / `allow_outranked` / `ask_rule_matched` / `lane_cannot_speak`(`shadowed` 退役、拆成中间两词)。
397
393
  */
398
- export type RuleOffersAbsence = NonNullable<CoreAskRequest["ruleOffersAbsence"]>;
394
+ export type RuleOffersAbsence = CoreRuleOffersAbsence;
399
395
  export declare const RuleOffersAbsenceSchema: z.ZodEnum<{
400
396
  mandated: "mandated";
397
+ allow_outranked: "allow_outranked";
398
+ ask_rule_matched: "ask_rule_matched";
401
399
  lane_cannot_speak: "lane_cannot_speak";
402
- shadowed: "shadowed";
403
400
  }>;
404
401
  /**
405
402
  * `ruleOffersAbsence` 座的**三态读数**(S-663 codex r1 起;此前是 {@link readRuleOffersAbsence} 函数体内的两步)。
@@ -464,6 +461,9 @@ type ToolApprovalPark = Extract<CorePendingAction, {
464
461
  * `AskRequest.origin`(盖章点即 core 的筛点),照旧只过「非空串」形门(`tool-approval.ts` 帧键 `origin` 顶注)。
465
462
  * · `classifierNoRuling`(core 7.43.0 #1353)—— 分类器没给判词的成因词,core `AUTO_MODE_FALLBACK_CAUSES` 闭集一词(筛 = `isAutoModeFallbackCause`)。
466
463
  * 读者:活卡帧读 `AskRequest.classifierNoRuling`(`tool-approval.ts`);inbox 行读 core `CheckpointSummary` 已筛过的同名位、直投不经本函数。
464
+ * · `cause`(core 7.51.0 #1448)—— **载体是引擎续跑回执的 `details`**(不是 ask 的三个载体之一),值是起跑失败的成因词,core `RESUME_STARTUP_CAUSES` 闭集一词
465
+ * (成员表取 core 常量;core 的 `resumeStartupCauseOf` 从失败的**码**读出)。读者:`parked-decide.ts` 的 422 `parked_resume.startup_failed` 体(`cause`)。
466
+ * 回执没说 ⇒ 缺席(不计数,「分不出」是一等状态);集外词 / 非串 ⇒ 按缺席(键不上 wire)+ 计一次,与卡上的闭集词同一只计数。
467
467
  * · `differs`(core 7.44.0 #1374)—— **载体是引擎拒 steer 重放那只错的 `detail`**(不是 ask 的三个载体之一),值是 core `STEER_REPLAY_FACETS` 的**非空子集**
468
468
  * (core:「恒非空」;筛 = 本文件 {@link isSteerReplayDiffers},成员表取 core 常量)。读者:`runs.ts` 的 409 `steering.duplicate_input_id` 体(`detail.differs`)。
469
469
  * 集外成员 / 空数组 / 非数组 ⇒ 按缺席(不铸 `detail`,码仍是契约)+ 计一次;detail 只报形名(`differs=<array>` —— 数组从不展开成员,见 {@link outOfSetDetail})。
@@ -480,12 +480,14 @@ type ToolApprovalPark = Extract<CorePendingAction, {
480
480
  * 只读值不调用值)。
481
481
  */
482
482
  export declare function readClosedWordSeat<S extends ClosedWordSeat>(carrier: object, seat: S): ClosedWordOf<S> | undefined;
483
- /** ask 载体上的闭集词座名:三个 core 载体上**同名**(`AskRequest` / 寄存行 `tool_approval` 臂 / `CheckpointSummary`)—— 任一处改名 / 退役 ⇒ 下面的围栏编译红。 */
484
- type AskClosedWordSeat = "mandate" | "origin" | "classifierNoRuling";
483
+ /** ask 载体上的闭集词座名:三个 core 载体上**同名**(`AskRequest` / 寄存行 `tool_approval` 臂 / `CheckpointSummary`)—— 任一处改名 / 退役 ⇒ 下面的围栏编译红。
484
+ * S-1493(core 7.51.0 #1688)起第四座 `boundGrantAbsence`:卡为什么没有授予绑定摘要(`not_bindable` / `unreadable`)。 */
485
+ type AskClosedWordSeat = "mandate" | "origin" | "classifierNoRuling" | "boundGrantAbsence";
485
486
  /** 闭集词座的名 = ask 载体上的三座 + 引擎拒 steer 重放那只错的 `detail.differs`(载体不同、读法同一只)。 */
486
- type ClosedWordSeat = AskClosedWordSeat | "differs";
487
- /** 一座的值型:ask 三座 = core 寄存行上那一座的型(去掉可选位的 `undefined`);`differs` = core 闭集 `SteerReplayFacet` 的数组(core `detail.differs` 的型)。 */
488
- type ClosedWordOf<S extends ClosedWordSeat> = S extends AskClosedWordSeat ? NonNullable<ToolApprovalPark[S]> : readonly SteerReplayFacet[];
487
+ type ClosedWordSeat = AskClosedWordSeat | "differs" | "cause";
488
+ /** 一座的值型:ask 座 = core 寄存行上那一座的型(去掉可选位的 `undefined`);`differs` = core 闭集 `SteerReplayFacet` 的数组(core `detail.differs` 的型);
489
+ * `cause` = core 的 `ResumeStartupCause`(续跑回执 `details.cause` 的型)。 */
490
+ type ClosedWordOf<S extends ClosedWordSeat> = S extends AskClosedWordSeat ? NonNullable<ToolApprovalPark[S]> : S extends "differs" ? readonly SteerReplayFacet[] : ResumeStartupCause;
489
491
  /**
490
492
  * 🔴 **S-934 ②(core 7.37.0 #1214)—— ask 类对的唯一窄读**:`askClass`(一问的类 = `classes` 的首员)与 `classes`(这一问属于的全部类,core
491
493
  * `ASK_CLASSES` 序)。三个载体上同名:`AskRequest`(活卡帧 / 呈卡帧的卡读它)、寄存行 `PendingAction.tool_approval`(运维队列行经
@@ -525,8 +527,11 @@ export interface AskClassPair {
525
527
  * bypass 姿态下按 `ask_rule` / `hook` 照问的那条壳规则无从落地。缺席 = 老行(core 7.5.0 之前 park 的)/ 集外词(计 S-249 tag)。
526
528
  * S-934 ②(core 7.37.0 #1214)第六 / 七位 `askClass` / `classes`:这一问的类对(经 {@link readAskClassPair};两位同在同缺,与活卡帧 / 呈卡帧的卡
527
529
  * 同名同义同值)—— durable 审批席按类答的依据。缺席 = 老行(core 7.37.0 之前 park 的,续跑不补)/ 读不出(计 S-249 tag)。
530
+ * S-1493(core 7.51.0 #1688)第八位 `boundGrantAbsence`:这张卡为什么没有授予绑定摘要(经 {@link readClosedWordSeat};与活卡帧 / inbox 行同名同义同值)——
531
+ * `not_bindable` = 这一问不绑任何授予(「本会话放行」可按工具记)。缺席 = 技能卡(带摘要;摘要不上队列行,见 ⑧b)/ 7.51.0 之前停驻的行(core inbox 投
532
+ * `unreadable`,队列行如实缺席)/ 集外词(计 S-249 tag)。
528
533
  */
529
- export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin" | "askClass" | "classes">;
534
+ export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin" | "askClass" | "classes" | "boundGrantAbsence">;
530
535
  /**
531
536
  * S-700 —— park 行事实的**唯一投影**(`pendingAction` 是寄存行上 core 铸的那一只,读自持久层 ⇒ `unknown`)。
532
537
  *
@@ -553,7 +558,7 @@ export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "rule
553
558
  * `ruleOffersAbsence` 推「强制」的**权限**判据需要的是三态(读不出 ⇒ 按强制,fail-closed),方向相反,所以权限面
554
559
  * 不许拿本函数的产物去推强制 —— 两者共用的是 schema,不是折叠。
555
560
  */
556
- export declare function parkRowFacts(pendingAction: unknown): ParkRowFacts;
561
+ export declare function parkRowFacts(stored: unknown): ParkRowFacts;
557
562
  /** S-114(core 7.4.0 [ref])—— 回落卡的计数与窗。`limit` 是**闭二词**(core d.ts 逐字),两个计数是
558
563
  * 非负整数,`autoDenyAfterMs` 是 core 契约里的 `0..2147483647` 非负整数(`0` = 本卡不武装窗:部署把
559
564
  * 旋钮关了,或 TOTAL 档的卡按 [ref]① 恒 0 等人)。四成员**全必填**——core 的 `DenialLimitFallback` 上
@@ -670,8 +675,9 @@ export declare const ApprovalCardSchema: z.ZodObject<{
670
675
  }, z.core.$strict>]>>>;
671
676
  ruleOffersAbsence: z.ZodOptional<z.ZodEnum<{
672
677
  mandated: "mandated";
678
+ allow_outranked: "allow_outranked";
679
+ ask_rule_matched: "ask_rule_matched";
673
680
  lane_cannot_speak: "lane_cannot_speak";
674
- shadowed: "shadowed";
675
681
  }>>;
676
682
  denialLimitFallback: z.ZodOptional<z.ZodObject<{
677
683
  consecutive: z.ZodNumber;
@@ -707,8 +713,8 @@ export declare const ApprovalCardSchema: z.ZodObject<{
707
713
  }, z.core.$strict>>>;
708
714
  personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
709
715
  }, z.core.$strict>>;
710
- askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
711
- classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
716
+ askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
717
+ classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
712
718
  fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
713
719
  sourceTaskId: z.ZodOptional<z.ZodString>;
714
720
  sourceAgentName: z.ZodOptional<z.ZodString>;
@@ -804,8 +810,9 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
804
810
  }, z.core.$strict>]>>>;
805
811
  ruleOffersAbsence: z.ZodOptional<z.ZodEnum<{
806
812
  mandated: "mandated";
813
+ allow_outranked: "allow_outranked";
814
+ ask_rule_matched: "ask_rule_matched";
807
815
  lane_cannot_speak: "lane_cannot_speak";
808
- shadowed: "shadowed";
809
816
  }>>;
810
817
  denialLimitFallback: z.ZodOptional<z.ZodObject<{
811
818
  consecutive: z.ZodNumber;
@@ -841,8 +848,8 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
841
848
  }, z.core.$strict>>>;
842
849
  personalRuleDotsAbsent: z.ZodOptional<z.ZodCustom<AskEvidenceAbsence, AskEvidenceAbsence>>;
843
850
  }, z.core.$strict>>;
844
- askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
845
- classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "governance_unavailable" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
851
+ askClass: z.ZodOptional<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>;
852
+ classes: z.ZodOptional<z.ZodArray<z.ZodCustom<"mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", "mode" | "hook" | "org_rule" | "write_protection" | "target_unresolved" | "content_question" | "ask_rule" | "denial_limit_fallback" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "transcript_write" | "rule_unreadable" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary">>>;
846
853
  fromSubagent: z.ZodOptional<z.ZodLiteral<true>>;
847
854
  sourceTaskId: z.ZodOptional<z.ZodString>;
848
855
  sourceAgentName: z.ZodOptional<z.ZodString>;
@@ -912,8 +919,28 @@ export interface ApprovalCardSource {
912
919
  * 头注。)
913
920
  */
914
921
  export declare function buildApprovalCard(source: ApprovalCardSource, req: unknown, requiresRealApproval: boolean): ApprovalCard;
915
- /** 落库信封的纯构造(写侧;读侧 = `ApprovalCardEnvelopeSchema.safeParse`,**同一个 schema**)。 */
922
+ /** 落库信封的纯构造(写侧;读侧 = {@link readStoredCardEnvelope},**同一个 schema**)。 */
916
923
  export declare function buildApprovalCardEnvelope(approvalId: string, card: ApprovalCard): ApprovalCardEnvelope;
924
+ /**
925
+ * 🔴 **存下的卡的唯一读者入口**(S-1562)—— `approval_ask.card_json` 的每一个读点(断连重放 {@link buildReplayFrame}、回决口的「要不要人」
926
+ * {@link storedCardDemandsAPerson}、幂等重入与规则兑付两处(`tool-approval.ts`)、local 车道的启动收敛(`approval-crash-convergence.ts`))都经这一只,
927
+ * 不各自 `safeParse`(修前五处各写一遍 —— 读法的任何一次改动都要改五处,漏一处就是两种读法)。
928
+ *
929
+ * 读法 = **一次性迁移 M18 的读侧半场 + 同一只 schema**:7.128.x 写下的卡上两座可能带引擎 7.51.0 退役的词(`ruleOffersAbsence: "shadowed"` /
930
+ * 类对里的 `governance_unavailable`),起服改写够不着的行(滚动升级窗里旧副本新写的、local 车道的文件 ask 账)读时过同一只改写
931
+ * (`retired-card-words.ts`),**响亮**:每改写一次计一次 `server.approval-card.retired-card-word-read`(计数 + probe + 一次 warn,detail 只报座名)。
932
+ * 窗关(登记表 M18)后读侧半场随起服改写一起删,本函数回到「只 `safeParse`」。读不出(真坏形)⇒ `undefined`,各读点的处置不变(跳过 + warn / park /
933
+ * 按要人 / 素材缺席 / 收敛成因按缺省)。
934
+ */
935
+ export declare function readStoredCardEnvelope(cardJson: unknown): ApprovalCardEnvelope | undefined;
936
+ /**
937
+ * 🔴 **停驻行 `tool_approval` 臂的读侧入口**(S-1562;一次性迁移 M18 的读侧半场)—— 读它两座的两个读者(运维队列行 {@link parkRowFacts}、
938
+ * 耐久 `/decide` 的 remember 判据 `tool-approval.ts` `parkRowStandingAnswerFacts`)先经这一只:7.50.x 停驻的行上两座的退役词按 M18 那一只改写读,
939
+ * 响亮(同一个 tag)。停驻行是**引擎写的文档**,没有起服改写这一半:引擎的行摘要覆盖类对 `askClass` / `classes`,本服务改写 = 续跑判官判 `damaged`、拒续跑 ⇒ **所有**停驻行
940
+ * (SQL 店的、local 车道引擎 File 店的)都只在这里读时改写,交的是浅拷贝,被读的行一个字节不动。
941
+ * 改写之后读者只读 core 的一张闭集,「读不出 ⇒ 按强制」只会遇到真坏形。别的臂 / 非对象 ⇒ 原样。窗关随 M18 一起删。
942
+ */
943
+ export declare function currentParkArm<T>(pendingAction: T): T;
917
944
  /**
918
945
  * [ref] §3.1 的呈卡帧(设计稿 §4.1)—— **live 铸造**形(重放形见 {@link buildReplayFrame},
919
946
  * 两者投的是同一种帧,区别只在 `card` 的来源:这里是刚投影出来的,那里是从行上回读的)。
@@ -1,7 +1,8 @@
1
1
  import { z } from "zod";
2
- import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, STEER_REPLAY_FACETS, isAskClass, isAskOrigin, isAutoModeFallbackCause, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
2
+ import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, BOUND_GRANT_ABSENCES, MAX_RULE_TEXT_CHARS, READ_ROOT_CANDIDATE_DIR_MAX, RESUME_STARTUP_CAUSES, RULE_OFFERS_ABSENCES, STEER_REPLAY_FACETS, isAskClass, isAskOrigin, isAutoModeFallbackCause, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
3
3
  import { redactSecrets } from "./trace/redact.js";
4
4
  import { recordFailOpen } from "./observability/fail-open.js";
5
+ import { retireParkArmWords, retireStoredCardWords } from "./retired-card-words.js";
5
6
  import { PERSISTED_RULE_MATCHES, UNCOVERED_SEGMENT_REASONS } from "./permission-rule-vocab.js";
6
7
  export const MAX_AGENT_NAME = 200;
7
8
  const MAX_IDENT = 200;
@@ -267,8 +268,7 @@ export function readRuleEvidence(req) {
267
268
  ...(raw.personalRuleDotsAbsent !== undefined ? { personalRuleDotsAbsent: raw.personalRuleDotsAbsent } : {}),
268
269
  };
269
270
  }
270
- const RULE_OFFERS_ABSENCE_VALUES = ["mandated", "lane_cannot_speak", "shadowed"];
271
- export const RuleOffersAbsenceSchema = z.enum(RULE_OFFERS_ABSENCE_VALUES);
271
+ export const RuleOffersAbsenceSchema = z.enum(RULE_OFFERS_ABSENCES);
272
272
  const RuleOffersAbsenceEnvelopeSchema = z.object({ ruleOffersAbsence: RuleOffersAbsenceSchema.optional() });
273
273
  export function readRuleOffersAbsenceSeat(x) {
274
274
  const parsed = RuleOffersAbsenceEnvelopeSchema.safeParse(x);
@@ -318,11 +318,21 @@ function isSteerReplayDiffers(v) {
318
318
  const facets = STEER_REPLAY_FACETS;
319
319
  return Array.isArray(v) && v.length > 0 && v.every((f) => facets.includes(f));
320
320
  }
321
+ function isResumeStartupCause(v) {
322
+ const words = RESUME_STARTUP_CAUSES;
323
+ return words.includes(v);
324
+ }
325
+ function isBoundGrantAbsence(v) {
326
+ const words = BOUND_GRANT_ABSENCES;
327
+ return words.includes(v);
328
+ }
321
329
  const CLOSED_WORD_SEAT_GUARDS = {
322
330
  mandate: isPersistedRuleMandate,
323
331
  origin: isAskOrigin,
324
332
  classifierNoRuling: isAutoModeFallbackCause,
333
+ boundGrantAbsence: isBoundGrantAbsence,
325
334
  differs: isSteerReplayDiffers,
335
+ cause: isResumeStartupCause,
326
336
  };
327
337
  export function readAskClassPair(carrier) {
328
338
  const askClass = "askClass" in carrier ? carrier.askClass : undefined;
@@ -335,13 +345,15 @@ export function readAskClassPair(carrier) {
335
345
  recordFailOpen("server.approval-card.closed-word-out-of-set", isAskClass(askClass) ? `classes=${outOfSetDetail(classes)}` : `askClass=${outOfSetDetail(askClass)}`);
336
346
  return undefined;
337
347
  }
338
- export function parkRowFacts(pendingAction) {
339
- if (typeof pendingAction !== "object" || pendingAction === null || !("kind" in pendingAction) || pendingAction.kind !== "tool_approval")
348
+ export function parkRowFacts(stored) {
349
+ if (typeof stored !== "object" || stored === null || !("kind" in stored) || stored.kind !== "tool_approval")
340
350
  return {};
351
+ const pendingAction = currentParkArm(stored);
341
352
  const ruleOffersAbsence = readRuleOffersAbsence(pendingAction);
342
353
  const mandate = readClosedWordSeat(pendingAction, "mandate");
343
354
  const origin = readClosedWordSeat(pendingAction, "origin");
344
355
  const askClassPair = readAskClassPair(pendingAction);
356
+ const boundGrantAbsence = readClosedWordSeat(pendingAction, "boundGrantAbsence");
345
357
  return {
346
358
  ...(readParkRowTrueSeat(pendingAction, "requiresRealApproval") ? { requiresRealApproval: true } : {}),
347
359
  ...(readParkRowTrueSeat(pendingAction, "mandated") ? { mandated: true } : {}),
@@ -349,6 +361,7 @@ export function parkRowFacts(pendingAction) {
349
361
  ...(origin !== undefined ? { origin } : {}),
350
362
  ...(ruleOffersAbsence !== undefined ? { ruleOffersAbsence } : {}),
351
363
  ...(askClassPair ?? {}),
364
+ ...(boundGrantAbsence !== undefined ? { boundGrantAbsence } : {}),
352
365
  };
353
366
  }
354
367
  const DenialLimitFallbackSchema = z
@@ -492,6 +505,22 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
492
505
  export function buildApprovalCardEnvelope(approvalId, card) {
493
506
  return { schemaVersion: APPROVAL_CARD_SCHEMA_VERSION, approvalId, card };
494
507
  }
508
+ export function readStoredCardEnvelope(cardJson) {
509
+ const stored = retireStoredCardWords(cardJson);
510
+ if (stored.seats.length > 0)
511
+ noteRetiredCardWordRead("card_json", stored.seats);
512
+ const parsed = ApprovalCardEnvelopeSchema.safeParse(stored.value);
513
+ return parsed.success ? parsed.data : undefined;
514
+ }
515
+ export function currentParkArm(pendingAction) {
516
+ const arm = retireParkArmWords(pendingAction);
517
+ if (arm.seats.length > 0)
518
+ noteRetiredCardWordRead("parked row", arm.seats);
519
+ return arm.value;
520
+ }
521
+ function noteRetiredCardWordRead(carrier, seats) {
522
+ recordFailOpen("server.approval-card.retired-card-word-read", `${carrier}: ${seats.join(" / ")}`);
523
+ }
495
524
  export function buildApprovalRequestFrame(input) {
496
525
  return {
497
526
  type: "approval_request",
@@ -510,8 +539,8 @@ export function buildRevokeFrame(batchId, askIds, reason, serverNowMs, originTas
510
539
  return { type: "approval_revoke", schemaVersion: 1, batchId, askIds: [...askIds], reason, serverNowMs, taskId: originTaskId };
511
540
  }
512
541
  export function buildReplayFrame(row, nowMs) {
513
- const parsed = ApprovalCardEnvelopeSchema.safeParse(row.cardJson);
514
- if (!parsed.success)
542
+ const parsed = readStoredCardEnvelope(row.cardJson);
543
+ if (parsed === undefined)
515
544
  return undefined;
516
545
  return {
517
546
  type: "approval_request",
@@ -519,16 +548,16 @@ export function buildReplayFrame(row, nowMs) {
519
548
  askId: row.askId,
520
549
  taskId: row.taskId,
521
550
  kind: "permission",
522
- card: parsed.data.card,
551
+ card: parsed.card,
523
552
  expiresAtMs: row.expiresAtMs,
524
553
  expiresInMs: Math.max(0, row.expiresAtMs - nowMs),
525
554
  serverNowMs: nowMs,
526
- approvalId: parsed.data.approvalId,
555
+ approvalId: parsed.approvalId,
527
556
  };
528
557
  }
529
558
  export function storedCardDemandsAPerson(cardJson) {
530
- const parsed = ApprovalCardEnvelopeSchema.safeParse(cardJson);
531
- return !parsed.success || parsed.data.card.risk.requiresRealApproval;
559
+ const parsed = readStoredCardEnvelope(cardJson);
560
+ return parsed === undefined || parsed.card.risk.requiresRealApproval;
532
561
  }
533
562
  export function buildApprovalPreamble(rows, nowMs, replayMax) {
534
563
  const frames = [];
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { APPROVAL_ASK_AUDIT_DIR, APPROVAL_ASK_AUDIT_LEDGER, FileApprovalAskAuditStore } from "./approval-ask-audit-store.js";
4
- import { ApprovalCardEnvelopeSchema } from "./approval-card.js";
4
+ import { readStoredCardEnvelope } from "./approval-card.js";
5
5
  import { APPROVAL_ENDING_CAUSES } from "./approval-deny-reasons.js";
6
6
  import { writerGoneEvidenceFor } from "./user-input-ledger.js";
7
7
  import { recordFailOpen } from "./observability/fail-open.js";
@@ -31,12 +31,12 @@ export async function convergeCrashedAsksAtBoot(input) {
31
31
  break;
32
32
  for (const row of page) {
33
33
  seen.add(row.askId);
34
- const envelope = ApprovalCardEnvelopeSchema.safeParse(row.cardJson);
35
- if (!envelope.success) {
34
+ const envelope = readStoredCardEnvelope(row.cardJson);
35
+ if (envelope === undefined) {
36
36
  causeUnreadable += 1;
37
37
  recordFailOpen("server.approval-crash-convergence.cause-unreadable", `ask ${row.askId} (task ${row.taskId}): card envelope unreadable — cause defaulted to ${APPROVAL_ENDING_CAUSES.CRASHED_BEFORE_PARK}`);
38
38
  }
39
- const reason = envelope.success && input.audit !== undefined ? input.audit.causeFor(envelope.data.approvalId) : APPROVAL_ENDING_CAUSES.CRASHED_BEFORE_PARK;
39
+ const reason = envelope !== undefined && input.audit !== undefined ? input.audit.causeFor(envelope.approvalId) : APPROVAL_ENDING_CAUSES.CRASHED_BEFORE_PARK;
40
40
  let won;
41
41
  try {
42
42
  won = await store.transitionAsk(row.askId, "STREAM_PENDING", "VOID", { deniedReason: reason, updatedAtMs: now() });
@@ -3,7 +3,7 @@ import { readFile } from "node:fs/promises";
3
3
  import { createLogger } from "../observability/logger.js";
4
4
  import { logConfigDiagnostics, parseEnvNameAllowlist, parseNumOrFailNonNegative } from "../config.js";
5
5
  import { installSecretEnvScrubRecorder } from "../observability/secret-env-scrub.js";
6
- import { hostSubprocessEnv } from "../server-secret-env.js";
6
+ import { declareServerWithheldEnv, hostSubprocessEnv } from "../server-secret-env.js";
7
7
  import { shellQuote as shellSafe } from "../plugins/remote-shell.js";
8
8
  import { BakeRunner, } from "./runner.js";
9
9
  const BAKE_CLAIM_INGEST_FETCH_TIMEOUT_MS = 30_000;
@@ -256,6 +256,7 @@ function makeClock() {
256
256
  };
257
257
  }
258
258
  async function main() {
259
+ declareServerWithheldEnv();
259
260
  const env = loadEnv();
260
261
  const log = createLogger(process.env.LOG_LEVEL || "info");
261
262
  logConfigDiagnostics(log);
@@ -222,6 +222,7 @@ export function createExecutionEnv(ctx) {
222
222
  ...(config.remoteExec.runtimeClass != null ? { runtimeClass: config.remoteExec.runtimeClass } : {}),
223
223
  ...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
224
224
  ...(config.remoteExec.timeoutMs != null ? { timeoutMs: config.remoteExec.timeoutMs } : {}),
225
+ ...(config.remoteExec.livenessMs != null ? { livenessMs: config.remoteExec.livenessMs } : {}),
225
226
  dataTimeoutMs: workspaceSnapshotTimeoutOf(config.remoteExec),
226
227
  ...(config.remoteExec.memory ? { memory: config.remoteExec.memory } : {}),
227
228
  ...(config.remoteExec.cpu ? { cpu: config.remoteExec.cpu } : {}),
@@ -1,6 +1,7 @@
1
+ import { type LaneHomeDeployment } from "../execution-lane-caps.js";
1
2
  import type { RestartSliceCtx } from "../web-admin-client/restart-signal.js";
2
3
  import type { MemoryConsolidationDriverConfig, ServiceConfig } from "../config-types.js";
3
- import { resolveMemoryConsolidationDriver, type ConsolidationWriteJudge, type EngineNotice, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryBackend, type MemoryConsolidationDriverDeps, type SessionCaptureRecordStore } from "@sema-agent/core";
4
+ import { resolveMemoryConsolidationDriver, type ConsolidationWriteJudge, type ConsolidationWriteJudgeInput, type EngineNotice, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type MemoryBackend, type MemoryConsolidationDriverDeps, type PermissionRuleStoreProvider, type SessionCaptureRecordStore } from "@sema-agent/core";
4
5
  /**
5
6
  * 座解析的 options 形 = core 解析器交回的那只(core 7.50.0 起它**不含** `writeJudge`:判官不是模型席的一部分,由调用方在动词上带)。
6
7
  * 取解析器的返回型而不是自己写 `Omit<…>`:形的属主是 core 的解析器,本仓不持第二份。
@@ -396,26 +397,55 @@ export declare function assertAutoConsolidationWirable(input: {
396
397
  memoryConsolidationWired: boolean;
397
398
  }): void;
398
399
  /**
399
- * 运维阀门腿的写判官座(core 7.50.0 起驱动动词必带)。
400
+ * 运维阀门腿的写判官座的**输入**(core 的判官构造器 `createConsolidationWriteJudge` 的 `input`)。返回值带一只**活的**规则店 provider(有行为,不是纯数据)⇒ `create*`(工厂命名律:`build*` 只产纯数据;不拆店出返回值,因为输入就是引擎构造器要的那一只形,多拆一个函数只会多一个规则)。
400
401
  *
401
- * ## 判官只有一只,这条腿拿不到它
402
+ * ## 构造器只有引擎那一只,本仓只供部署事实
402
403
  *
403
- * 「这条路径能不能写」在引擎里只有**一只**判官(合成写判官:技能拒行 / 收窄折叠 / 调用方与继承策略 / 人的持久规则车道 /
404
- * 组织车道,一条走法一个优先序);引擎的自动整理腿把**腿自己的**那只交给驱动。本腿(运维手动阀门)没有腿:没有名册上的
405
- * `Write` 脸、没有引擎盖的豁免根与工作目录、没有持久规则车道 —— 而引擎包今天不导出那只判官的构造器。在本仓手搭一只
406
- * 「对部署策略问一次合成 `Write`」的判官 = 把引擎判官的层走法、脸、豁免根、已中止信号的约定与判词读法**再写一份**
407
- * (第二个读者,与引擎那只迟早分歧,而且分歧是静默的)。所以本腿不造第二只。
404
+ * 「这条路径能不能写」在引擎里只有**一只**判官(合成写判官:技能拒行 / 收窄折叠 / 调用方与继承策略 / 人的持久规则车道 / 组织车道,一条走法一个优先序)。
405
+ * 引擎的自动整理腿(有腿:名册上的 `Write` 脸、引擎盖的豁免根、人的持久规则读者)与本腿(运维手动阀门:没有腿)用的是**同一个构造器** ——
406
+ * 同样的行给同样的答案,本仓不手搭第二只({@link createOperatorValveWriteJudge} 恰一处调用它,见 `test/memory-consolidation-write-judge.test.ts` ⑥)。
408
407
  *
409
- * ## 于是它是一只**响亮的放行座**,登记为保护型欠账
408
+ * ## 本仓供的两个部署事实(其余键一律缺席,缺席的语义见引擎:那一层不存在)
409
+ *
410
+ * · `ruleStoreProvider` = 部署唯一的那只合成规则店(`RunnerDeps.permissionRuleStore` 的同一个变量,装配第 4 段铸一次)。规则店没装配 ⇒ 缺席 ⇒ 没有规则层。
411
+ * · `anchors.home` = `executionLaneHomeDir(config)` —— `~/` 行的基,与引擎执行环境的 `homeDir` 座、下单 422 门、规则基 `taskHome` 是**同一只函数**
412
+ * (车道没有自己的 home 时诚实缺席;缺席 ⇒ 引擎读到人持有的 `~/` 收紧行时无处锚定 = 按异议处置,拒闭)。**刻意不另调 `os.homedir()`**:
413
+ * 那会在非 host 车道上造出第二个读法 —— 阀门答「可解析」而腿内答「读不出」。⚠️ 今天这一键在生产座上**空转**:阀门不带主体(下面的 `principal`),
414
+ * 引擎读匿名地板、不读任何人的持久行,「`~/` 行无锚 ⇒ 拒闭」走不到;留着它是为了主体有了来源之后不必再回来改这里。
415
+ *
416
+ * ## 刻意缺席的键(披露,不是遗漏)—— 三层没喂,所以这条腿仍是**响亮的放行座**(P-DEBT,见 {@link createOperatorValveWriteJudge})
417
+ *
418
+ * · `principal` / `localOwnerDeclared`(人的持久规则层):阀门是 operator 面的一次调用,本仓没有一个能回答「这个库属于谁」的来源 ——
419
+ * 单用户 + file 后端(阀门结构上能起的唯一形,见 {@link assertConsolidationDriverWirable})里记忆是部署级全局层 / 任务根散列的项目层,principal 标签从不分盘,
420
+ * 本仓也从不声明 `localOwnerRules`;整理 run 又是按 scope 单飞、可续跑的持久作业,「谁的规则」对并入 / 续跑的调用方没有定义。
421
+ * · `callerPolicy`(部署的调用方策略层):`APPROVAL_REQUIRE` / `APPROVAL_DENY` / `AUTONOMY` / 敏感路径守卫集是**每任务现合成**的(`deployment-governance.ts`,
422
+ * 读热可改的活配置,「禁 memoize」),没有部署级单例;boot 期铸一份喂进来就是冻结一份会过期的策略(收紧不生效 = 静默放行)。喂它需要一份设计:取哪几层、
423
+ * 活配置怎么读、审批席取什么形;其中敏感路径层还要引擎的豁免根(`RunnerDeps.memoryEngineDir` 盖在每个请求上),而宿主构造器的输入没有这一位 —— 要向 core 请托,
424
+ * 不在本层造第二条豁免根的读法。
425
+ * · `anchors.root`:阀门按 scope 跑,手里没有项目根 —— 项目层 scope 键是任务根的单向散列(`project-identity.ts` 的 `repo:<sha256[:24]>`),反推不出根;
426
+ * 全局层根本没有根。⇒ 人持有的相对 deny / ask 行无处锚定 = 异议,拒闭(引擎契约:判官不猜一行原本指向哪里)。
427
+ *
428
+ * 所以今天这条腿的放行范围与 7.128.x 相同(人的规则、部署的审批名单 / 敏感路径守卫都拦不住手动阀门这一轮折叠);变的只是「判官不再是代答」—— 往后每喂一层,
429
+ * 只在本函数加键,钉 = `test/memory-consolidation-write-judge.test.ts` ⑦。
410
430
  *
411
- * 答 `no_objection` —— 与 v7.49.x 本腿的行为逐字同(那时驱动根本不问),不回退任何现网能力;每被问一次记一次
412
- * `server.memory-consolidation.operator-valve-unjudged`(P-DEBT:计数 + 探针行 + 一次性告警),债在遥测里显形。
413
431
  * 自动整理腿不受影响:它走引擎腿自己的判官,人的持久规则与部署策略照判。
414
- * 退役条件:引擎导出宿主可用的写判官构造器(收部署策略 + 一只规则店主体)那一版,本函数换成它、本 tag 删。
415
- * scope 与人:本仓的文件后端不按请求主体铸 scope(单用户形是部署声明的全局层 `MEMORY_SCOPE` 与按任务根派生的项目层),
416
- * 所以从 scope 读不出「这是谁的库」;匿名 run 读不读本地属主那只规则桶另候裁定 —— 两件都不在本座里猜。
417
432
  */
418
- export declare function createOperatorValveWriteJudge(): ConsolidationWriteJudge;
433
+ export declare function createOperatorValveJudgeInput(facts: {
434
+ /** 部署唯一的合成规则店(装配第 4 段铸一次,`RunnerDeps.permissionRuleStore` 与本座读同一只)。缺席 = 规则店没装配。 */
435
+ readonly ruleStoreProvider: PermissionRuleStoreProvider | undefined;
436
+ /** 只读 `executionLaneHomeDir` 读的两位(`ServiceConfig` 结构满足)。 */
437
+ readonly config: LaneHomeDeployment;
438
+ }): ConsolidationWriteJudgeInput;
439
+ /**
440
+ * 运维阀门腿的写判官座:引擎的判官构造器喂 {@link createOperatorValveJudgeInput},**外加一个响亮的债计数**(P-DEBT)。
441
+ *
442
+ * 构造器只有引擎那一只,本函数不判任何东西:`judge(target)` 的答案原样返回。它只在每次被问时记一次
443
+ * `server.memory-consolidation.operator-valve-layers-unfed`(计数 + 探针行 + 一次性告警)—— 因为人的规则层、部署策略层、项目根三样都没喂
444
+ * ({@link createOperatorValveJudgeInput} 头注),放行的最坏后果没变:运维手动整理时,一条点名记忆库路径的人的持久规则或部署写策略拦不住这一轮折叠
445
+ * (与 7.128.x 逐字同)。债在遥测里显形,而不是随着「判官已换成引擎的」这句话消失。自动整理腿不受影响,走引擎腿自己的判官。
446
+ * 收口 = 三层各自有了来源(人:「读谁的桶」裁定;策略:设计 + 引擎的豁免根入参;根:无来源则永久缺席并改写本债)那一版,本 tag 删。
447
+ */
448
+ export declare function createOperatorValveWriteJudge(facts: Parameters<typeof createOperatorValveJudgeInput>[0]): ConsolidationWriteJudge;
419
449
  /** 两个 admin 口消费的窄能力面(`ServiceDeps.memoryConsolidation` 的实参来源)。 */
420
450
  export interface MemoryConsolidationFaces {
421
451
  /** D3 的座位自证(投影用;boot 期解析一次,restart-to-apply)。 */
@@ -476,7 +506,7 @@ export declare function createMemoryConsolidationFaces(store: {
476
506
  * 早问库目录一次、应用时问每个产物文件,答 `no_objection` 以外一律拒写。装配层给哪一只见 {@link createOperatorValveWriteJudge}。 */
477
507
  writeJudge: ConsolidationWriteJudge;
478
508
  /** 引擎通告的**运维行**座(与 Runner 的 `onNotice` 同一只转发器)。缺席 ⇒ 通告只在回执上。判官拒的两种时机都经它走一次:
479
- * 应用时拒 = 引擎在驱动里铸的 `memory.consolidation_incomplete`;早问拒 = 驱动抛出的拒绝经引擎导出的构造器转成的
509
+ * 应用时拒 = 引擎在驱动里铸的 `memory.consolidation_incomplete`;早问拒 = 驱动抛出的拒绝经引擎导出的投递口(`deliverWriteRefusal`)转成的
480
510
  * `memory.consolidation_refused`(本仓不读通告名、不自铸通告形)。 */
481
511
  onNotice?: (notice: EngineNotice) => void;
482
512
  }): MemoryConsolidationFaces;
@@ -1,9 +1,10 @@
1
1
  import { redactSecrets } from "../trace/redact.js";
2
2
  import { recordFailOpen } from "../observability/fail-open.js";
3
3
  import { memoryMountRootOf } from "../memory-scope.js";
4
+ import { executionLaneHomeDir } from "../execution-lane-caps.js";
4
5
  import { DEFAULT_MODEL_REF, resolveMainModel } from "../model-select.js";
5
6
  import { backendOwnsControlPlane } from "../memory-operator-faces.js";
6
- import { CONSOLIDATION_WRITE_REFUSED_CODE, ConsolidationRefusedError, expandTiers, MemoryEngine, memoryConsolidationRefusedNotice, readConsolidationDriverRun, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
7
+ import { createConsolidationWriteJudge, deliverWriteRefusal, expandTiers, MemoryEngine, readConsolidationDriverRun, resolveMemoryConsolidationDriver, runMemoryConsolidationDriver, } from "@sema-agent/core";
7
8
  export function resolveConsolidationDriverSeat(deps) {
8
9
  let options;
9
10
  try {
@@ -317,10 +318,18 @@ export function assertAutoConsolidationWirable(input) {
317
318
  `unset, or set MEMORY_AUTO_CONSOLIDATION=off (unsetting it is NOT the same: the engine's named default is ON as of ` +
318
319
  `core 7.21.1).`);
319
320
  }
320
- export function createOperatorValveWriteJudge() {
321
- return () => {
322
- recordFailOpen("server.memory-consolidation.operator-valve-unjudged");
323
- return { verdict: "no_objection" };
321
+ export function createOperatorValveJudgeInput(facts) {
322
+ const home = executionLaneHomeDir(facts.config);
323
+ return {
324
+ ...(facts.ruleStoreProvider !== undefined ? { ruleStoreProvider: facts.ruleStoreProvider } : {}),
325
+ anchors: home !== undefined ? { home } : {},
326
+ };
327
+ }
328
+ export function createOperatorValveWriteJudge(facts) {
329
+ const judge = createConsolidationWriteJudge(createOperatorValveJudgeInput(facts));
330
+ return (target) => {
331
+ recordFailOpen("server.memory-consolidation.operator-valve-layers-unfed");
332
+ return judge(target);
324
333
  };
325
334
  }
326
335
  export function createMemoryConsolidationFaces(store, input) {
@@ -343,9 +352,7 @@ export function createMemoryConsolidationFaces(store, input) {
343
352
  writeJudge: input.writeJudge,
344
353
  ...(input.onNotice !== undefined ? { onNotice: input.onNotice } : {}),
345
354
  }).catch((err) => {
346
- if (input.onNotice !== undefined && err instanceof ConsolidationRefusedError && err.code === CONSOLIDATION_WRITE_REFUSED_CODE) {
347
- input.onNotice(memoryConsolidationRefusedNotice({ code: err.code, scope, reason: err.message, ...(err.occurrenceId !== undefined ? { occurrenceId: err.occurrenceId } : {}) }));
348
- }
355
+ deliverWriteRefusal(err, scope, input.onNotice);
349
356
  throw err;
350
357
  });
351
358
  if (receipt.stopDetail !== undefined) {
@@ -26,9 +26,10 @@
26
26
  * 降级成**结构性事实**(这条路上根本没有 wrapper);
27
27
  * · `headers` 半边从此有出路(wrapper 形只注得进 `apiKey`,core 的座位 `{apiKey, headers?}` 两半都收);
28
28
  * · 判据(`gatewayBaseUrl`)与 resolver 一样**按调用现取** —— 见下面 `createSideQueryLane` 的注。
29
- * `createPerModelKeyBrain` **不删**:它仍是 WebFetch 摘要面(`boot/webfetch-summarize-lane.ts`)的
30
- * key plane —— core 的 `WebFetchSummarizerOptions` 至今只有 `maxContentChars`,那一面没有座位可换
31
- * (亲验 core 5.46.0 `dist/tools/web.d.ts`)。
29
+ * `createPerModelKeyBrain` 当时**没删**:它还是 WebFetch 摘要面(`boot/webfetch-summarize-lane.ts`)的 key plane ——
30
+ * core 的 `WebFetchSummarizerOptions` 那时只有 `maxContentChars`。core 7.51.0 给摘要器补上了同一签名的座
31
+ * (`WebFetchSummarizerOptions.getApiKeyAndHeaders`)⇒ 包装退役,四面(任务 / side-query / 记忆整理 / WebFetch 摘要)
32
+ * 都经 core 的座位供给 per-model 凭据,本仓不再在任何一面包 brain。
32
33
  *
33
34
  * 🔴 **poison(声明的钥匙拿不到)上抛,绝不静默回落网关 key** —— `resolveModelApiKey` 抛
34
35
  * `ModelKeyPoisonedError` 是「这个模型配了自己的钥匙(托管密钥解不开 / S-896 起 `apiKeyEnv` 变量缺席)却拿不到」的响亮态;吞成 undefined 等于用共享
@@ -46,8 +47,9 @@
46
47
  * 是配对法的单一实现,三只一方 brain(openai / anthropic / open-responses)在 `buildRequest` 里逐次
47
48
  * 复判 —— 部署声明了 `config.baseUrl` 而 entry URL 不在那个根上、凭据又只有部署级那一份 ⇒
48
49
  * `route.credential_mismatch` 响亮拒;连部署级凭据都没有 ⇒ `route.credential_missing`。**三面同批**
49
- * (主推理链 / side-query / WebFetch 摘要走的是同一只 brain 栈),旋钮 = 给模型自己的凭据、或不声明
50
- * `config.baseUrl`(core 的 `"unpinned"` 快速起步姿态)。⇒ [ref] 要的「三面同批 + 旋钮」由上游一次交齐。
50
+ * (主推理链 / side-query / WebFetch 摘要走的是同一只 brain 栈),旋钮 = 给模型自己的凭据(当年还有第二条:不声明
51
+ * `config.baseUrl`,走 core 的 `"unpinned"` 快速起步姿态 —— core 7.51.0 #1531 起该姿态退役,一份部署凭据只配一个根)。
52
+ * ⇒ [ref] 要的「三面同批 + 旋钮」由上游一次交齐。
51
53
  *
52
54
  * 于是本席的 `isOffRouteBaseUrl` + `recordFailOpen("server.model-key.off-route-model-uses-gateway-key")`
53
55
  * 两件**一并撤线**:那条计数的语义是「这一次调用真把网关凭据发给了别家」,而在 5.57 上那次调用根本
@@ -97,21 +99,6 @@ export interface SideQueryLaneCtx {
97
99
  export declare function createPerModelAuthSeat(getKeyResolver: () => KeyResolver, opts?: {
98
100
  readonly upstream?: SideQuerySpec["getApiKeyAndHeaders"];
99
101
  }): PerModelAuthSeat;
100
- /**
101
- * per-model key 注入 brain wrapper —— **[ref] 后只服务 WebFetch 摘要面**
102
- * (`boot/webfetch-summarize-lane.ts`)。side-query 面已换到 core 的 spec 座位(见顶注「[ref] 换装」);
103
- * core 的 `WebFetchSummarizerOptions` 至今只有 `maxContentChars`(亲验 5.46.0 `dist/tools/web.d.ts`),
104
- * 那一面**没有座位可换**,只能继续在 brain 层补凭据。
105
- *
106
- * 语义(与 `createPerModelAuthSeat` 同一张表,只是注入位在 `options.apiKey`):
107
- * · `options.apiKey` **已在场** ⇒ 原样透传(上游/装饰器已经定了凭据,本层不抢);
108
- * · resolver 缺席 / 返回 undefined ⇒ 不注入 ⇒ 网关 key(additive 契约);
109
- * · resolver 抛(sealed key 中毒)⇒ **上抛**,本次调用整体失败,一个字节都不发。
110
- *
111
- * `complete` 在场时同样包一层:core 的 `Brain.complete` 是 compaction/摘要腿的直调口(WebFetch 摘要器
112
- * 正是**优先**走它),漏包等于给同一个病留第二条路。
113
- */
114
- export declare function createPerModelKeyBrain(brain: Brain, getKeyResolver: () => KeyResolver): Brain;
115
102
  /**
116
103
  * 装配 side-query 执行席 = 真 `runSideQuery` + core 的 per-model auth 座,models/roles 与 Runner 同源。
117
104
  *
@@ -8,30 +8,6 @@ export function createPerModelAuthSeat(getKeyResolver, opts = {}) {
8
8
  return resolve ? await resolve({ name: model.name }) : undefined;
9
9
  };
10
10
  }
11
- export function createPerModelKeyBrain(brain, getKeyResolver) {
12
- const seat = createPerModelAuthSeat(getKeyResolver);
13
- const keyFor = async (model, given) => {
14
- if (given !== undefined)
15
- return given;
16
- return (await seat(model))?.apiKey;
17
- };
18
- const stream = async (model, context, options) => {
19
- const apiKey = await keyFor(model, options?.apiKey);
20
- return brain.stream(model, context, apiKey === undefined ? options : { ...options, apiKey });
21
- };
22
- const complete = brain.complete?.bind(brain);
23
- return {
24
- stream,
25
- ...(complete
26
- ? {
27
- complete: async (model, context, options) => {
28
- const apiKey = await keyFor(model, options?.apiKey);
29
- return complete(model, context, apiKey === undefined ? options : { ...options, apiKey });
30
- },
31
- }
32
- : {}),
33
- };
34
- }
35
11
  export function createSideQueryLane(ctx) {
36
12
  return (spec) => runSideQuery({
37
13
  ...spec,
@@ -14,8 +14,11 @@ import { setRunTerminalLogObserver } from "../observability/run-terminal.js";
14
14
  import { setRedactionObserver } from "../trace/redact.js";
15
15
  import { installOutboundDispatcher } from "../outbound-dispatcher.js";
16
16
  import { provisionSemaConfigDir } from "../sema-config-dir.js";
17
+ import { bindOwnCredentialsConfig, declareServerWithheldEnv } from "../server-secret-env.js";
17
18
  export function runStage01() {
19
+ declareServerWithheldEnv();
18
20
  const config = loadConfig();
21
+ bindOwnCredentialsConfig(config);
19
22
  const runStaleFailure = crossInvariant("run-stale-heartbeat").check({ live: config, next: config });
20
23
  if (runStaleFailure !== undefined) {
21
24
  throw new Error(runStaleFailure);
@@ -76,7 +76,7 @@ export function runStage06(ctx) {
76
76
  onIncident: (err) => logger.warn("memory_consolidation_incident", { code: err.code ?? null, detail: err.message }),
77
77
  onStopDetail: (audit) => logger.warn("memory_consolidation_stop_detail", audit),
78
78
  ...(sessionCaptureRecordStore !== undefined ? { captureRecordStore: sessionCaptureRecordStore } : {}),
79
- writeJudge: createOperatorValveWriteJudge(),
79
+ writeJudge: createOperatorValveWriteJudge({ ruleStoreProvider: permissionRuleProvider, config }),
80
80
  onNotice: createEngineNoticeForwarder(logger, defaultEngineNoticeRouter, metrics),
81
81
  })
82
82
  : undefined;