@akagilnc/pi-workflow-roles 0.1.5357 → 0.1.5365

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.
@@ -1,6 +1,6 @@
1
1
  import type { RoleHost, HostContext, HostToolResult, HostGatekeeperActions } from "./host-contracts.ts";
2
2
  import { Type, type Static } from "typebox";
3
- import { openToolObjectFromUnion } from "./open-tool-schema.ts";
3
+ import { openToolObject } from "./open-tool-schema.ts";
4
4
  import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
5
5
 
6
6
  import {
@@ -36,37 +36,22 @@ export {
36
36
  };
37
37
  export type { WorkerOutput };
38
38
 
39
- // #836 r16 class 1: report/remainingScope are LLM/human-read narrative content —
40
- // no code branches on their length. `reason` alone keeps minLength: the worker
41
- // gate reads `reason.trim().length > 0` to pick typed-reminder-bounce vs accept
42
- // (src/worker-submission-gates.ts:159-163,297-302).
43
- // Worker status is not the review three-state field (#1055): schema stays open.
44
- // One shared description across every variant
45
- // so openToolObjectFromUnion's identical-declaration collapse drops none of it.
39
+ // status 的合法词写在 description。WORKER_DONE_STATUSES 只让 completed /
40
+ // partially_completed 进入提交闸。unfinished 且未见理由说明时,运行时同 run 催全
41
+ // (ADR 0050);理由在不在不按 JSON 类型判,也不在派发前用长度拒收。
42
+ // report / remainingScope / reason 的声明只留字段名和语义。
46
43
  const CODER_STATUS_DESCRIPTION =
47
44
  `planned | completed | refused | partially_completed | unfinished。unfinished:缺前置或违宪约束致本局未完成。${PARTIALLY_COMPLETED_DEFINITION}` as const;
48
- const coderOutputVariants = Type.Union([
49
- Type.Object({
50
- status: Type.Unknown({ description: CODER_STATUS_DESCRIPTION }),
51
- report: Type.String({ description: "如实结果报告" }),
52
- }, { additionalProperties: false }),
53
- Type.Object({
54
- status: Type.Unknown({ description: CODER_STATUS_DESCRIPTION }),
55
- report: Type.String({ description: "如实结果报告" }),
56
- }, { additionalProperties: false }),
57
- Type.Object({
58
- status: Type.Unknown({ description: CODER_STATUS_DESCRIPTION }),
59
- report: Type.String({ description: "如实结果报告" }),
60
- remainingScope: Type.String({ description: "本局后剩余工作" }),
61
- reason: Type.Optional(Type.String({
62
- minLength: 1,
63
- description:
64
- "阻断原因:缺前置或违宪约束。缺待决 owner 决定或答复属缺前置。",
65
- })),
66
- }, { additionalProperties: false }),
67
- ]);
45
+ const coderOutputObject = Type.Object({
46
+ status: Type.Unknown({ description: CODER_STATUS_DESCRIPTION }),
47
+ report: Type.Unknown({ description: "如实结果报告" }),
48
+ remainingScope: Type.Unknown({ description: "本局后剩余工作" }),
49
+ reason: Type.Unknown({
50
+ description: "阻断原因:缺前置或违宪约束。缺待决 owner 决定或答复属缺前置。",
51
+ }),
52
+ });
68
53
  export const coderOutputSchema = withTerminatingOutputDeclarations(
69
- openToolObjectFromUnion(coderOutputVariants),
54
+ openToolObject(coderOutputObject),
70
55
  );
71
56
  export type { FixerOutput, CoderOutput };
72
57
  export const FIXER_FLAG_DEFINITIONS = {
@@ -156,10 +156,21 @@ function isRecord(value: unknown): value is Record<string, unknown> {
156
156
  return typeof value === "object" && value !== null && !Array.isArray(value);
157
157
  }
158
158
 
159
+ /** ADR 0050: a written explanation, including text carried by an object key. */
160
+ function containsWrittenReason(value: unknown): boolean {
161
+ if (typeof value === "string") return value.trim().length > 0;
162
+ if (Array.isArray(value)) return value.some(containsWrittenReason);
163
+ if (typeof value === "object" && value !== null) {
164
+ return Object.entries(value).some(
165
+ ([key, item]) => containsWrittenReason(key) || containsWrittenReason(item),
166
+ );
167
+ }
168
+ return false;
169
+ }
170
+
159
171
  function unfinishedReasonPresent(details?: unknown): boolean {
160
- if (typeof details !== "object" || details === null) return false;
161
- const reason = (details as { reason?: unknown }).reason;
162
- return typeof reason === "string" && reason.trim().length > 0;
172
+ if (typeof details !== "object" || details === null || Array.isArray(details)) return false;
173
+ return containsWrittenReason((details as { reason?: unknown }).reason);
163
174
  }
164
175
 
165
176
  function readGateState(session: HostRecordSession): {