@akagilnc/pi-workflow-roles 0.1.3652 → 0.1.3661
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/README.md +0 -2
- package/dist/acp-host/production-host.js +1056 -1236
- package/dist/public-cli/case-dossier-delivery.js +43 -0
- package/dist/public-cli/inspector-run.js +9 -6
- package/dist/public-cli/instruction-seat-run.js +24 -24
- package/dist/public-cli/invocation.js +2 -24
- package/dist/public-cli/main.js +1876 -2159
- package/dist/public-cli/post-admission.js +38 -12
- package/dist/public-cli/run-lifecycle.js +25 -14
- package/dist/public-cli/seat-ticket-binding.js +93 -70
- package/package.json +1 -1
- package/src/public-cli/case-dossier-delivery.ts +51 -0
- package/src/public-cli/countersign-run.ts +14 -17
- package/src/public-cli/diarist-run.ts +11 -13
- package/src/public-cli/inspector-run.ts +9 -10
- package/src/public-cli/instruction-seat-run.ts +28 -35
- package/src/public-cli/invocation.ts +4 -46
- package/src/public-cli/post-admission.ts +41 -6
- package/src/public-cli/run-lifecycle.ts +29 -21
- package/src/public-cli/seat-ticket-binding.ts +108 -104
- package/dist/diarist-ticket-resolution.js +0 -177
- package/resources/diarist-resolve-ticket.md +0 -39
- package/src/diarist-ticket-resolution.ts +0 -302
|
@@ -12,6 +12,14 @@ import { buildResumeContinuationPrompt, RESUME_TRANSPORT_ENVELOPE, } from "./run
|
|
|
12
12
|
import { CliUsageError } from "./cli-errors.js";
|
|
13
13
|
import { buildInstructionTransportPrompt, freezeAttachmentsIntoRun, } from "./invocation.js";
|
|
14
14
|
import { pathContainedIn } from "../activation-ledger-topology.js";
|
|
15
|
+
import { projectCaseDossierPointerSection } from "./case-dossier-delivery.js";
|
|
16
|
+
/** Append one system section to a continuation prompt, keeping its kind. */
|
|
17
|
+
function appendContinuationSection(continuation, section) {
|
|
18
|
+
const prompt = `${continuation.prompt}\n\n${section}`;
|
|
19
|
+
return continuation.kind === "initial"
|
|
20
|
+
? { kind: "initial", prompt }
|
|
21
|
+
: { kind: "resume", prompt };
|
|
22
|
+
}
|
|
15
23
|
import { projectHostTransitionPriorNative } from "../host-transition-prior-native.js";
|
|
16
24
|
import { missingCredentialPreDispatchFailure, postRunMissingCredentialFailure, } from "./public-run-credentials.js";
|
|
17
25
|
import { acquireRunWriterLease, clearCurrentCourt, clearTypedProviderHttpObservation, markRunResumable, markRunRunning, markRunTerminal, readCurrentCourt, recordCurrentCourt, renderResumeCommand, RunWriterLeaseHeldError, } from "./run-lifecycle.js";
|
|
@@ -115,20 +123,17 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
115
123
|
const principalCoordinates = admitted.principal === undefined
|
|
116
124
|
? undefined
|
|
117
125
|
: env.principalAuthority.decode(admitted.principal);
|
|
118
|
-
let
|
|
126
|
+
let hostTransition;
|
|
119
127
|
try {
|
|
120
128
|
previousHost = await readInvocationHost(admitted.runDirectory);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (hostTransition !== undefined) {
|
|
130
|
-
turnRequest = { ...turnRequest, hostTransition };
|
|
131
|
-
}
|
|
129
|
+
hostTransition =
|
|
130
|
+
previousHost !== undefined && liveHost !== undefined && principalCoordinates !== undefined
|
|
131
|
+
? await projectHostTransitionPriorNative({
|
|
132
|
+
previousHost,
|
|
133
|
+
liveHost,
|
|
134
|
+
piSessionFile: principalCoordinates.sessionFile,
|
|
135
|
+
})
|
|
136
|
+
: undefined;
|
|
132
137
|
}
|
|
133
138
|
catch (error) {
|
|
134
139
|
// prior-native IO is on the public one-shot path — controlled failure, not bare throw.
|
|
@@ -156,6 +161,27 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
156
161
|
}, adapters, env.principalAuthority, io));
|
|
157
162
|
}
|
|
158
163
|
}
|
|
164
|
+
// Turn request is assembled after beforeDispatch so this turn sees whatever it
|
|
165
|
+
// settled — the seat's ticket bind re-projection. Case dossier delivery
|
|
166
|
+
// (ADR 0081) rides here for every public entry: first call, same-ticket
|
|
167
|
+
// re-summons and manual resume alike. System refs append their own neutral
|
|
168
|
+
// section; caller frozen attachments and the seat's own prompt bytes are
|
|
169
|
+
// never rewritten.
|
|
170
|
+
let turnRequest = env.signal === undefined ? request : { ...request, signal: env.signal };
|
|
171
|
+
if (hostTransition !== undefined) {
|
|
172
|
+
turnRequest = { ...turnRequest, hostTransition };
|
|
173
|
+
}
|
|
174
|
+
const dossierSection = await projectCaseDossierPointerSection({
|
|
175
|
+
ticketNumber: admitted.ticketNumber,
|
|
176
|
+
projectRoot: admitted.projectRoot,
|
|
177
|
+
home: env.home,
|
|
178
|
+
});
|
|
179
|
+
if (dossierSection !== undefined) {
|
|
180
|
+
turnRequest = {
|
|
181
|
+
...turnRequest,
|
|
182
|
+
continuation: appendContinuationSection(turnRequest.continuation, dossierSection),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
159
185
|
let result;
|
|
160
186
|
try {
|
|
161
187
|
result = await env.roleTurnHost.executeTurn(turnRequest);
|
|
@@ -819,6 +819,30 @@ export async function findLatestRunIdForSeatTicket(input) {
|
|
|
819
819
|
}
|
|
820
820
|
return best;
|
|
821
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Ticket identities this book's retained runs already record (#709).
|
|
824
|
+
* Read-only reuse surface for seat ticket binding — no ticket number is minted here.
|
|
825
|
+
*/
|
|
826
|
+
export async function collectBookRunTicketNumbers(input) {
|
|
827
|
+
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
828
|
+
const runsDir = join(activationBookDirectory(ledgerHome, input.bookKey), "runs");
|
|
829
|
+
let entries;
|
|
830
|
+
try {
|
|
831
|
+
entries = await readdir(runsDir);
|
|
832
|
+
}
|
|
833
|
+
catch (error) {
|
|
834
|
+
if (errorCodeOf(error) === "ENOENT")
|
|
835
|
+
return new Set();
|
|
836
|
+
throw error;
|
|
837
|
+
}
|
|
838
|
+
const known = new Set();
|
|
839
|
+
for (const entry of entries) {
|
|
840
|
+
const ticketNumber = await readRunTicketNumber(join(runsDir, entry));
|
|
841
|
+
if (ticketNumber !== undefined)
|
|
842
|
+
known.add(ticketNumber);
|
|
843
|
+
}
|
|
844
|
+
return known;
|
|
845
|
+
}
|
|
822
846
|
/** Restore optional correlation + typed ticket identity from a durable admitted page. */
|
|
823
847
|
function parsePersistedTicketIdentity(record) {
|
|
824
848
|
const correlationId = typeof record.correlationId === "string" && record.correlationId.trim() !== ""
|
|
@@ -829,20 +853,15 @@ function parsePersistedTicketIdentity(record) {
|
|
|
829
853
|
record.ticketNumber >= 1
|
|
830
854
|
? record.ticketNumber
|
|
831
855
|
: undefined;
|
|
832
|
-
const ticketResolution = record.ticketResolution === "true-unbound" ? "true-unbound" : undefined;
|
|
833
856
|
return {
|
|
834
857
|
...(correlationId === undefined ? {} : { correlationId }),
|
|
835
858
|
...(ticketNumber === undefined ? {} : { ticketNumber }),
|
|
836
|
-
...(ticketResolution === undefined ? {} : { ticketResolution }),
|
|
837
859
|
};
|
|
838
860
|
}
|
|
839
861
|
function restoredTicketFields(fields) {
|
|
840
862
|
return {
|
|
841
863
|
...(fields.correlationId === undefined ? {} : { correlationId: fields.correlationId }),
|
|
842
864
|
...(fields.ticketNumber === undefined ? {} : { ticketNumber: fields.ticketNumber }),
|
|
843
|
-
...(fields.ticketResolution === undefined
|
|
844
|
-
? {}
|
|
845
|
-
: { ticketResolution: fields.ticketResolution }),
|
|
846
865
|
};
|
|
847
866
|
}
|
|
848
867
|
async function loadResumableRunRecord(home, runId, authority) {
|
|
@@ -880,7 +899,6 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
880
899
|
let derived;
|
|
881
900
|
let correlationId;
|
|
882
901
|
let ticketNumber;
|
|
883
|
-
let ticketResolution;
|
|
884
902
|
let prNumber;
|
|
885
903
|
let repository;
|
|
886
904
|
let repositoryDisplay;
|
|
@@ -1016,7 +1034,6 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
1016
1034
|
const fromAdmitted = parsePersistedTicketIdentity(record);
|
|
1017
1035
|
correlationId = fromAdmitted.correlationId;
|
|
1018
1036
|
ticketNumber = fromAdmitted.ticketNumber;
|
|
1019
|
-
ticketResolution = fromAdmitted.ticketResolution;
|
|
1020
1037
|
}
|
|
1021
1038
|
}
|
|
1022
1039
|
catch (error) {
|
|
@@ -1041,17 +1058,12 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
1041
1058
|
: {}),
|
|
1042
1059
|
};
|
|
1043
1060
|
}
|
|
1044
|
-
if (correlationId === undefined ||
|
|
1045
|
-
ticketNumber === undefined ||
|
|
1046
|
-
ticketResolution === undefined) {
|
|
1061
|
+
if (correlationId === undefined || ticketNumber === undefined) {
|
|
1047
1062
|
const fromInvocation = parsePersistedTicketIdentity(rec);
|
|
1048
1063
|
if (correlationId === undefined)
|
|
1049
1064
|
correlationId = fromInvocation.correlationId;
|
|
1050
1065
|
if (ticketNumber === undefined)
|
|
1051
1066
|
ticketNumber = fromInvocation.ticketNumber;
|
|
1052
|
-
if (ticketResolution === undefined) {
|
|
1053
|
-
ticketResolution = fromInvocation.ticketResolution;
|
|
1054
|
-
}
|
|
1055
1067
|
}
|
|
1056
1068
|
}
|
|
1057
1069
|
}
|
|
@@ -1081,7 +1093,6 @@ async function loadResumableRunRecord(home, runId, authority) {
|
|
|
1081
1093
|
...(derived === undefined ? {} : { derived }),
|
|
1082
1094
|
...(correlationId === undefined ? {} : { correlationId }),
|
|
1083
1095
|
...(ticketNumber === undefined ? {} : { ticketNumber }),
|
|
1084
|
-
...(ticketResolution === undefined ? {} : { ticketResolution }),
|
|
1085
1096
|
...(prNumber === undefined ? {} : { prNumber }),
|
|
1086
1097
|
...(repository === undefined ? {} : { repository }),
|
|
1087
1098
|
...(repositoryDisplay === undefined ? {} : { repositoryDisplay }),
|
|
@@ -1,94 +1,117 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared
|
|
3
|
-
* One path: unbound admission →
|
|
2
|
+
* Shared ticket identity seam for public court seats (#635 / #637 / #709 / #747).
|
|
3
|
+
* One path: unbound admission → reuse a ticket number this book already records
|
|
4
|
+
* (retained run pages + 起居录 volumes) → bindAdmittedTicketNumber.
|
|
5
|
+
* ADR 0081 `reuse-case-ticket-without-extra-llm`: no seat-side model call, no
|
|
6
|
+
* second ticket-number source of truth, no minting a number from human titles.
|
|
7
|
+
* Nothing matched is not 真无票 — the run simply stays unbound, which is lawful.
|
|
4
8
|
* No CLI --ticket and no attachment frontmatter binding.
|
|
5
|
-
* #
|
|
9
|
+
* #747: officer same-parent resume also lives here (shared seam).
|
|
6
10
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { bindAdmittedTicketNumber,
|
|
11
|
-
import { findLatestRunIdForSeatTicket, } from "./run-lifecycle.js";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { ActivationGitRepositoryRequiredError, resolveBookKeyFromGit, } from "../activation-ledger-git.js";
|
|
13
|
+
import { resolveTicketProvenanceVolume } from "../ticket-provenance.js";
|
|
14
|
+
import { bindAdmittedTicketNumber, } from "./invocation.js";
|
|
15
|
+
import { collectBookRunTicketNumbers, findLatestRunIdForSeatTicket, } from "./run-lifecycle.js";
|
|
12
16
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
17
|
+
* Complete decimal ticket tokens in an instruction.
|
|
18
|
+
* A digit run is one token: `82` inside `#582` is not 82, and a leading zero
|
|
19
|
+
* makes the run a different literal than the ticket number it would parse to.
|
|
16
20
|
*/
|
|
17
|
-
export
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
checkExistence,
|
|
29
|
-
});
|
|
21
|
+
export function instructionTicketTokens(instruction) {
|
|
22
|
+
const tokens = new Set();
|
|
23
|
+
for (const run of instruction.match(/\d+/g) ?? []) {
|
|
24
|
+
if (run.startsWith("0"))
|
|
25
|
+
continue;
|
|
26
|
+
const parsed = Number(run);
|
|
27
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1)
|
|
28
|
+
continue;
|
|
29
|
+
tokens.add(parsed);
|
|
30
|
+
}
|
|
31
|
+
return [...tokens];
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
* Ticket identity this summons reuses, or undefined when none is unambiguous.
|
|
35
|
+
* Known identities come only from records this book already holds: 起居录 volume
|
|
36
|
+
* partitions and ticket numbers on retained run pages. Zero or several known
|
|
37
|
+
* tokens in the instruction leave the run unbound — never guess, never fail.
|
|
34
38
|
*/
|
|
35
|
-
export async function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
export async function resolveKnownTicketNumber(input) {
|
|
40
|
+
const tokens = instructionTicketTokens(input.instruction);
|
|
41
|
+
if (tokens.length === 0)
|
|
42
|
+
return undefined;
|
|
43
|
+
const known = [];
|
|
44
|
+
let runTickets;
|
|
45
|
+
for (const token of tokens) {
|
|
46
|
+
const volume = resolveTicketProvenanceVolume(token, input.projectRoot, input.home);
|
|
47
|
+
if (existsSync(volume.volumeDir)) {
|
|
48
|
+
known.push(token);
|
|
49
|
+
continue;
|
|
43
50
|
}
|
|
44
|
-
|
|
51
|
+
if (runTickets === undefined) {
|
|
52
|
+
runTickets = await readBookRunTickets(input);
|
|
53
|
+
}
|
|
54
|
+
if (runTickets.has(token))
|
|
55
|
+
known.push(token);
|
|
45
56
|
}
|
|
57
|
+
return known.length === 1 ? known[0] : undefined;
|
|
46
58
|
}
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Diarist first-summons identity (ADR 0081 `initial-court-ticket-supplied`).
|
|
61
|
+
* Prefer a book-known reuse; when the book has no record yet, the sole complete
|
|
62
|
+
* decimal token in the caller's dispatch is the supplied ticket — the working
|
|
63
|
+
* 起居郎 round establishes the volume. Several tokens or none stay unbound.
|
|
64
|
+
* Not a second ticket-number source of truth and not an extra recognizer call.
|
|
65
|
+
*/
|
|
66
|
+
export async function resolveDiaristSummonsTicketNumber(input) {
|
|
67
|
+
const known = await resolveKnownTicketNumber(input);
|
|
68
|
+
if (known !== undefined)
|
|
69
|
+
return known;
|
|
70
|
+
const tokens = instructionTicketTokens(input.instruction);
|
|
71
|
+
return tokens.length === 1 ? tokens[0] : undefined;
|
|
54
72
|
}
|
|
55
73
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
74
|
+
* Ticket numbers on this book's retained runs.
|
|
75
|
+
* A directory with no book (not a git repository) simply holds no run history —
|
|
76
|
+
* admission owns that rejection face, this lookup does not pre-empt it.
|
|
58
77
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
async function readBookRunTickets(input) {
|
|
79
|
+
let bookKey;
|
|
80
|
+
try {
|
|
81
|
+
bookKey = input.bookKey ?? resolveBookKeyFromGit(input.projectRoot);
|
|
62
82
|
}
|
|
63
|
-
|
|
64
|
-
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof ActivationGitRepositoryRequiredError)
|
|
85
|
+
return new Set();
|
|
86
|
+
throw error;
|
|
65
87
|
}
|
|
88
|
+
return await collectBookRunTicketNumbers({ home: input.home, bookKey });
|
|
66
89
|
}
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
throw probe.error;
|
|
75
|
-
await applyTicketResolution(admitted, probe.resolution);
|
|
90
|
+
/** Bind a reused ticket number onto an admission that is still unbound. */
|
|
91
|
+
export async function bindReusedTicketNumber(admitted, ticketNumber) {
|
|
92
|
+
if (ticketNumber === undefined)
|
|
93
|
+
return;
|
|
94
|
+
if (admitted.ticketNumber !== undefined)
|
|
95
|
+
return;
|
|
96
|
+
await bindAdmittedTicketNumber(admitted, ticketNumber);
|
|
76
97
|
}
|
|
77
98
|
/**
|
|
78
|
-
*
|
|
79
|
-
* Already-
|
|
80
|
-
*
|
|
81
|
-
*
|
|
99
|
+
* Sole seat disposition for an unbound admission (#635 / #709).
|
|
100
|
+
* Already-bound admissions short-circuit — resume keeps the identity it has.
|
|
101
|
+
* Used by seats that do not pre-resolve for same-ticket resume; the seats that
|
|
102
|
+
* do (countersign / inspector / diarist) reuse the number they already resolved.
|
|
82
103
|
*/
|
|
83
|
-
export async function resolveSeatTicketBinding(admitted, env
|
|
104
|
+
export async function resolveSeatTicketBinding(admitted, env) {
|
|
84
105
|
if (admitted.ticketNumber !== undefined)
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
return admitted.ticketNumber;
|
|
107
|
+
const ticketNumber = await resolveKnownTicketNumber({
|
|
108
|
+
instruction: admitted.instruction,
|
|
109
|
+
projectRoot: admitted.projectRoot,
|
|
110
|
+
home: env.home,
|
|
111
|
+
bookKey: admitted.bookKey,
|
|
112
|
+
});
|
|
113
|
+
await bindReusedTicketNumber(admitted, ticketNumber);
|
|
114
|
+
return ticketNumber;
|
|
92
115
|
}
|
|
93
116
|
/**
|
|
94
117
|
* Sole same-seat → resume decision (#637 / #724 / #747).
|
package/package.json
CHANGED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 系统随案递送本票起居录的中立指针段(ADR 0081 `automatic-case-material`;
|
|
3
|
+
* 指针输入沿 ADR 0079 `summons-pointer-input`,不把卷宗正文塞进提示词)。
|
|
4
|
+
* 只读已有案卷:不刷新、不生成、不校验内容、不新增拒收或停工条件。
|
|
5
|
+
* 机器文本仅中立标识材料(ADR 0073),用途说明归角色材料所有。
|
|
6
|
+
*/
|
|
7
|
+
import { stat } from "node:fs/promises";
|
|
8
|
+
|
|
9
|
+
import { resolveTicketProvenanceVolume } from "../ticket-provenance.ts";
|
|
10
|
+
|
|
11
|
+
/** Section heading of the system-delivered dossier pointer. */
|
|
12
|
+
export const CASE_DOSSIER_SECTION_HEADING = "## 本票起居录(系统随案提供)" as const;
|
|
13
|
+
|
|
14
|
+
/** Honest one-line state of one dossier file: present, absent, or unreadable. */
|
|
15
|
+
async function describeDossierFile(path: string): Promise<string> {
|
|
16
|
+
try {
|
|
17
|
+
const stats = await stat(path);
|
|
18
|
+
if (!stats.isFile()) return `不可读(非普通文件):${path}`;
|
|
19
|
+
return path;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
22
|
+
if (code === "ENOENT") return `尚未生成:${path}`;
|
|
23
|
+
return `不可读(${code ?? "未知错误"}):${path}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Pointer section for a bound ticket's existing 起居录, or undefined when the
|
|
29
|
+
* run carries no ticket identity (unbound calls stay legal and get no dossier).
|
|
30
|
+
* A bound ticket whose volume is missing or unreadable is stated as such —
|
|
31
|
+
* the section never claims a dossier that is not there.
|
|
32
|
+
*/
|
|
33
|
+
export async function projectCaseDossierPointerSection(input: {
|
|
34
|
+
readonly ticketNumber: number | undefined;
|
|
35
|
+
readonly projectRoot: string;
|
|
36
|
+
readonly home: string;
|
|
37
|
+
}): Promise<string | undefined> {
|
|
38
|
+
if (input.ticketNumber === undefined) return undefined;
|
|
39
|
+
const volume = resolveTicketProvenanceVolume(
|
|
40
|
+
input.ticketNumber,
|
|
41
|
+
input.projectRoot,
|
|
42
|
+
input.home,
|
|
43
|
+
);
|
|
44
|
+
return [
|
|
45
|
+
CASE_DOSSIER_SECTION_HEADING,
|
|
46
|
+
"",
|
|
47
|
+
`票号:#${input.ticketNumber}`,
|
|
48
|
+
`人读视图:${await describeDossierFile(volume.humanViewFile)}`,
|
|
49
|
+
`记录卷宗:${await describeDossierFile(volume.recordFile)}`,
|
|
50
|
+
].join("\n");
|
|
51
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public Countersign Role run: admit ticket materials → shared post-admission
|
|
3
3
|
* coordinator → settle Terminal result (#572 / ADR 0074). #599: manual resume
|
|
4
|
-
* continues the exact session. Unbound admission
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* continues the exact session. Unbound admission reuses a known ticket identity
|
|
5
|
+
* (#709). Who runs 起居郎, and when, is the caller's composition
|
|
6
|
+
* (ADR 0010 / ADR 0075 `no-call-rule`) — not this seat's business.
|
|
7
7
|
*/
|
|
8
8
|
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
9
9
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
@@ -15,9 +15,8 @@ import {
|
|
|
15
15
|
type ParseCountersignArgvResult,
|
|
16
16
|
} from "./invocation.ts";
|
|
17
17
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ticketNumberFromProbe,
|
|
18
|
+
bindReusedTicketNumber,
|
|
19
|
+
resolveKnownTicketNumber,
|
|
21
20
|
tryResumeSameTicketSeatRun,
|
|
22
21
|
} from "./seat-ticket-binding.ts";
|
|
23
22
|
import {
|
|
@@ -91,17 +90,15 @@ export async function runPublicCountersign(
|
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
// #637: same ticket → resume prior countersign run with this summons' materials.
|
|
94
|
-
//
|
|
95
|
-
// controlled failure (bare pre-admit throw skips terminal settlement).
|
|
93
|
+
// #709: identity is reused from records this book already holds — no seat model call.
|
|
96
94
|
// No bare catch→fresh: lookup/resume failures surface; only true absence mints new.
|
|
97
95
|
const projectRoot = parsed.project ?? env.cwd;
|
|
98
|
-
const
|
|
99
|
-
parsed.instruction,
|
|
96
|
+
const reusedTicketNumber = await resolveKnownTicketNumber({
|
|
97
|
+
instruction: parsed.instruction,
|
|
100
98
|
projectRoot,
|
|
101
|
-
env,
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
if (probedTicketNumber !== undefined) {
|
|
99
|
+
home: env.home,
|
|
100
|
+
});
|
|
101
|
+
if (reusedTicketNumber !== undefined) {
|
|
105
102
|
const summons: SameTicketSummonsMaterials = {
|
|
106
103
|
instruction: parsed.instruction,
|
|
107
104
|
instructionEmpty: parsed.instruction.trim() === "",
|
|
@@ -111,7 +108,7 @@ export async function runPublicCountersign(
|
|
|
111
108
|
home: env.home,
|
|
112
109
|
projectRoot,
|
|
113
110
|
role: "countersign",
|
|
114
|
-
ticketNumber:
|
|
111
|
+
ticketNumber: reusedTicketNumber,
|
|
115
112
|
freshSummons: env.freshSummons,
|
|
116
113
|
summons,
|
|
117
114
|
resume: (runId, materials) =>
|
|
@@ -178,8 +175,8 @@ export async function runPublicCountersign(
|
|
|
178
175
|
request: turnRequest,
|
|
179
176
|
adapters: countersignAdapters({
|
|
180
177
|
beforeDispatch: async (admitted) => {
|
|
181
|
-
// #635/#
|
|
182
|
-
await
|
|
178
|
+
// #635/#709: bind the reused identity inside the controlled-failure boundary.
|
|
179
|
+
await bindReusedTicketNumber(admitted, reusedTicketNumber);
|
|
183
180
|
Object.assign(
|
|
184
181
|
turnRequest,
|
|
185
182
|
buildCountersignTurnRequest(admitted, turnProjection),
|
|
@@ -24,9 +24,8 @@ import {
|
|
|
24
24
|
type ParseDiaristArgvResult,
|
|
25
25
|
} from "./invocation.ts";
|
|
26
26
|
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
ticketNumberFromProbe,
|
|
27
|
+
bindReusedTicketNumber,
|
|
28
|
+
resolveDiaristSummonsTicketNumber,
|
|
30
29
|
tryResumeSameTicketSeatRun,
|
|
31
30
|
} from "./seat-ticket-binding.ts";
|
|
32
31
|
import {
|
|
@@ -170,16 +169,15 @@ export async function runPublicDiarist(
|
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
// #637: same ticket → resume this seat's prior run with this summons' materials.
|
|
173
|
-
//
|
|
174
|
-
//
|
|
172
|
+
// #709 / ADR 0081: reuse book records, or take the caller's sole dispatch token
|
|
173
|
+
// on a first summons that has not yet minted a volume — no seat recognizer call.
|
|
175
174
|
const projectRoot = parsed.project ?? env.cwd;
|
|
176
|
-
const
|
|
177
|
-
parsed.instruction,
|
|
175
|
+
const reusedTicketNumber = await resolveDiaristSummonsTicketNumber({
|
|
176
|
+
instruction: parsed.instruction,
|
|
178
177
|
projectRoot,
|
|
179
|
-
env,
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
if (probedTicketNumber !== undefined) {
|
|
178
|
+
home: env.home,
|
|
179
|
+
});
|
|
180
|
+
if (reusedTicketNumber !== undefined) {
|
|
183
181
|
const summons: SameTicketSummonsMaterials = {
|
|
184
182
|
instruction: parsed.instruction,
|
|
185
183
|
instructionEmpty: parsed.instruction.trim() === "",
|
|
@@ -189,7 +187,7 @@ export async function runPublicDiarist(
|
|
|
189
187
|
home: env.home,
|
|
190
188
|
projectRoot,
|
|
191
189
|
role: "diarist",
|
|
192
|
-
ticketNumber:
|
|
190
|
+
ticketNumber: reusedTicketNumber,
|
|
193
191
|
freshSummons: env.freshSummons,
|
|
194
192
|
summons,
|
|
195
193
|
resume: (runId, materials) =>
|
|
@@ -256,7 +254,7 @@ export async function runPublicDiarist(
|
|
|
256
254
|
request: turnRequest,
|
|
257
255
|
adapters: diaristAdapters({
|
|
258
256
|
beforeDispatch: async (admittedSeat) => {
|
|
259
|
-
await
|
|
257
|
+
await bindReusedTicketNumber(admittedSeat, reusedTicketNumber);
|
|
260
258
|
const sourcesPath = await freezeDiaristSourceCatalog(admittedSeat, env);
|
|
261
259
|
Object.assign(
|
|
262
260
|
turnRequest,
|
|
@@ -9,8 +9,8 @@ import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contrac
|
|
|
9
9
|
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
10
10
|
import { CliUsageError } from "./cli-errors.ts";
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
bindReusedTicketNumber,
|
|
13
|
+
resolveKnownTicketNumber,
|
|
14
14
|
tryResumeSameTicketSeatRun,
|
|
15
15
|
} from "./seat-ticket-binding.ts";
|
|
16
16
|
import {
|
|
@@ -88,15 +88,14 @@ export async function runPublicInspector(
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// #747: same parent (卷宗指针) → resume prior inspector run with this summons' materials.
|
|
91
|
-
//
|
|
92
|
-
// controlled failure (bare pre-admit throw skips terminal settlement).
|
|
91
|
+
// #709: ticket identity is reused from records this book already holds — no seat model call.
|
|
93
92
|
// No bare catch→fresh: lookup/resume failures surface; only true absence mints new.
|
|
94
93
|
const projectRoot = parsed.project ?? env.cwd;
|
|
95
|
-
const
|
|
96
|
-
parsed.instruction,
|
|
94
|
+
const reusedTicketNumber = await resolveKnownTicketNumber({
|
|
95
|
+
instruction: parsed.instruction,
|
|
97
96
|
projectRoot,
|
|
98
|
-
env,
|
|
99
|
-
);
|
|
97
|
+
home: env.home,
|
|
98
|
+
});
|
|
100
99
|
const parentRunPath = parentRunPathFromGatePointerInstruction(parsed.instruction);
|
|
101
100
|
if (parentRunPath !== undefined) {
|
|
102
101
|
const summons: SameTicketSummonsMaterials = {
|
|
@@ -171,8 +170,8 @@ export async function runPublicInspector(
|
|
|
171
170
|
request: turnRequest,
|
|
172
171
|
adapters: inspectorAdapters({
|
|
173
172
|
beforeDispatch: async (admittedSeat) => {
|
|
174
|
-
// #635/#
|
|
175
|
-
await
|
|
173
|
+
// #635/#709: bind the reused identity inside the controlled-failure boundary.
|
|
174
|
+
await bindReusedTicketNumber(admittedSeat, reusedTicketNumber);
|
|
176
175
|
},
|
|
177
176
|
}),
|
|
178
177
|
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|