@akagilnc/pi-workflow-roles 0.1.5941 → 0.1.5949
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/dist/acp-host/production-host.js +81 -70
- package/dist/collector-tool-schemas.js +1 -1
- package/dist/diarist-contracts.js +8 -6
- package/dist/doctor-contracts.js +1 -1
- package/dist/headless-host/production-host.js +73 -62
- package/dist/migrate-book-topology.js +22 -36
- package/dist/package-contracts/fixer-output.js +1 -1
- package/dist/package-contracts/gatekeeper-output.js +2 -2
- package/dist/package-contracts/navigator-output.js +2 -2
- package/dist/package-contracts/reviewer-output.js +1 -1
- package/dist/package-contracts/terminating-infrastructure.js +6 -23
- package/dist/public-cli/instruction-seat-run.js +2 -1
- package/dist/public-cli/main.js +74 -63
- package/dist/public-cli/run-lifecycle.js +1 -1
- package/dist/public-cli/seat-ticket-binding.js +45 -17
- package/dist/review-submission.js +1 -1
- package/package.json +1 -1
- package/src/collector-tool-schemas.ts +1 -1
- package/src/diarist-contracts.ts +10 -8
- package/src/doctor-contracts.ts +1 -1
- package/src/package-contracts/fixer-output.ts +1 -1
- package/src/package-contracts/gatekeeper-output.ts +2 -2
- package/src/package-contracts/navigator-output.ts +2 -2
- package/src/package-contracts/reviewer-output.ts +1 -1
- package/src/package-contracts/terminating-infrastructure.ts +10 -35
- package/src/public-cli/instruction-seat-run.ts +2 -1
- package/src/public-cli/run-lifecycle.ts +1 -1
- package/src/public-cli/seat-ticket-binding.ts +43 -16
- package/src/review-submission.ts +1 -1
package/src/diarist-contracts.ts
CHANGED
|
@@ -31,10 +31,10 @@ export type DiaristOutput =
|
|
|
31
31
|
readonly ticketNumber?: number | null;
|
|
32
32
|
/**
|
|
33
33
|
* Dialogue bounds: one entry per session volume, each with one or more ranges.
|
|
34
|
-
* Empty / absent = lawful empty selection (no dialogue this turn).
|
|
34
|
+
* Empty / null / absent = lawful empty selection (no dialogue this turn).
|
|
35
35
|
* Malformed endpoints → accept hook reasks (`reask-not-explode`).
|
|
36
36
|
*/
|
|
37
|
-
readonly sessions?: readonly TicketProvenanceSession[];
|
|
37
|
+
readonly sessions?: readonly TicketProvenanceSession[] | null;
|
|
38
38
|
/** Per-ticket dialogue bounds for a single multi-ticket summons (#1107). */
|
|
39
39
|
readonly ticketSessions?: readonly {
|
|
40
40
|
readonly ticketNumber: number;
|
|
@@ -65,13 +65,13 @@ export function validateRecordedDiaristOutput(value: unknown): DiaristOutput {
|
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Project sessions from a completed diarist payload.
|
|
68
|
-
*
|
|
68
|
+
* Null / absent key → empty (lawful). Non-null but unusable → undefined (caller reasks).
|
|
69
69
|
*/
|
|
70
70
|
export function projectDiaristSessions(
|
|
71
71
|
value: unknown,
|
|
72
72
|
): readonly TicketProvenanceSession[] | undefined {
|
|
73
73
|
const raw = (value as { sessions?: unknown } | null)?.sessions;
|
|
74
|
-
if (raw
|
|
74
|
+
if (raw == null) return [];
|
|
75
75
|
return projectTicketProvenanceSessions(raw);
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -115,15 +115,17 @@ export const diaristOutputSchema = withTerminatingOutputDeclarations(
|
|
|
115
115
|
ticketNumber: Type.Optional(
|
|
116
116
|
Type.Unknown({
|
|
117
117
|
description:
|
|
118
|
-
"
|
|
118
|
+
"仅有本庭对象时填票号(正整数);没有就填 null=真无票;下游走 typed 键;认不出用 status=escalate,不洗成无录。机械层不重判。",
|
|
119
119
|
}),
|
|
120
120
|
),
|
|
121
121
|
reason: Type.Unknown({
|
|
122
|
-
description: "status 为 escalate
|
|
122
|
+
description: "仅 status 为 escalate 时填上呈的原因;没有就填 null",
|
|
123
123
|
}),
|
|
124
|
-
sessions: Type.Optional(Type.Unknown({
|
|
124
|
+
sessions: Type.Optional(Type.Unknown({
|
|
125
|
+
description: `仅单票庭时填对话边界;没有就填 null。${DIARIST_SESSIONS_DESCRIPTION}`,
|
|
126
|
+
})),
|
|
125
127
|
ticketSessions: Type.Unknown({
|
|
126
|
-
description:
|
|
128
|
+
description: `仅多票庭时填逐票对话边界;没有就填 null。每票含 ticketNumber(本条边界所归票号,正整数)与 sessions(${DIARIST_SESSIONS_DESCRIPTION})。一次交卷各票各自分录。`,
|
|
127
129
|
}),
|
|
128
130
|
}),
|
|
129
131
|
),
|
package/src/doctor-contracts.ts
CHANGED
|
@@ -72,7 +72,7 @@ const doctorSubmissionObject = Type.Object({
|
|
|
72
72
|
`逐条资产观察与处方,原样留存。一条可含 targetKey、targetKind(${DOCTOR_TARGET_KINDS.join(" | ")})、observation、evidenceIds、disposition(${DOCTOR_DISPOSITIONS.join(" | ")})、assetEvidence(targetKey、targetKind、evidenceId)、guardrails(reproducibleFailure、owningSeamOrInvariant、deletionOrSimplificationSuffices,各项可含 answer、evidenceIds、explanation)、prescription(kind 为 ${DOCTOR_PRESCRIPTION_KINDS.join(" | ")},另可写 recommendation、necessityExplanation)、lastRealBite(kind 为 ${DOCTOR_BITE_KINDS.join(" | ")},另可写 targetKey、evidenceId、eligibleEvidenceIds)。不要求任何处方或可复用 finding;缺可复用资产或 bounded-bite 证据只排除对应资产处方。机器不核验。`,
|
|
73
73
|
}),
|
|
74
74
|
reason: Type.Unknown({
|
|
75
|
-
description: "
|
|
75
|
+
description: "仅 refused 时填证据不足以支撑如实证词的原因;没有就填 null",
|
|
76
76
|
}),
|
|
77
77
|
missingEvidence: Type.Unknown({
|
|
78
78
|
description: "如实证词所需而尚缺的证据,原样留存(如每项 need、targetKeys)。",
|
|
@@ -34,7 +34,7 @@ const fixerOutputObject = Type.Object({
|
|
|
34
34
|
diffItems: diffItemsField,
|
|
35
35
|
testEvidence: Type.Unknown({
|
|
36
36
|
description:
|
|
37
|
-
"
|
|
37
|
+
"仅 diff 含测试改动时填测试证据条;没有就填 null。机器不核验。可写 contract(测试改动所证明的契约)、minimumNecessaryCost(测试改动的一行最小必要成本)、measuredDuration(聚焦验证实测时长)。",
|
|
38
38
|
}),
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -19,10 +19,10 @@ export const gatekeeperDecisionSchema = openToolObject(
|
|
|
19
19
|
description: "dispatch | pass",
|
|
20
20
|
}),
|
|
21
21
|
officer: Type.Unknown({
|
|
22
|
-
description: "status 为 dispatch
|
|
22
|
+
description: "仅 status 为 dispatch 时填 inspector | notary;没有就填 null",
|
|
23
23
|
}),
|
|
24
24
|
findings: Type.Unknown({
|
|
25
|
-
description: "status 为 pass
|
|
25
|
+
description: "仅 status 为 pass 时填 string[] findings;没有就填 null",
|
|
26
26
|
}),
|
|
27
27
|
}),
|
|
28
28
|
);
|
|
@@ -19,7 +19,7 @@ export const NAVIGATOR_OUTPUT_TOOL_NAME = "ak_navigator_output";
|
|
|
19
19
|
*/
|
|
20
20
|
export const navigatorAdviceFields = {
|
|
21
21
|
prose: Type.Unknown({
|
|
22
|
-
description: "
|
|
22
|
+
description: "仅无状态分叉时填单条散文建议;没有就填 null。原样呈现。",
|
|
23
23
|
}),
|
|
24
24
|
byStatus: Type.Unknown({
|
|
25
25
|
description:
|
|
@@ -28,7 +28,7 @@ export const navigatorAdviceFields = {
|
|
|
28
28
|
}),
|
|
29
29
|
byRole: Type.Unknown({
|
|
30
30
|
description:
|
|
31
|
-
"
|
|
31
|
+
"仅直接入口不给角色时填整张路线表(键为衙门角色,值为该衙门 status → 建议);没有就填 null",
|
|
32
32
|
}),
|
|
33
33
|
} as const;
|
|
34
34
|
|
|
@@ -8,7 +8,7 @@ import { withTerminatingOutputDeclarations } from "./terminating-infrastructure.
|
|
|
8
8
|
export const REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
|
|
9
9
|
|
|
10
10
|
const REVIEWER_AMENDMENTS_DESCRIPTION =
|
|
11
|
-
"已运行 lens 的 amendments 承载 candidates、逐条处置与 verdict 的完整报告(非仅 verdict
|
|
11
|
+
"已运行 lens 的 amendments 承载 candidates、逐条处置与 verdict 的完整报告(非仅 verdict 行);各轴(completeness / correctness)仅有已产出报告时填报告;没有就填 null。hard-stop/usage error 为 refused 时,已产出报告仍照录对应 lens 字段。" as const;
|
|
12
12
|
// #1134: `status` alone is the trajectory field (#917 §6 two normal lens verdicts →
|
|
13
13
|
// completed; hard-stop / usage error → refused); its words ride the description.
|
|
14
14
|
// amendments/diagnostic are LLM/human-read narrative content returned as
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Package-owned shared infrastructure-failure declaration for every primary
|
|
3
3
|
* packaged-role output tool (#541 / #1214 A2).
|
|
4
4
|
*
|
|
5
|
-
* One module owns the
|
|
6
|
-
*
|
|
5
|
+
* One module owns the infrastructureFailure declaration composed into each
|
|
6
|
+
* output tool's schema. Name and semantic description only — no object type, so
|
|
7
|
+
* a null fill is not a shape rejection (#1134). The field is part of the role's
|
|
7
8
|
* original receipt: ledger records it as-is. Declaration alone does not abort
|
|
8
9
|
* the host (#1214 A2). True host/lifecycle failure still fails honestly on its
|
|
9
10
|
* own channel.
|
|
@@ -12,34 +13,11 @@ import { Type, type TSchema } from "typebox";
|
|
|
12
13
|
|
|
13
14
|
export const INFRASTRUCTURE_FAILURE_DECLARATION_KEY =
|
|
14
15
|
"infrastructureFailure" as const;
|
|
15
|
-
export const INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY = "diagnostic" as const;
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* the declaration fragment.
|
|
22
|
-
*/
|
|
23
|
-
const infrastructureFailureNested = Type.Object(
|
|
24
|
-
{
|
|
25
|
-
[INFRASTRUCTURE_FAILURE_DIAGNOSTIC_KEY]: Type.Unknown({
|
|
26
|
-
description: "基础设施失败诊断字符串。",
|
|
27
|
-
}),
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
additionalProperties: true,
|
|
31
|
-
description: "仅基础设施真实失败时出现。",
|
|
32
|
-
},
|
|
33
|
-
);
|
|
34
|
-
// Open nested required so host cannot pure-shape-reject the declaration fragment.
|
|
35
|
-
(infrastructureFailureNested as unknown as { required: string[] }).required = [];
|
|
36
|
-
|
|
37
|
-
const infrastructureFailureDeclarationSchema = Type.Object(
|
|
38
|
-
{
|
|
39
|
-
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: infrastructureFailureNested,
|
|
40
|
-
},
|
|
41
|
-
{ additionalProperties: true },
|
|
42
|
-
);
|
|
17
|
+
/** Name + semantic description. diagnostic's meaning lives in the description. */
|
|
18
|
+
const infrastructureFailureField = Type.Unknown({
|
|
19
|
+
description: "仅基础设施真实失败时填 {diagnostic};没有就填 null",
|
|
20
|
+
});
|
|
43
21
|
|
|
44
22
|
/**
|
|
45
23
|
* Compose declarations shared by terminating output tools: infrastructure failure,
|
|
@@ -62,7 +40,7 @@ export function withTerminatingOutputDeclarations<
|
|
|
62
40
|
? {
|
|
63
41
|
ticketNumber: Type.Unknown({
|
|
64
42
|
description:
|
|
65
|
-
"
|
|
43
|
+
"仅尚未绑定时填本票号(正整数、数字串或前导 #N;归位只读本字段);没有就填 null",
|
|
66
44
|
}),
|
|
67
45
|
}
|
|
68
46
|
: {}
|
|
@@ -72,15 +50,12 @@ export function withTerminatingOutputDeclarations<
|
|
|
72
50
|
? {
|
|
73
51
|
summary: Type.Unknown({
|
|
74
52
|
description:
|
|
75
|
-
"
|
|
53
|
+
"仅本席有结论时填一两句、20–50 字结论摘要;没有就填 null。不因缺失或超长拒收、截断或代填。",
|
|
76
54
|
}),
|
|
77
55
|
}
|
|
78
56
|
: {}
|
|
79
57
|
),
|
|
80
|
-
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]:
|
|
81
|
-
infrastructureFailureDeclarationSchema.properties[
|
|
82
|
-
INFRASTRUCTURE_FAILURE_DECLARATION_KEY
|
|
83
|
-
],
|
|
58
|
+
[INFRASTRUCTURE_FAILURE_DECLARATION_KEY]: infrastructureFailureField,
|
|
84
59
|
};
|
|
85
60
|
const object = Type.Object(properties, { additionalProperties: true });
|
|
86
61
|
const incoming = (schema as { required?: unknown }).required;
|
|
@@ -973,7 +973,8 @@ async function runOmittedLensBatch(
|
|
|
973
973
|
|
|
974
974
|
/**
|
|
975
975
|
* One same-parent lookup. Seat branches still build their own summons.
|
|
976
|
-
* A found child resumes that child
|
|
976
|
+
* A found child resumes that child. No prior run, explicit new, or a typed
|
|
977
|
+
* session-id-missing resume (失败照记,记完再起新) returns undefined so the caller mints.
|
|
977
978
|
*/
|
|
978
979
|
function resumeSameParentInstructionSeat(input: {
|
|
979
980
|
readonly env: InstructionSeatRunEnv;
|
|
@@ -130,7 +130,7 @@ export type SameTicketSummonsMaterials = {
|
|
|
130
130
|
readonly sourceRun?: NotarySourceRunLocator;
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
const WRITER_LOCK_FILE = "writer.lock";
|
|
133
|
+
export const WRITER_LOCK_FILE = "writer.lock";
|
|
134
134
|
|
|
135
135
|
export async function writeRoleRunState(
|
|
136
136
|
runDirectory: string,
|
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987).
|
|
3
|
-
*
|
|
4
|
-
* Lookup uses the parent run path; a typed ticket narrows same-ticket gate
|
|
5
|
-
* re-summons, never creates an issue identity. Callers can also use explicit
|
|
6
|
-
* `ak-role resume <runId>`. Lookup/resume failures propagate (失败诚实) — never wash into
|
|
7
|
-
* a fresh mint. Returns undefined when the caller declared an explicit fresh
|
|
8
|
-
* summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
9
|
-
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
2
|
+
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987 / #1253).
|
|
3
|
+
* Contract is on tryResumeSameTicketSeatRun.
|
|
10
4
|
*/
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
11
7
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.ts";
|
|
12
8
|
import {
|
|
9
|
+
autopsyWriterLock,
|
|
13
10
|
findLatestRunForSeatTicket,
|
|
11
|
+
resolveLiveRunDirectoryPath,
|
|
12
|
+
WRITER_LOCK_FILE,
|
|
14
13
|
type RoleRunRecord,
|
|
15
14
|
type SameTicketSummonsMaterials,
|
|
16
15
|
} from "./run-lifecycle.ts";
|
|
17
16
|
|
|
17
|
+
const SESSION_ID_MISSING = "session-id-missing";
|
|
18
|
+
|
|
19
|
+
function resumedSessionIdMissing(result: unknown, runId: string): boolean {
|
|
20
|
+
if (typeof result !== "object" || result === null) return false;
|
|
21
|
+
const terminal = (result as { terminal?: unknown }).terminal;
|
|
22
|
+
if (typeof terminal !== "object" || terminal === null) return false;
|
|
23
|
+
if ((terminal as { runId?: unknown }).runId !== runId) return false;
|
|
24
|
+
const outcome = (terminal as { roleOutcome?: unknown }).roleOutcome;
|
|
25
|
+
if (typeof outcome !== "object" || outcome === null) return false;
|
|
26
|
+
if ((outcome as { kind?: unknown }).kind !== "failure") return false;
|
|
27
|
+
const facts = (outcome as { decisiveFacts?: unknown }).decisiveFacts;
|
|
28
|
+
if (typeof facts !== "object" || facts === null) return false;
|
|
29
|
+
return (facts as { errorCode?: unknown }).errorCode === SESSION_ID_MISSING;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Live or unverifiable holder: same fail-closed verdict as lease acquire. */
|
|
33
|
+
async function writerLockBlocksFreshSummons(runDirectory: string): Promise<boolean> {
|
|
34
|
+
const autopsy = await autopsyWriterLock(join(runDirectory, WRITER_LOCK_FILE));
|
|
35
|
+
return autopsy.verdict === "alive" || autopsy.verdict === "unknown";
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
/**
|
|
19
|
-
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987).
|
|
39
|
+
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987 / #1253).
|
|
20
40
|
* A supplied typed ticket only narrows the prior-run search. When a prior run is
|
|
21
41
|
* found, resume carries this summons' materials and the located runDirectory so
|
|
22
|
-
* load does not re-walk every book for the bare runId (#1195).
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
42
|
+
* load does not re-walk every book for the bare runId (#1195). Typed
|
|
43
|
+
* session-id-missing is already recorded on that run (失败照记,记完再起新);
|
|
44
|
+
* return undefined so the caller mints once. Resume runs first; this seam does
|
|
45
|
+
* not look up a session id. A held or unverifiable writer lock, and every other
|
|
46
|
+
* result, returns as-is. Also returns undefined for explicit `ak-role new`, a
|
|
47
|
+
* blank parent path, or no prior run. freshSummons is required so no seat can
|
|
48
|
+
* drift back into its own skip branch.
|
|
27
49
|
*/
|
|
28
50
|
export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
29
51
|
readonly home: string;
|
|
@@ -41,13 +63,18 @@ export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
|
41
63
|
}): Promise<T | undefined> {
|
|
42
64
|
if (input.freshSummons === true) return undefined;
|
|
43
65
|
if (input.parentRunPath.trim() === "") return undefined;
|
|
66
|
+
const bookKey = resolveBookKeyFromGit(input.projectRoot);
|
|
44
67
|
const previous = await findLatestRunForSeatTicket({
|
|
45
68
|
home: input.home,
|
|
46
|
-
bookKey
|
|
69
|
+
bookKey,
|
|
47
70
|
role: input.role,
|
|
48
71
|
parentRunPath: input.parentRunPath,
|
|
49
72
|
...(input.ticketNumber === undefined ? {} : { ticketNumber: input.ticketNumber }),
|
|
50
73
|
});
|
|
51
74
|
if (previous === undefined) return undefined;
|
|
52
|
-
|
|
75
|
+
const resumed = await input.resume(previous.runId, input.summons, previous.runDirectory);
|
|
76
|
+
if (!resumedSessionIdMissing(resumed, previous.runId)) return resumed;
|
|
77
|
+
const live = await resolveLiveRunDirectoryPath(previous.runDirectory, input.home, bookKey);
|
|
78
|
+
if (live !== undefined && await writerLockBlocksFreshSummons(live)) return resumed;
|
|
79
|
+
return undefined;
|
|
53
80
|
}
|
package/src/review-submission.ts
CHANGED
|
@@ -27,7 +27,7 @@ const reviewNarrativeFields = {
|
|
|
27
27
|
reason: Type.Optional(Type.Unknown({ description: "上呈理由" })),
|
|
28
28
|
violations: Type.Optional(Type.Unknown({ description: "违规条目" })),
|
|
29
29
|
conflicts: Type.Optional(Type.Unknown({ description: "待决冲突" })),
|
|
30
|
-
fix: Type.Optional(Type.Unknown({ description: "continue
|
|
30
|
+
fix: Type.Optional(Type.Unknown({ description: "仅 continue 时填补救说明(可写 summary 摘要,其余内容原样留存);没有就填 null" })),
|
|
31
31
|
classes: Type.Optional(Type.Unknown({ description: "已裁决 finding 类;可说明 name、owner、boundary、disposition,原样留存" })),
|
|
32
32
|
note: Type.Optional(Type.Unknown({ description: "裁决附注" })),
|
|
33
33
|
evidence: Type.Optional(Type.Unknown({ description: "留存证据" })),
|