@akagilnc/pi-workflow-roles 0.1.2331 → 0.1.2336
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.
|
@@ -15,12 +15,32 @@ function read(value, key) {
|
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
/** Canonical per-axis string slots only — no shape reject, no prose parse (ADR 0057). */
|
|
19
|
+
function readAmendments(output) {
|
|
20
|
+
const amendments = read(output, "amendments");
|
|
21
|
+
if (!isRecord(amendments))
|
|
22
|
+
return undefined;
|
|
23
|
+
const slots = {};
|
|
24
|
+
for (const axis of ["standards", "spec"]) {
|
|
25
|
+
const value = read(amendments, axis);
|
|
26
|
+
if (typeof value === "string")
|
|
27
|
+
slots[axis] = value;
|
|
28
|
+
}
|
|
29
|
+
if (slots.standards === undefined && slots.spec === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
return Object.freeze(slots);
|
|
32
|
+
}
|
|
18
33
|
export function validateReviewerIntent(output) {
|
|
19
34
|
const status = read(output, "status");
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
const amendments = readAmendments(output);
|
|
36
|
+
if (status === "completed") {
|
|
37
|
+
return amendments === undefined ? { status } : { status, amendments };
|
|
38
|
+
}
|
|
39
|
+
if (status === "refused") {
|
|
40
|
+
return amendments === undefined
|
|
41
|
+
? { status, diagnostic: read(output, "diagnostic") }
|
|
42
|
+
: { status, diagnostic: read(output, "diagnostic"), amendments };
|
|
43
|
+
}
|
|
24
44
|
throw new Error("Reviewer output has no recognized execution intent");
|
|
25
45
|
}
|
|
26
46
|
/** Validate runtime-owned facts at their real identity seams (target pins + plain text). */
|
package/dist/public-cli/main.js
CHANGED
|
@@ -21190,13 +21190,16 @@ function reviewerDecisiveFacts(output) {
|
|
|
21190
21190
|
const status = safelyRead(candidate, "status");
|
|
21191
21191
|
const outcomes = safelyRead(candidate, "outcomes");
|
|
21192
21192
|
const reports = safelyRead(candidate, "reports");
|
|
21193
|
+
const amendments = safelyRead(candidate, "amendments");
|
|
21193
21194
|
const axes = reviewerAxes(outcomes.readable ? outcomes.value : void 0);
|
|
21194
21195
|
const reportAxes = reviewerAxes(reports.readable ? reports.value : void 0);
|
|
21196
|
+
const amendmentAxes = reviewerAxes(amendments.readable ? amendments.value : void 0);
|
|
21195
21197
|
const acceptedBatch = safelyRead(candidate, "acceptedBatch");
|
|
21196
21198
|
const specDisposition = safelyRead(candidate, "specDisposition");
|
|
21197
21199
|
const facts = {
|
|
21198
21200
|
axes,
|
|
21199
21201
|
reportAxes,
|
|
21202
|
+
amendmentAxes,
|
|
21200
21203
|
acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== void 0,
|
|
21201
21204
|
...auditNoReceiptDecisiveFact(candidate),
|
|
21202
21205
|
// #380: spread sole-built field; do not re-key here (S1).
|
package/package.json
CHANGED
|
@@ -11,9 +11,11 @@ import type { ReviewerAcceptedEvidence, ReviewerFailureClassification, ReviewerW
|
|
|
11
11
|
export const REVIEWER_OUTPUT_TOOL_NAME = "ak_reviewer_output";
|
|
12
12
|
export const REVIEWER_ACCEPTED_TEXT = "Reviewer report accepted";
|
|
13
13
|
|
|
14
|
+
/** Seat-owned per-axis delta relative to child reports — not a replacement report. */
|
|
15
|
+
export type ReviewerAmendments = Readonly<Partial<Record<"standards" | "spec", string>>>;
|
|
14
16
|
export type ReviewerIntent =
|
|
15
|
-
| Readonly<{ status: "completed" }>
|
|
16
|
-
| Readonly<{ status: "refused"; diagnostic: string }>;
|
|
17
|
+
| Readonly<{ status: "completed"; amendments?: ReviewerAmendments }>
|
|
18
|
+
| Readonly<{ status: "refused"; diagnostic: string; amendments?: ReviewerAmendments }>;
|
|
17
19
|
/** Child report is plain text — no length/digest identity shell (ADR 0031). */
|
|
18
20
|
export type VerbatimChildReport = Readonly<{ text: string }>;
|
|
19
21
|
/** Prompt projection on the receipt face is plain text (ADR 0031). */
|
|
@@ -44,6 +46,8 @@ type RuntimeReviewerReceiptV2Clean = Readonly<{
|
|
|
44
46
|
/** Self-fetch bytes + source annotation when Spec primary path produced material (#343). */
|
|
45
47
|
specFetchedMaterial?: ReviewerAcceptedEvidence["specFetchedMaterial"];
|
|
46
48
|
reports: Readonly<Partial<Record<"standards" | "spec", VerbatimChildReport>>>;
|
|
49
|
+
/** Seat-owned per-axis deltas; separate from runtime-owned child reports. */
|
|
50
|
+
amendments?: ReviewerAmendments;
|
|
47
51
|
outcomes: Readonly<Partial<Record<"standards" | "spec", RuntimeReviewerOutcome>>>;
|
|
48
52
|
identities: Readonly<{
|
|
49
53
|
canonicalSkill: ReviewerReceiptSkillContent;
|
|
@@ -68,10 +72,30 @@ function read(value: unknown, key: string): unknown {
|
|
|
68
72
|
try { return value[key]; } catch { return undefined; }
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
/** Canonical per-axis string slots only — no shape reject, no prose parse (ADR 0057). */
|
|
76
|
+
function readAmendments(output: unknown): ReviewerAmendments | undefined {
|
|
77
|
+
const amendments = read(output, "amendments");
|
|
78
|
+
if (!isRecord(amendments)) return undefined;
|
|
79
|
+
const slots: Partial<Record<"standards" | "spec", string>> = {};
|
|
80
|
+
for (const axis of ["standards", "spec"] as const) {
|
|
81
|
+
const value = read(amendments, axis);
|
|
82
|
+
if (typeof value === "string") slots[axis] = value;
|
|
83
|
+
}
|
|
84
|
+
if (slots.standards === undefined && slots.spec === undefined) return undefined;
|
|
85
|
+
return Object.freeze(slots);
|
|
86
|
+
}
|
|
87
|
+
|
|
71
88
|
export function validateReviewerIntent(output: unknown): ReviewerIntent {
|
|
72
89
|
const status = read(output, "status");
|
|
73
|
-
|
|
74
|
-
if (status === "
|
|
90
|
+
const amendments = readAmendments(output);
|
|
91
|
+
if (status === "completed") {
|
|
92
|
+
return amendments === undefined ? { status } : { status, amendments };
|
|
93
|
+
}
|
|
94
|
+
if (status === "refused") {
|
|
95
|
+
return amendments === undefined
|
|
96
|
+
? { status, diagnostic: read(output, "diagnostic") as string }
|
|
97
|
+
: { status, diagnostic: read(output, "diagnostic") as string, amendments };
|
|
98
|
+
}
|
|
75
99
|
throw new Error("Reviewer output has no recognized execution intent");
|
|
76
100
|
}
|
|
77
101
|
|
|
@@ -1309,13 +1309,17 @@ function reviewerDecisiveFacts(
|
|
|
1309
1309
|
const status = safelyRead(candidate, "status");
|
|
1310
1310
|
const outcomes = safelyRead(candidate, "outcomes");
|
|
1311
1311
|
const reports = safelyRead(candidate, "reports");
|
|
1312
|
+
const amendments = safelyRead(candidate, "amendments");
|
|
1312
1313
|
const axes = reviewerAxes(outcomes.readable ? outcomes.value : undefined);
|
|
1313
1314
|
const reportAxes = reviewerAxes(reports.readable ? reports.value : undefined);
|
|
1315
|
+
// Typed presence only — never copy amendment prose into public facts.
|
|
1316
|
+
const amendmentAxes = reviewerAxes(amendments.readable ? amendments.value : undefined);
|
|
1314
1317
|
const acceptedBatch = safelyRead(candidate, "acceptedBatch");
|
|
1315
1318
|
const specDisposition = safelyRead(candidate, "specDisposition");
|
|
1316
1319
|
const facts: Record<string, unknown> = {
|
|
1317
1320
|
axes,
|
|
1318
1321
|
reportAxes,
|
|
1322
|
+
amendmentAxes,
|
|
1319
1323
|
acceptedBatchPresent: acceptedBatch.readable && acceptedBatch.value !== undefined,
|
|
1320
1324
|
...auditNoReceiptDecisiveFact(candidate),
|
|
1321
1325
|
// #380: spread sole-built field; do not re-key here (S1).
|
package/src/reviewer-role.ts
CHANGED
|
@@ -32,9 +32,20 @@ export type ReviewerAdmittedInputs = Readonly<{
|
|
|
32
32
|
ticketNumber?: number;
|
|
33
33
|
}>;
|
|
34
34
|
|
|
35
|
+
const reviewerAmendmentsSchema = Type.Object({
|
|
36
|
+
standards: Type.Optional(Type.String({ description: "Delta relative to the Standards child report: added finding, withdrawal, or factual correction." })),
|
|
37
|
+
spec: Type.Optional(Type.String({ description: "Delta relative to the Spec child report: added finding, withdrawal, or factual correction." })),
|
|
38
|
+
}, { additionalProperties: true, description: "Optional per-axis deltas relative to child reports; not a replacement report. Omit axes with no delta." });
|
|
35
39
|
const reviewerOutputVariants = Type.Union([
|
|
36
|
-
Type.Object({
|
|
37
|
-
|
|
40
|
+
Type.Object({
|
|
41
|
+
status: Type.Literal("completed", { description: "Reviewer dispatch completed." }),
|
|
42
|
+
amendments: Type.Optional(reviewerAmendmentsSchema),
|
|
43
|
+
}, { additionalProperties: false }),
|
|
44
|
+
Type.Object({
|
|
45
|
+
status: Type.Literal("refused", { description: "Reviewer dispatch was lawfully refused." }),
|
|
46
|
+
diagnostic: Type.String({ minLength: 1, description: "Diagnostic explaining the refusal." }),
|
|
47
|
+
amendments: Type.Optional(reviewerAmendmentsSchema),
|
|
48
|
+
}, { additionalProperties: false }),
|
|
38
49
|
]);
|
|
39
50
|
const reviewerOutputSchema = openToolObjectFromUnion(reviewerOutputVariants);
|
|
40
51
|
export type ReviewerRoleDependencies = {
|
|
@@ -43,6 +43,8 @@ export function assembleRuntimeReviewerReceipt(input: {
|
|
|
43
43
|
}
|
|
44
44
|
const accepted = input.record.accepted;
|
|
45
45
|
const skillText = accepted?.input.canonicalSkill ?? input.canonicalSkillText;
|
|
46
|
+
// Seat-owned amendments sit beside reports; never rewrite runtime-owned child bytes.
|
|
47
|
+
const amendments = input.intent.amendments;
|
|
46
48
|
return freeze({
|
|
47
49
|
version: 2,
|
|
48
50
|
status: input.intent.status,
|
|
@@ -62,6 +64,7 @@ export function assembleRuntimeReviewerReceipt(input: {
|
|
|
62
64
|
: { specFetchedMaterial: accepted.specFetchedMaterial }),
|
|
63
65
|
}),
|
|
64
66
|
reports,
|
|
67
|
+
...(amendments === undefined ? {} : { amendments }),
|
|
65
68
|
outcomes,
|
|
66
69
|
identities: {
|
|
67
70
|
canonicalSkill: { text: skillText },
|