@claudexor/orchestrator 3.0.4 → 3.1.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.
- package/dist/attemptFinalize.d.ts +200 -0
- package/dist/attemptFinalize.d.ts.map +1 -0
- package/dist/attemptFinalize.js +412 -0
- package/dist/attemptFinalize.js.map +1 -0
- package/dist/attemptTelemetry.d.ts +88 -7
- package/dist/attemptTelemetry.d.ts.map +1 -1
- package/dist/attemptTelemetry.js +276 -14
- package/dist/attemptTelemetry.js.map +1 -1
- package/dist/budgetFailure.d.ts +70 -0
- package/dist/budgetFailure.d.ts.map +1 -0
- package/dist/budgetFailure.js +114 -0
- package/dist/budgetFailure.js.map +1 -0
- package/dist/candidateEvidence.d.ts +55 -1
- package/dist/candidateEvidence.d.ts.map +1 -1
- package/dist/candidateEvidence.js +72 -0
- package/dist/candidateEvidence.js.map +1 -1
- package/dist/continuation.d.ts +77 -0
- package/dist/continuation.d.ts.map +1 -0
- package/dist/continuation.js +92 -0
- package/dist/continuation.js.map +1 -0
- package/dist/deepScanReducer.d.ts +148 -0
- package/dist/deepScanReducer.d.ts.map +1 -0
- package/dist/deepScanReducer.js +348 -0
- package/dist/deepScanReducer.js.map +1 -0
- package/dist/effortGovernance.d.ts +49 -0
- package/dist/effortGovernance.d.ts.map +1 -0
- package/dist/effortGovernance.js +35 -0
- package/dist/effortGovernance.js.map +1 -0
- package/dist/harnessFailure.d.ts +27 -0
- package/dist/harnessFailure.d.ts.map +1 -0
- package/dist/harnessFailure.js +61 -0
- package/dist/harnessFailure.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestrator.d.ts +103 -16
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +1245 -327
- package/dist/orchestrator.js.map +1 -1
- package/dist/planQuestions.d.ts.map +1 -1
- package/dist/planQuestions.js +105 -50
- package/dist/planQuestions.js.map +1 -1
- package/dist/planRun.d.ts +15 -7
- package/dist/planRun.d.ts.map +1 -1
- package/dist/planRun.js +88 -42
- package/dist/planRun.js.map +1 -1
- package/dist/planTerminal.d.ts +36 -0
- package/dist/planTerminal.d.ts.map +1 -0
- package/dist/planTerminal.js +63 -0
- package/dist/planTerminal.js.map +1 -0
- package/dist/reviewerPanel.d.ts +4 -0
- package/dist/reviewerPanel.d.ts.map +1 -1
- package/dist/reviewerPanel.js +54 -9
- package/dist/reviewerPanel.js.map +1 -1
- package/dist/revisePrompt.d.ts +17 -0
- package/dist/revisePrompt.d.ts.map +1 -0
- package/dist/revisePrompt.js +15 -0
- package/dist/revisePrompt.js.map +1 -0
- package/dist/runSupport.d.ts +67 -2
- package/dist/runSupport.d.ts.map +1 -1
- package/dist/runSupport.js +86 -6
- package/dist/runSupport.js.map +1 -1
- package/dist/runTelemetryWriter.d.ts +6 -1
- package/dist/runTelemetryWriter.d.ts.map +1 -1
- package/dist/runTelemetryWriter.js +2 -0
- package/dist/runTelemetryWriter.js.map +1 -1
- package/dist/runTerminals.d.ts +15 -4
- package/dist/runTerminals.d.ts.map +1 -1
- package/dist/runTerminals.js +16 -1
- package/dist/runTerminals.js.map +1 -1
- package/dist/structuredOutput.d.ts +27 -0
- package/dist/structuredOutput.d.ts.map +1 -1
- package/dist/structuredOutput.js +65 -7
- package/dist/structuredOutput.js.map +1 -1
- package/dist/transientClassify.d.ts +59 -0
- package/dist/transientClassify.d.ts.map +1 -0
- package/dist/transientClassify.js +109 -0
- package/dist/transientClassify.js.map +1 -0
- package/dist/write-isolation.d.ts +11 -0
- package/dist/write-isolation.d.ts.map +1 -0
- package/dist/write-isolation.js +13 -0
- package/dist/write-isolation.js.map +1 -0
- package/package.json +17 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planQuestions.d.ts","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"planQuestions.d.ts","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsCtD;;;;6DAI6D;AAC7D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;IAClD,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC;IAC9B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B,CAwCA"}
|
package/dist/planQuestions.js
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Engine-owned parser for the planner's tagged `## Open Questions` block
|
|
3
3
|
* (ported from the retired spec-interview grounding parser; the plan
|
|
4
|
-
* lifecycle is its sole owner now). Parsing is
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* lifecycle is its sole owner now). Parsing is bounded to the INSTRUCTED
|
|
5
|
+
* block and degrades gracefully. Once the block contains any recognized
|
|
6
|
+
* `[single]`/`[multi]`/`[text]` bullet it is STRUCTURED: only tagged bullets
|
|
7
|
+
* (and a terminal `(none)`) are questions, and the first nonconforming
|
|
8
|
+
* top-level bullet ends the set (QA-016 — an adapter that appends ordinary
|
|
9
|
+
* todo bullets after the tagged block can no longer fabricate owner
|
|
10
|
+
* questions). A block with NO tagged bullet keeps the tolerant legacy
|
|
11
|
+
* behavior: an untagged bullet with no `::` is a free-text question, one WITH
|
|
12
|
+
* 2+ options defaults to single-choice. A tagged choice with no options falls
|
|
13
|
+
* back to text; `(none)` is TERMINAL (so `(none)` followed by todos is `ready`,
|
|
14
|
+
* not `needs_answers`). This is plain delimiter parsing of the harness's own
|
|
15
|
+
* structured output (a data shape we instructed), not a governance signal
|
|
16
|
+
* (INV-049).
|
|
10
17
|
*/
|
|
11
18
|
const QUESTION_KINDS = new Set(["single", "multi", "text"]);
|
|
12
19
|
function isMarkdownHeading(line) {
|
|
@@ -66,54 +73,102 @@ export function extractPlanQuestions(plan) {
|
|
|
66
73
|
// silently ready).
|
|
67
74
|
return { parse: sawHeading ? "found" : "none_found", questions: best };
|
|
68
75
|
}
|
|
76
|
+
/** The recognized `[single]`/`[multi]`/`[text]` kind tag on a bullet body, or
|
|
77
|
+
* null when the body carries no recognized tag (the instructed format always
|
|
78
|
+
* tags; an untagged bullet is a deviation). */
|
|
79
|
+
function recognizedTag(body) {
|
|
80
|
+
if (!body.startsWith("["))
|
|
81
|
+
return null;
|
|
82
|
+
const close = body.indexOf("]");
|
|
83
|
+
if (close <= 0)
|
|
84
|
+
return null;
|
|
85
|
+
const tag = body.slice(1, close).trim().toLowerCase();
|
|
86
|
+
return QUESTION_KINDS.has(tag) ? tag : null;
|
|
87
|
+
}
|
|
88
|
+
/** The top-level `- `/`* ` list-item body of a line, or null when the line is
|
|
89
|
+
* not a bullet. */
|
|
90
|
+
function bulletBody(raw) {
|
|
91
|
+
const line = raw.trim();
|
|
92
|
+
if (!line.startsWith("- ") && !line.startsWith("* "))
|
|
93
|
+
return null;
|
|
94
|
+
return line.slice(2).trim();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* QA-016: parse the bullets under one `## Open Questions` heading into typed
|
|
98
|
+
* questions, bounded to the INSTRUCTED block. The instructed format tags every
|
|
99
|
+
* bullet (`[single]`/`[multi]`/`[text]`), so once the block contains any tagged
|
|
100
|
+
* bullet it is STRUCTURED: only tagged bullets (and a terminal `(none)`) are
|
|
101
|
+
* questions, and the FIRST nonconforming top-level bullet ends the set — an
|
|
102
|
+
* adapter that appends ordinary todo bullets after the tagged block (Cursor's
|
|
103
|
+
* empty-`planUri` recovery) can no longer fabricate owner questions. A block
|
|
104
|
+
* with NO tagged bullet keeps the tolerant legacy behavior (an untagged bullet
|
|
105
|
+
* with 2+ `::` options is single-choice, else free text). `(none)` is terminal
|
|
106
|
+
* in both modes, so `(none)` followed by todos reads as `ready` (zero
|
|
107
|
+
* questions), never `needs_answers`.
|
|
108
|
+
*/
|
|
69
109
|
function parseQuestionBullets(blockLines) {
|
|
110
|
+
const bodies = blockLines.map(bulletBody).filter((body) => body !== null);
|
|
111
|
+
const structured = bodies.some((body) => recognizedTag(body) !== null);
|
|
70
112
|
const questions = [];
|
|
71
|
-
for (const
|
|
72
|
-
|
|
73
|
-
if (!line.startsWith("- ") && !line.startsWith("* "))
|
|
74
|
-
continue;
|
|
75
|
-
let body = line.slice(2).trim();
|
|
113
|
+
for (const body of bodies) {
|
|
114
|
+
// `(none)` terminates the question set (never "skip and keep scanning").
|
|
76
115
|
if (isNoneBullet(body))
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
kind = tag;
|
|
86
|
-
kindTagged = true;
|
|
87
|
-
body = body.slice(close + 1).trim();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (isNoneBullet(body))
|
|
92
|
-
continue;
|
|
93
|
-
const segments = body
|
|
94
|
-
.split("::")
|
|
95
|
-
.map((p) => p.trim())
|
|
96
|
-
.filter((p) => p.length > 0);
|
|
97
|
-
const splitAsChoice = kindTagged ? segments.length > 1 : segments.length >= 3;
|
|
98
|
-
const promptText = splitAsChoice ? (segments[0] ?? "") : body;
|
|
99
|
-
if (!promptText || isPlaceholder(promptText))
|
|
100
|
-
continue;
|
|
101
|
-
const options = (splitAsChoice ? segments.slice(1) : [])
|
|
102
|
-
.filter((label) => !isPlaceholder(label))
|
|
103
|
-
.map((label, i) => ({ id: `o${i + 1}`, label }));
|
|
104
|
-
if (!kindTagged)
|
|
105
|
-
kind = options.length > 0 ? "single" : "text";
|
|
106
|
-
if (kind !== "text" && options.length === 0)
|
|
107
|
-
kind = "text";
|
|
108
|
-
const isText = kind === "text";
|
|
109
|
-
questions.push({
|
|
110
|
-
id: `q${questions.length + 1}`,
|
|
111
|
-
kind,
|
|
112
|
-
prompt: promptText,
|
|
113
|
-
options: isText ? [] : options,
|
|
114
|
-
allow_text: isText,
|
|
115
|
-
});
|
|
116
|
+
break;
|
|
117
|
+
const tag = recognizedTag(body);
|
|
118
|
+
// In a structured block, a nonconforming (untagged) bullet ends the set.
|
|
119
|
+
if (structured && tag === null)
|
|
120
|
+
break;
|
|
121
|
+
const parsed = tag !== null ? parseTaggedBullet(body, tag) : parseTolerantBullet(body);
|
|
122
|
+
if (parsed)
|
|
123
|
+
questions.push({ ...parsed, id: `q${questions.length + 1}` });
|
|
116
124
|
}
|
|
117
125
|
return questions;
|
|
118
126
|
}
|
|
127
|
+
function toQuestion(kind, promptText, options) {
|
|
128
|
+
const resolved = kind !== "text" && options.length === 0 ? "text" : kind;
|
|
129
|
+
const isText = resolved === "text";
|
|
130
|
+
return {
|
|
131
|
+
id: "",
|
|
132
|
+
kind: resolved,
|
|
133
|
+
prompt: promptText,
|
|
134
|
+
options: isText ? [] : options,
|
|
135
|
+
allow_text: isText,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** Parse a bullet that carries a recognized `[single]`/`[multi]`/`[text]` tag. */
|
|
139
|
+
function parseTaggedBullet(body, kind) {
|
|
140
|
+
const rest = body.slice(body.indexOf("]") + 1).trim();
|
|
141
|
+
if (isNoneBullet(rest))
|
|
142
|
+
return null;
|
|
143
|
+
const segments = rest
|
|
144
|
+
.split("::")
|
|
145
|
+
.map((p) => p.trim())
|
|
146
|
+
.filter((p) => p.length > 0);
|
|
147
|
+
const splitAsChoice = segments.length > 1;
|
|
148
|
+
const promptText = splitAsChoice ? (segments[0] ?? "") : rest;
|
|
149
|
+
if (!promptText || isPlaceholder(promptText))
|
|
150
|
+
return null;
|
|
151
|
+
const options = (splitAsChoice ? segments.slice(1) : [])
|
|
152
|
+
.filter((label) => !isPlaceholder(label))
|
|
153
|
+
.map((label, i) => ({ id: `o${i + 1}`, label }));
|
|
154
|
+
return toQuestion(kind, promptText, options);
|
|
155
|
+
}
|
|
156
|
+
/** Parse an untagged bullet in a wholly-untagged (legacy) block: a bullet with
|
|
157
|
+
* 2+ `::` options is single-choice, otherwise free text. */
|
|
158
|
+
function parseTolerantBullet(body) {
|
|
159
|
+
if (isNoneBullet(body))
|
|
160
|
+
return null;
|
|
161
|
+
const segments = body
|
|
162
|
+
.split("::")
|
|
163
|
+
.map((p) => p.trim())
|
|
164
|
+
.filter((p) => p.length > 0);
|
|
165
|
+
const splitAsChoice = segments.length >= 3;
|
|
166
|
+
const promptText = splitAsChoice ? (segments[0] ?? "") : body;
|
|
167
|
+
if (!promptText || isPlaceholder(promptText))
|
|
168
|
+
return null;
|
|
169
|
+
const options = (splitAsChoice ? segments.slice(1) : [])
|
|
170
|
+
.filter((label) => !isPlaceholder(label))
|
|
171
|
+
.map((label, i) => ({ id: `o${i + 1}`, label }));
|
|
172
|
+
return toQuestion(options.length > 0 ? "single" : "text", promptText, options);
|
|
173
|
+
}
|
|
119
174
|
//# sourceMappingURL=planQuestions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planQuestions.js","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"planQuestions.js","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"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"}
|
package/dist/planRun.d.ts
CHANGED
|
@@ -3,13 +3,14 @@ import { ArtifactStore, type RunPaths } from "@claudexor/artifact-store";
|
|
|
3
3
|
import { EventLog } from "@claudexor/event-log";
|
|
4
4
|
import { BudgetLedger } from "@claudexor/budget";
|
|
5
5
|
import type { AttemptTelemetry } from "./attemptTelemetry.js";
|
|
6
|
+
import type { AttemptOutcomeClass } from "./attemptFinalize.js";
|
|
7
|
+
import { type BudgetDenial } from "./budgetFailure.js";
|
|
6
8
|
import type { OrchestratorResult, PlannerAttemptArgs, PlannerAttemptOutcome, RoutedAdapter, RunInput } from "./orchestrator.js";
|
|
7
9
|
/**
|
|
8
10
|
* Council plan strategy (INV-031 / D31) + the shared plan-run finalize/failure
|
|
9
11
|
* tails, extracted from orchestrator.ts so the god-file does not absorb the new
|
|
10
|
-
* behavior (complexity ratchet).
|
|
11
|
-
*
|
|
12
|
-
* a module-level import, identical to what the orchestrator used inline.
|
|
12
|
+
* behavior (complexity ratchet). FREE functions that receive the few orchestrator
|
|
13
|
+
* methods they need via `PlanRunDeps`; every other collaborator is a module import.
|
|
13
14
|
*/
|
|
14
15
|
export interface PlanRunDeps {
|
|
15
16
|
/** One planner spawn (native plan mode, read-only) — the SAME machinery the
|
|
@@ -56,10 +57,9 @@ export declare function runCouncilPlan(deps: PlanRunDeps, args: {
|
|
|
56
57
|
contextSection: string;
|
|
57
58
|
laneRun: boolean;
|
|
58
59
|
}): Promise<OrchestratorResult>;
|
|
59
|
-
/** Write final plan artifacts (plan.md, questions.json, work_product,
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* shape-identical (downstream readiness/freeze/implement never branch). */
|
|
60
|
+
/** Write final plan artifacts (plan.md, questions.json, work_product, summary,
|
|
61
|
+
* telemetry) and the terminal event, then return the result. ONE owner for both
|
|
62
|
+
* the solo and council success tails so the artifacts are shape-identical. */
|
|
63
63
|
export declare function finalizePlanRun(deps: PlanRunDeps, args: {
|
|
64
64
|
input: RunInput;
|
|
65
65
|
contract: TaskContract;
|
|
@@ -77,6 +77,8 @@ export declare function finalizePlanRun(deps: PlanRunDeps, args: {
|
|
|
77
77
|
attemptId: string;
|
|
78
78
|
harnessId: string;
|
|
79
79
|
status: "success" | "failed" | "blocked";
|
|
80
|
+
/** D-16 r9: interrupted planners project an interrupted terminal. */
|
|
81
|
+
outcomeClass?: AttemptOutcomeClass;
|
|
80
82
|
error: string | null;
|
|
81
83
|
}[];
|
|
82
84
|
attemptTelemetries: {
|
|
@@ -103,6 +105,8 @@ export declare function writePlanHarnessFailure(deps: PlanRunDeps, ctx: {
|
|
|
103
105
|
attemptId: string;
|
|
104
106
|
harnessId: string;
|
|
105
107
|
status: "success" | "failed" | "blocked";
|
|
108
|
+
/** D-16 r9: interrupted planners project an interrupted terminal. */
|
|
109
|
+
outcomeClass?: AttemptOutcomeClass;
|
|
106
110
|
error: string | null;
|
|
107
111
|
}[];
|
|
108
112
|
attemptTelemetries: {
|
|
@@ -110,5 +114,9 @@ export declare function writePlanHarnessFailure(deps: PlanRunDeps, ctx: {
|
|
|
110
114
|
harnessId: string;
|
|
111
115
|
telemetry: AttemptTelemetry;
|
|
112
116
|
}[];
|
|
117
|
+
/** QA-050: the typed budget denial captured when a planner slot was refused
|
|
118
|
+
* pre-spawn, so plan/council terminals emit a budget failure (typed code +
|
|
119
|
+
* remediation) instead of a harness auth/setup template. */
|
|
120
|
+
budgetDenial?: BudgetDenial | null;
|
|
113
121
|
}, fallbackMessage: string): OrchestratorResult;
|
|
114
122
|
//# sourceMappingURL=planRun.d.ts.map
|
package/dist/planRun.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planRun.d.ts","sourceRoot":"","sources":["../src/planRun.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,KAAK,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"planRun.d.ts","sourceRoot":"","sources":["../src/planRun.ts"],"names":[],"mappings":"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"}
|
package/dist/planRun.js
CHANGED
|
@@ -2,8 +2,9 @@ import { join } from "node:path";
|
|
|
2
2
|
import { PlanQuestionsArtifact, derivePlanReadiness, makeOutcomeFacts, } from "@claudexor/schema";
|
|
3
3
|
import { newId, redactSecrets } from "@claudexor/util";
|
|
4
4
|
import { cancelledResult, writeFailure } from "./runTerminals.js";
|
|
5
|
+
import { budgetFailureRecord, classifyBudgetFailure } from "./budgetFailure.js";
|
|
5
6
|
import { extractPlanQuestions } from "./planQuestions.js";
|
|
6
|
-
import {
|
|
7
|
+
import { emitPlanTerminal, resolvePlanTerminalFacts } from "./planTerminal.js";
|
|
7
8
|
import { buildCouncilProjection, councilDegradationNote, councilDraftRelPath, councilMergePrompt, resolveCouncilWidth, } from "./council.js";
|
|
8
9
|
/**
|
|
9
10
|
* Council plan strategy (INV-031 / D31). Round 1: every member drafts a plan
|
|
@@ -30,6 +31,9 @@ export async function runCouncilPlan(deps, args) {
|
|
|
30
31
|
members: memberAdapters.map((a) => a.adapter.id),
|
|
31
32
|
});
|
|
32
33
|
let drafts = [];
|
|
34
|
+
// QA-050: the first council member refused pre-spawn on budget; drives the
|
|
35
|
+
// all-members-failed terminal to a typed budget failure.
|
|
36
|
+
let councilBudgetDenial = null;
|
|
33
37
|
try {
|
|
34
38
|
// Round 1 — parallel drafts (each member = one planner attempt).
|
|
35
39
|
const outcomes = await Promise.all(memberAdapters.map((routed, idx) => deps.runPlannerAttempt({
|
|
@@ -60,8 +64,11 @@ export async function runCouncilPlan(deps, args) {
|
|
|
60
64
|
attemptId: outcome.attemptId,
|
|
61
65
|
harnessId: outcome.harnessId,
|
|
62
66
|
status: outcome.status,
|
|
67
|
+
outcomeClass: outcome.outcomeClass,
|
|
63
68
|
error: outcome.error,
|
|
64
69
|
});
|
|
70
|
+
if (outcome.budgetDenied)
|
|
71
|
+
councilBudgetDenial ??= outcome.budgetDenial ?? null;
|
|
65
72
|
if (outcome.status === "success" && outcome.text) {
|
|
66
73
|
const rel = councilDraftRelPath(routed.adapter.id);
|
|
67
74
|
const absPath = join(paths.root, rel);
|
|
@@ -78,21 +85,24 @@ export async function runCouncilPlan(deps, args) {
|
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
// the
|
|
88
|
+
catch (err) {
|
|
89
|
+
// QA-047 root cause 2: the success path keeps roHome alive so the merge
|
|
90
|
+
// REUSES the admitted context (draft authenticated there) instead of a
|
|
91
|
+
// fresh HOME whose cold native-status probe times out. Leak-safe here.
|
|
84
92
|
roHome.dispose();
|
|
93
|
+
throw err;
|
|
85
94
|
}
|
|
86
95
|
if (input.signal?.aborted) {
|
|
96
|
+
roHome.dispose();
|
|
87
97
|
return cancelledResult(log, runId, taskId, "plan", paths.root, planAttempts.map((p) => ({
|
|
88
98
|
attemptId: p.attemptId,
|
|
89
99
|
harnessId: p.harnessId,
|
|
90
100
|
status: p.status,
|
|
91
101
|
})), () => deps.writeRunTelemetry(store, paths, contract, runId, taskId, "plan", attemptTelemetries, null), ledger.spend(), input.signal, store);
|
|
92
102
|
}
|
|
93
|
-
//
|
|
94
|
-
// merge). One survivor still merges (normalizes format + extracts questions).
|
|
103
|
+
// ALL members failed → typed failure (no plan to merge); one survivor merges.
|
|
95
104
|
if (drafts.length === 0) {
|
|
105
|
+
roHome.dispose();
|
|
96
106
|
return writePlanHarnessFailure(deps, {
|
|
97
107
|
input,
|
|
98
108
|
contract,
|
|
@@ -104,6 +114,7 @@ export async function runCouncilPlan(deps, args) {
|
|
|
104
114
|
ledger,
|
|
105
115
|
planAttempts,
|
|
106
116
|
attemptTelemetries,
|
|
117
|
+
budgetDenial: councilBudgetDenial,
|
|
107
118
|
}, "all council members failed");
|
|
108
119
|
}
|
|
109
120
|
// The merger is the primary when it survived round 1, else the first
|
|
@@ -112,7 +123,6 @@ export async function runCouncilPlan(deps, args) {
|
|
|
112
123
|
const draftedIds = new Set(drafts.map((d) => d.harnessId));
|
|
113
124
|
const primary = memberAdapters.find((a) => draftedIds.has(a.adapter.id)) ??
|
|
114
125
|
memberAdapters[0];
|
|
115
|
-
const roHome2 = resolveReadOnlyRouteContext(deps.execRootOf(input));
|
|
116
126
|
let mergeOutcome;
|
|
117
127
|
try {
|
|
118
128
|
mergeOutcome = await deps.runPlannerAttempt({
|
|
@@ -127,7 +137,9 @@ export async function runCouncilPlan(deps, args) {
|
|
|
127
137
|
routed: primary,
|
|
128
138
|
attemptId: `p${String(memberCount + 1).padStart(2, "0")}`,
|
|
129
139
|
laneRun: args.laneRun,
|
|
130
|
-
|
|
140
|
+
// QA-047 root cause 2: merge in the SAME admitted route context (not a
|
|
141
|
+
// fresh HOME whose cold native-status probe times out as an absent login).
|
|
142
|
+
fallbackHome: roHome.env,
|
|
131
143
|
// The merge references the draft FILES by absolute path (pointer lines);
|
|
132
144
|
// full draft text never rides the prompt bubble.
|
|
133
145
|
promptBody: councilMergePrompt(input.prompt, drafts.map((d) => ({ harnessId: d.harnessId, absPath: d.absPath }))),
|
|
@@ -136,7 +148,7 @@ export async function runCouncilPlan(deps, args) {
|
|
|
136
148
|
});
|
|
137
149
|
}
|
|
138
150
|
finally {
|
|
139
|
-
|
|
151
|
+
roHome.dispose();
|
|
140
152
|
}
|
|
141
153
|
if (mergeOutcome.telemetry)
|
|
142
154
|
attemptTelemetries.push({
|
|
@@ -148,16 +160,21 @@ export async function runCouncilPlan(deps, args) {
|
|
|
148
160
|
attemptId: mergeOutcome.attemptId,
|
|
149
161
|
harnessId: mergeOutcome.harnessId,
|
|
150
162
|
status: mergeOutcome.status,
|
|
163
|
+
outcomeClass: mergeOutcome.outcomeClass,
|
|
151
164
|
error: mergeOutcome.error,
|
|
152
165
|
});
|
|
153
166
|
const mergedBy = mergeOutcome.status === "success" ? primary.adapter.id : null;
|
|
167
|
+
// QA-047 root cause 4: a member card carries its DRAFT error only — the
|
|
168
|
+
// primary owns two attempts under one harness id (draft + merge), so a
|
|
169
|
+
// harness-id-only lookup would misattach the merge failure to a drafted member.
|
|
170
|
+
const mergeAttemptId = mergeOutcome.attemptId;
|
|
154
171
|
const councilProjection = buildCouncilProjection({
|
|
155
172
|
requested,
|
|
156
173
|
members: memberAdapters.map((a) => ({
|
|
157
174
|
harnessId: a.adapter.id,
|
|
158
175
|
role: a.adapter.id === primary.adapter.id ? "primary" : "member",
|
|
159
176
|
drafted: draftedIds.has(a.adapter.id),
|
|
160
|
-
error: planAttempts.find((p) => p.harnessId === a.adapter.id && p.error)?.error ?? null,
|
|
177
|
+
error: planAttempts.find((p) => p.harnessId === a.adapter.id && p.attemptId !== mergeAttemptId && p.error)?.error ?? null,
|
|
161
178
|
})),
|
|
162
179
|
mergedBy,
|
|
163
180
|
});
|
|
@@ -182,6 +199,7 @@ export async function runCouncilPlan(deps, args) {
|
|
|
182
199
|
ledger,
|
|
183
200
|
planAttempts,
|
|
184
201
|
attemptTelemetries,
|
|
202
|
+
budgetDenial: mergeOutcome.budgetDenied ? (mergeOutcome.budgetDenial ?? null) : null,
|
|
185
203
|
}, `council merge failed: ${mergeOutcome.error ?? "the primary produced no unified plan"}`);
|
|
186
204
|
}
|
|
187
205
|
return finalizePlanRun(deps, {
|
|
@@ -200,31 +218,26 @@ export async function runCouncilPlan(deps, args) {
|
|
|
200
218
|
council: councilProjection,
|
|
201
219
|
});
|
|
202
220
|
}
|
|
203
|
-
/** Write final plan artifacts (plan.md, questions.json, work_product,
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
* shape-identical (downstream readiness/freeze/implement never branch). */
|
|
221
|
+
/** Write final plan artifacts (plan.md, questions.json, work_product, summary,
|
|
222
|
+
* telemetry) and the terminal event, then return the result. ONE owner for both
|
|
223
|
+
* the solo and council success tails so the artifacts are shape-identical. */
|
|
207
224
|
export function finalizePlanRun(deps, args) {
|
|
208
225
|
const { input, contract, taskId, runId, store, paths, log, ledger, plans, planAttempts, council, } = args;
|
|
209
226
|
const failedPlanners = planAttempts.filter((p) => p.status !== "success");
|
|
210
227
|
const winner = plans[0];
|
|
211
228
|
const winnerHarness = winner?.id ?? "(none)";
|
|
212
229
|
const winnerAttemptId = args.winnerAttemptId ?? planAttempts.find((p) => p.status === "success")?.attemptId ?? null;
|
|
213
|
-
// final/plan.md is the PURE plan body (
|
|
214
|
-
// text): implement freezes and hashes THIS file, so wrapper prose lives in
|
|
215
|
-
// summary.md instead (advisor pass, V6a).
|
|
230
|
+
// final/plan.md is the PURE plan body (implement freezes+hashes it; V6a).
|
|
216
231
|
const planDoc = redactSecrets(winner?.text ?? "(no output)");
|
|
217
232
|
store.writeText(join(paths.finalDir, "plan.md"), planDoc + "\n");
|
|
218
|
-
// Engine-parsed open questions (final/questions.json): the ONE artifact
|
|
219
|
-
//
|
|
220
|
-
// only — draft questions never leak into the final set.
|
|
233
|
+
// Engine-parsed open questions (final/questions.json): the ONE artifact plan
|
|
234
|
+
// readiness derives from. For council this runs on the MERGE output only.
|
|
221
235
|
const parsedQuestions = extractPlanQuestions(planDoc);
|
|
222
236
|
store.writeJson(join(paths.finalDir, "questions.json"), parsedQuestions);
|
|
223
237
|
if (council)
|
|
224
238
|
store.writeYaml(join(paths.root, "council", "membership.yaml"), council);
|
|
225
|
-
// A plan is a delivered work product (a report)
|
|
226
|
-
//
|
|
227
|
-
// changed.
|
|
239
|
+
// A plan is a delivered work product (a report); result_kind=plan tells
|
|
240
|
+
// surfaces NO files changed.
|
|
228
241
|
store.writeYaml(join(paths.finalDir, "work_product.yaml"), {
|
|
229
242
|
id: newId("wp"),
|
|
230
243
|
kind: "report",
|
|
@@ -233,7 +246,7 @@ export function finalizePlanRun(deps, args) {
|
|
|
233
246
|
meta: {
|
|
234
247
|
mode: "plan",
|
|
235
248
|
result_kind: "plan",
|
|
236
|
-
planners: plans.length,
|
|
249
|
+
planners: council?.members.length ?? plans.length,
|
|
237
250
|
diffstat: { files: 0, additions: 0, deletions: 0 },
|
|
238
251
|
blockers: 0,
|
|
239
252
|
adopted: null,
|
|
@@ -241,10 +254,12 @@ export function finalizePlanRun(deps, args) {
|
|
|
241
254
|
});
|
|
242
255
|
const readiness = derivePlanReadiness(PlanQuestionsArtifact.parse(parsedQuestions));
|
|
243
256
|
const councilNote = council ? councilDegradationNote(council) : "";
|
|
257
|
+
// D-16: fold the WINNING attempt's work_state into the plan terminal (INV-116; see planTerminal.ts).
|
|
258
|
+
const { planFacts, planVetoed, lifecycleLine, summarySuffix } = resolvePlanTerminalFacts(args.attemptTelemetries, winnerAttemptId);
|
|
244
259
|
store.writeText(join(paths.finalDir, "summary.md"), [
|
|
245
260
|
`# Run ${runId} (plan)`,
|
|
246
261
|
"",
|
|
247
|
-
|
|
262
|
+
lifecycleLine,
|
|
248
263
|
council
|
|
249
264
|
? `- Council: merged by ${council.mergedBy ?? "(none)"} from ${council.drafted} of ${council.requested} member(s)`
|
|
250
265
|
: `- Planner: ${winnerHarness}`,
|
|
@@ -266,8 +281,8 @@ export function finalizePlanRun(deps, args) {
|
|
|
266
281
|
question_count: readiness.questionCount,
|
|
267
282
|
readiness: readiness.state,
|
|
268
283
|
});
|
|
269
|
-
|
|
270
|
-
|
|
284
|
+
// D-16 terminal disclosure keyed on the folded facts (see planTerminal.ts).
|
|
285
|
+
emitPlanTerminal(store, paths, log, planFacts, planVetoed);
|
|
271
286
|
return {
|
|
272
287
|
spendUsd: ledger.spend(),
|
|
273
288
|
runId,
|
|
@@ -277,7 +292,7 @@ export function finalizePlanRun(deps, args) {
|
|
|
277
292
|
facts: planFacts,
|
|
278
293
|
winner: null,
|
|
279
294
|
runDir: paths.root,
|
|
280
|
-
summary: `${council ? `Council plan (merged by ${winnerHarness})` : `Plan by ${winnerHarness}`}; ${readiness.questionCount} open question(s)${parsedQuestions.parse === "none_found" ? " (untagged plan — unverified)" : ""}.`,
|
|
295
|
+
summary: `${council ? `Council plan (merged by ${winnerHarness})` : `Plan by ${winnerHarness}`}; ${readiness.questionCount} open question(s)${parsedQuestions.parse === "none_found" ? " (untagged plan — unverified)" : ""}${summarySuffix}.`,
|
|
281
296
|
candidates: planAttempts.map((p) => ({
|
|
282
297
|
attemptId: p.attemptId,
|
|
283
298
|
harnessId: p.harnessId,
|
|
@@ -291,23 +306,53 @@ export function finalizePlanRun(deps, args) {
|
|
|
291
306
|
export function writePlanHarnessFailure(deps, ctx, fallbackMessage) {
|
|
292
307
|
const { input, contract, taskId, runId, store, paths, log, ledger, planAttempts } = ctx;
|
|
293
308
|
const blocked = planAttempts.some((p) => p.status === "blocked");
|
|
294
|
-
|
|
295
|
-
|
|
309
|
+
// QA-050: a budget refusal (pre-spawn denial, or a settled budget terminal)
|
|
310
|
+
// is a BUDGET failure across plan + council, not a harness one.
|
|
311
|
+
const budgetMapping = !blocked && (ctx.budgetDenial || ledger.terminal())
|
|
312
|
+
? classifyBudgetFailure({ denial: ctx.budgetDenial ?? null, terminal: ledger.terminal() })
|
|
313
|
+
: null;
|
|
314
|
+
// QA-047 root cause 3: a proven-success draft can NEVER read "failed". Only
|
|
315
|
+
// non-success attempts feed failure lines; drafts are preserved evidence.
|
|
316
|
+
const failedLines = planAttempts
|
|
317
|
+
.filter((p) => p.status !== "success")
|
|
318
|
+
.map((p) => `${p.attemptId}/${p.harnessId}: ${p.error ?? "failed"}`);
|
|
319
|
+
const preserved = planAttempts
|
|
320
|
+
.filter((p) => p.status === "success")
|
|
321
|
+
.map((p) => `${p.attemptId}/${p.harnessId}`);
|
|
322
|
+
const message = budgetMapping
|
|
323
|
+
? budgetMapping.safeMessage
|
|
324
|
+
: `${failedLines.length > 0 ? failedLines.join("\n") : fallbackMessage}${preserved.length > 0 ? `\nPreserved drafts: ${preserved.join(", ")}` : ""}`.trim();
|
|
296
325
|
deps.writeRunTelemetry(store, paths, contract, runId, taskId, "plan", ctx.attemptTelemetries, null);
|
|
297
|
-
store.writeText(join(paths.contextDir, "context_error.md"), `# Harness Error\n\n${message}\n`);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
326
|
+
store.writeText(join(paths.contextDir, "context_error.md"), `# ${budgetMapping ? "Budget Denied" : "Harness Error"}\n\n${message}\n`);
|
|
327
|
+
if (budgetMapping) {
|
|
328
|
+
writeFailure(store, paths, budgetFailureRecord(budgetMapping, {
|
|
329
|
+
eventRefs: planAttempts.map((p) => `attempts/${p.attemptId}/events.jsonl`),
|
|
330
|
+
runDir: paths.root,
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
writeFailure(store, paths, {
|
|
335
|
+
phase: "harness",
|
|
336
|
+
category: blocked ? "policy" : "harness_error",
|
|
337
|
+
safeMessage: message,
|
|
338
|
+
eventRefs: planAttempts.map((p) => `attempts/${p.attemptId}/events.jsonl`),
|
|
339
|
+
runDir: paths.root,
|
|
340
|
+
nextActions: ["Open diagnostics", "Check harness authentication", "Retry after setup"],
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
// D-16 r9: when NO planner blocked/budget-failed and some ran out of
|
|
344
|
+
// context, the terminal is interrupted — not a generic harness failure.
|
|
345
|
+
const anyInterrupted = planAttempts.some((p) => p.outcomeClass === "interrupted");
|
|
346
|
+
store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (plan)\n\n- Lifecycle: ${blocked ? "succeeded (needs review)" : anyInterrupted && !budgetMapping ? "interrupted" : "failed"}\n\n${message}\n`);
|
|
307
347
|
log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
|
|
308
348
|
const planFailFacts = blocked
|
|
309
349
|
? makeOutcomeFacts("succeeded", { review: "blocked", reason: "review_blocked" })
|
|
310
|
-
:
|
|
350
|
+
: !budgetMapping && anyInterrupted
|
|
351
|
+
? makeOutcomeFacts("interrupted", { reason: "context_capacity_exhausted" })
|
|
352
|
+
: makeOutcomeFacts("failed", {
|
|
353
|
+
reason: budgetMapping ? budgetMapping.reason : "harness_failed",
|
|
354
|
+
});
|
|
355
|
+
const failPhase = budgetMapping ? budgetMapping.phase : "harness";
|
|
311
356
|
if (blocked)
|
|
312
357
|
log.emit("run.blocked", {
|
|
313
358
|
lifecycle: planFailFacts.lifecycle,
|
|
@@ -321,7 +366,8 @@ export function writePlanHarnessFailure(deps, ctx, fallbackMessage) {
|
|
|
321
366
|
lifecycle: planFailFacts.lifecycle,
|
|
322
367
|
facts: planFailFacts,
|
|
323
368
|
reason: planFailFacts.reason,
|
|
324
|
-
phase:
|
|
369
|
+
phase: failPhase,
|
|
370
|
+
...(budgetMapping?.harnessId ? { harness_id: budgetMapping.harnessId } : {}),
|
|
325
371
|
error: message,
|
|
326
372
|
failure_ref: "final/failure.yaml",
|
|
327
373
|
});
|