sortie-dogs 0.10.19 → 0.10.22
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 +7 -7
- package/dist/asset-version.d.ts +1 -1
- package/dist/asset-version.js +1 -1
- package/dist/core/operator-proposal.d.ts +37 -2
- package/dist/core/operator-proposal.js +253 -12
- package/dist/plugin/adaptive-remediation-host.d.ts +1 -1
- package/dist/plugin/adaptive-remediation-host.js +1 -1
- package/dist/plugin/model-cost.d.ts +3 -3
- package/dist/plugin/model-cost.js +7 -2
- package/dist/plugin/model-routing.d.ts +7 -7
- package/dist/plugin/model-routing.js +5 -5
- package/dist/plugin/profiled.js +77 -10
- package/dist/runtime-assets-v010.js +22 -2
- package/dist/runtime-assets.d.ts +2 -2
- package/dist/runtime-assets.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -198,7 +198,7 @@ not invent, probe, or translate variant names.
|
|
|
198
198
|
- `freeTierFallbackModels`: ordered global last-resort model IDs. Default:
|
|
199
199
|
`opencode/deepseek-v4-flash-free`; `[]` disables this fallback.
|
|
200
200
|
- `dedicatedWorkerModel`: canonical stable serial target, default
|
|
201
|
-
`openai/gpt-
|
|
201
|
+
`openai/gpt-6-sol` / `medium`. The v0.10 profile also supplies its explicit
|
|
202
202
|
role routes below; do not infer the v0.10 worker route from this stable setting.
|
|
203
203
|
- `consultation.strategy`: fixed advisor identity, optional `required`, and
|
|
204
204
|
positive `maxCallsPerCandidate`; default one call and not required.
|
|
@@ -237,13 +237,13 @@ reuse the same evidence instead of spending the validation budget again.
|
|
|
237
237
|
|
|
238
238
|
### Default v0.10 routes
|
|
239
239
|
|
|
240
|
-
- `dog-operator`: `openai/gpt-
|
|
241
|
-
- `dogs-coordinator`: `openai/gpt-
|
|
242
|
-
- `dog-worker-v010`: `openai/gpt-
|
|
243
|
-
- `dog-scout-v010`: `openai/gpt-
|
|
244
|
-
- `dog-reviewer-v010`: `openai/gpt-
|
|
240
|
+
- `dog-operator`: `openai/gpt-6-luna` / `max`
|
|
241
|
+
- `dogs-coordinator`: `openai/gpt-6-sol` / `xhigh`
|
|
242
|
+
- `dog-worker-v010`: `openai/gpt-6-luna` / `max`
|
|
243
|
+
- `dog-scout-v010`: `openai/gpt-6-luna` / `xhigh`
|
|
244
|
+
- `dog-reviewer-v010`: `openai/gpt-6-sol` / `xhigh`
|
|
245
245
|
- `dog-advisor-v010`: preferred declared `anthropic/claude-opus-5`, otherwise
|
|
246
|
-
`openai/gpt-
|
|
246
|
+
`openai/gpt-6-sol` / `xhigh`
|
|
247
247
|
|
|
248
248
|
An explicit model and variant selected in OpenCode remains authoritative for that
|
|
249
249
|
session. Child role defaults fill absent native settings and may be overridden by
|
package/dist/asset-version.d.ts
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export declare const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export declare const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1-reflection1-cancel1-proposal-budget1-goal-recovery1-delegate-execute1-v2-depth1-process-replacement1-unstarted-v2-1-cold-turn1-return-report-v2-2";
|
|
6
|
+
export declare const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1-reflection1-cancel1-proposal-budget1-goal-recovery1-delegate-execute1-v2-depth1-process-replacement1-unstarted-v2-1-cold-turn1-return-report-v2-2-root-revision1";
|
|
7
7
|
export type RuntimeAssetVersion = typeof RUNTIME_ASSET_VERSION | typeof V010_RUNTIME_ASSET_VERSION;
|
package/dist/asset-version.js
CHANGED
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* installed project marker without importing every asset body.
|
|
4
4
|
*/
|
|
5
5
|
export const RUNTIME_ASSET_VERSION = "0.3.89-completion-proof-v1";
|
|
6
|
-
export const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1-reflection1-cancel1-proposal-budget1-goal-recovery1-delegate-execute1-v2-depth1-process-replacement1-unstarted-v2-1-cold-turn1-return-report-v2-2";
|
|
6
|
+
export const V010_RUNTIME_ASSET_VERSION = "0.10.0-v0912-language4-cost-rpt10-compaction-ref2-proposal1-review-remediation1-surface4-proposal-recovery2-quality1-terminal2-route1-path1-permission2-prerequisite1-v2-bridge1-intent1-reflection1-cancel1-proposal-budget1-goal-recovery1-delegate-execute1-v2-depth1-process-replacement1-unstarted-v2-1-cold-turn1-return-report-v2-2-root-revision1";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RuntimeProfile } from "./runtime-profile.js";
|
|
2
|
-
import { type OperatorPlan, type OperatorTask } from "./operator-runtime.js";
|
|
2
|
+
import { type OperatorPlan, type OperatorState, type OperatorTask } from "./operator-runtime.js";
|
|
3
3
|
export declare const DEFAULT_OPERATOR_PROPOSAL_BUDGET: Readonly<{
|
|
4
4
|
max_reads: 45;
|
|
5
5
|
max_submissions: 9;
|
|
@@ -8,6 +8,7 @@ export declare const OPERATOR_PROPOSAL_BUDGET_CAPS: Readonly<{
|
|
|
8
8
|
max_reads: 192;
|
|
9
9
|
max_submissions: 24;
|
|
10
10
|
}>;
|
|
11
|
+
export declare const OPERATOR_PROPOSAL_REVISION_CONTRACT: string;
|
|
11
12
|
export declare const OPERATOR_APPROVAL_CONTRACT: string;
|
|
12
13
|
export interface OperatorIntentRequirement {
|
|
13
14
|
readonly id: string;
|
|
@@ -90,6 +91,31 @@ export interface OperatorProposalState {
|
|
|
90
91
|
proposal_hash: string | null;
|
|
91
92
|
proposal: OperatorProposalPacket | null;
|
|
92
93
|
approval_rationale: string | null;
|
|
94
|
+
/** Preparation may publish execution controls before approval commits; never revise that pinned plan. */
|
|
95
|
+
approval_started?: boolean;
|
|
96
|
+
root_revisions?: OperatorProposalRevision[];
|
|
97
|
+
/** Immutable archive identities of earlier approved contracts on this root. */
|
|
98
|
+
approved_history?: readonly {
|
|
99
|
+
readonly archive_hash: string;
|
|
100
|
+
readonly intent_id: string;
|
|
101
|
+
readonly proposal_id: string;
|
|
102
|
+
readonly run_id: string;
|
|
103
|
+
readonly disposition: "completed" | "incomplete";
|
|
104
|
+
}[];
|
|
105
|
+
}
|
|
106
|
+
interface OperatorProposalIdentity {
|
|
107
|
+
readonly proposal_id: string;
|
|
108
|
+
readonly revision: number;
|
|
109
|
+
readonly content_hash: string;
|
|
110
|
+
}
|
|
111
|
+
export interface OperatorProposalRevision {
|
|
112
|
+
readonly actor: string;
|
|
113
|
+
readonly at: string;
|
|
114
|
+
readonly rationale: string;
|
|
115
|
+
readonly from: OperatorProposalIdentity;
|
|
116
|
+
readonly to: OperatorProposalIdentity;
|
|
117
|
+
readonly patch_hash: string;
|
|
118
|
+
readonly paths: readonly string[];
|
|
93
119
|
}
|
|
94
120
|
export interface OperatorProposalBudgetDiagnostic {
|
|
95
121
|
readonly status: "proposal-budget-exhausted";
|
|
@@ -112,12 +138,13 @@ export declare class OperatorProposalBudgetError extends Error {
|
|
|
112
138
|
/** Durable pre-execution lane. It grants investigation and submission, never source mutation or execution. */
|
|
113
139
|
export declare class OperatorProposalRuntime {
|
|
114
140
|
readonly profile: RuntimeProfile;
|
|
115
|
-
private readonly states;
|
|
116
141
|
private readonly pending;
|
|
117
142
|
private serial;
|
|
143
|
+
private locked;
|
|
118
144
|
readonly projectRoot: string;
|
|
119
145
|
constructor(projectRoot: string, profile: RuntimeProfile);
|
|
120
146
|
private file;
|
|
147
|
+
private approvedArchiveFile;
|
|
121
148
|
private spendFile;
|
|
122
149
|
private readSpend;
|
|
123
150
|
private saveSpend;
|
|
@@ -135,6 +162,8 @@ export declare class OperatorProposalRuntime {
|
|
|
135
162
|
private resolveTask;
|
|
136
163
|
begin(root: string, raw: unknown): Promise<OperatorProposalState>;
|
|
137
164
|
private beginUnlocked;
|
|
165
|
+
/** Explicit root-only transition after an approved contract's execution lane has ended. */
|
|
166
|
+
reviseApproved(root: string, actor: string, raw: unknown, readRun: () => Promise<OperatorState | undefined>, currentGoal: OperatorProposalGoalBinding): Promise<OperatorProposalState>;
|
|
138
167
|
bindGoal(root: string, binding: OperatorProposalGoalBinding): Promise<OperatorProposalState>;
|
|
139
168
|
private bindGoalUnlocked;
|
|
140
169
|
admit(root: string, callID: string, args: unknown, reserveBudget?: () => Promise<void>): Promise<OperatorTask>;
|
|
@@ -148,6 +177,11 @@ export declare class OperatorProposalRuntime {
|
|
|
148
177
|
submit(root: string, actor: string, raw: unknown): Promise<OperatorProposalState>;
|
|
149
178
|
submitJSON(root: string, actor: string, source: string): Promise<OperatorProposalState>;
|
|
150
179
|
private submitUnlocked;
|
|
180
|
+
/** A read-free root correction of an ended child's submitted packet, never a new investigation grant. */
|
|
181
|
+
reviseJSON(root: string, actor: string, source: string): Promise<OperatorProposalState>;
|
|
182
|
+
private patchedPacket;
|
|
183
|
+
/** Close revision before any prepare/register side effect, including when that later step fails. */
|
|
184
|
+
pinApproval(root: string, raw: unknown): Promise<void>;
|
|
151
185
|
approve(root: string, raw: unknown, commit?: boolean): Promise<OperatorProposalState>;
|
|
152
186
|
private approveUnlocked;
|
|
153
187
|
/**
|
|
@@ -161,3 +195,4 @@ export declare class OperatorProposalRuntime {
|
|
|
161
195
|
private requiredUnlocked;
|
|
162
196
|
packet(state: OperatorProposalState): unknown;
|
|
163
197
|
}
|
|
198
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { normalizeRelativePath } from "./path.js";
|
|
5
5
|
import { OperatorContractError, parseOperatorPlan } from "./operator-runtime.js";
|
|
@@ -10,6 +10,18 @@ const ORIGINAL_REQUEST_MAX_CHARACTERS = 128 * 1024;
|
|
|
10
10
|
const ORIGINAL_REQUEST_MAX_BYTES = 128 * 1024;
|
|
11
11
|
export const DEFAULT_OPERATOR_PROPOSAL_BUDGET = Object.freeze({ max_reads: 45, max_submissions: 9 });
|
|
12
12
|
export const OPERATOR_PROPOSAL_BUDGET_CAPS = Object.freeze({ max_reads: 192, max_submissions: 24 });
|
|
13
|
+
export const OPERATOR_PROPOSAL_REVISION_CONTRACT = "revision_json must encode exactly {proposal_id:string,revision:positive integer,content_hash:string,rationale:nonblank single-line string,patches:array}. " +
|
|
14
|
+
"Pin the current submitted identity from operator_status. patches contains 1..32 {op,path,value} objects. " +
|
|
15
|
+
"replace is allowed only at /coverage, /existing_surface, /uncovered, /negative_handling, /read_scope, /plan/units, /plan/acceptance_proof, " +
|
|
16
|
+
"/plan/units/<index>/{title,objective,read,validation,acceptance_indices}; add or replace is also allowed at " +
|
|
17
|
+
"/plan/goal_declaration/criteria/<index>/{validation_command,goal_validation_command}. No duplicate or overlapping paths. " +
|
|
18
|
+
"Read spellings may normalize separators and dot segments without traversal; read authority can only shrink. " +
|
|
19
|
+
"The exact write union, ordered acceptance, source_refs, intent, authoritative_refs, goal binding, goal defaults, criterion identities, git_lifecycle and budgets are immutable. " +
|
|
20
|
+
"Unit count cannot increase. The host derives the next revision, hash and budget_estimate, validates the complete packet, and records root-patch provenance atomically. " +
|
|
21
|
+
"Each authorized attempt, including malformed input or rejected patches, consumes one remaining submission; foreign/stale calls do not spend the live grant. No reads or execution units are granted or restored. " +
|
|
22
|
+
"Approval preparation or approval closes this revision lane. Revision never restarts a child, prepares a run, or approves anything. " +
|
|
23
|
+
"Compare every original requirement again before explicit approval with the new identity. Use only already observed evidence. " +
|
|
24
|
+
"Keep root-owned push/global apply and user-only acceptance pending until separately evidenced; worker tests never prove those obligations. Unrepresentable or unobserved requirements stay uncovered.";
|
|
13
25
|
const OPERATOR_APPROVAL_IDENTITY_FIELDS = ["proposal_id", "revision", "content_hash", "compared_requirement_ids", "decision"];
|
|
14
26
|
const OPERATOR_APPROVAL_RATIONALE_FIELDS = ["rationale", "comparison_rationale"];
|
|
15
27
|
export const OPERATOR_APPROVAL_CONTRACT = "approval_json must encode one JSON object using exactly one six-field shape. " +
|
|
@@ -287,10 +299,9 @@ function parsePacket(value, state) {
|
|
|
287
299
|
/** Durable pre-execution lane. It grants investigation and submission, never source mutation or execution. */
|
|
288
300
|
export class OperatorProposalRuntime {
|
|
289
301
|
profile;
|
|
290
|
-
states = new Map();
|
|
291
302
|
pending = new Map();
|
|
292
303
|
async serial(root, action) {
|
|
293
|
-
const result = (this.pending.get(root) ?? Promise.resolve()).then(action);
|
|
304
|
+
const result = (this.pending.get(root) ?? Promise.resolve()).then(() => this.locked(root, action));
|
|
294
305
|
const tail = result.then(() => undefined, () => undefined);
|
|
295
306
|
this.pending.set(root, tail);
|
|
296
307
|
try {
|
|
@@ -301,12 +312,40 @@ export class OperatorProposalRuntime {
|
|
|
301
312
|
this.pending.delete(root);
|
|
302
313
|
}
|
|
303
314
|
}
|
|
315
|
+
async locked(root, action) {
|
|
316
|
+
await mkdir(join(this.projectRoot, this.profile.stateDirectory, "operator-proposals"), { recursive: true });
|
|
317
|
+
const lock = `${this.file(root)}.lock`;
|
|
318
|
+
let handle;
|
|
319
|
+
for (let attempt = 0; attempt < 100; attempt++) {
|
|
320
|
+
try {
|
|
321
|
+
handle = await open(lock, "wx", 0o600);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
if (error.code !== "EEXIST")
|
|
326
|
+
throw error;
|
|
327
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (!handle)
|
|
331
|
+
throw new Error("operator-proposal-state-busy");
|
|
332
|
+
try {
|
|
333
|
+
return await action();
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
await handle.close();
|
|
337
|
+
await rm(lock, { force: true });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
304
340
|
projectRoot;
|
|
305
341
|
constructor(projectRoot, profile) {
|
|
306
342
|
this.profile = profile;
|
|
307
343
|
this.projectRoot = resolve(projectRoot);
|
|
308
344
|
}
|
|
309
345
|
file(root) { return join(this.projectRoot, this.profile.stateDirectory, "operator-proposals", `${hash(root)}.json`); }
|
|
346
|
+
approvedArchiveFile(root, intentID, proposalHash, runID) {
|
|
347
|
+
return join(this.projectRoot, this.profile.stateDirectory, "operator-proposals", `${hash(root)}.${intentID}.${proposalHash}.${hash(runID).slice(0, 16)}.approved.json`);
|
|
348
|
+
}
|
|
310
349
|
spendFile(root) { return join(this.projectRoot, this.profile.stateDirectory, "operator-proposals", `${hash(root)}.spend.json`); }
|
|
311
350
|
async readSpend(root) {
|
|
312
351
|
let source;
|
|
@@ -331,6 +370,12 @@ export class OperatorProposalRuntime {
|
|
|
331
370
|
!/^sha256:[a-f0-9]{64}$/u.test(spend.retry.goal_binding.acceptance_fingerprint))) {
|
|
332
371
|
throw new Error("operator-proposal-spend-invalid");
|
|
333
372
|
}
|
|
373
|
+
if (spend.approved_history !== undefined && (!Array.isArray(spend.approved_history) ||
|
|
374
|
+
spend.approved_history.some(item => !record(item) || !/^[a-f0-9]{64}$/u.test(String(item.archive_hash)) ||
|
|
375
|
+
!identifier(item.intent_id) || !identifier(item.proposal_id) || !text(item.run_id) ||
|
|
376
|
+
!["completed", "incomplete"].includes(String(item.disposition))))) {
|
|
377
|
+
throw new Error("operator-proposal-spend-invalid");
|
|
378
|
+
}
|
|
334
379
|
return spend;
|
|
335
380
|
}
|
|
336
381
|
async saveSpend(spend) {
|
|
@@ -362,9 +407,6 @@ export class OperatorProposalRuntime {
|
|
|
362
407
|
return this.serial(root, () => this.readUnlocked(root));
|
|
363
408
|
}
|
|
364
409
|
async readUnlocked(root) {
|
|
365
|
-
const cached = this.states.get(root);
|
|
366
|
-
if (cached)
|
|
367
|
-
return structuredClone(cached);
|
|
368
410
|
let source;
|
|
369
411
|
try {
|
|
370
412
|
source = await readFile(this.file(root), "utf8");
|
|
@@ -396,8 +438,7 @@ export class OperatorProposalRuntime {
|
|
|
396
438
|
else {
|
|
397
439
|
throw new Error("operator-proposal-state-invalid");
|
|
398
440
|
}
|
|
399
|
-
|
|
400
|
-
return structuredClone(state);
|
|
441
|
+
return state;
|
|
401
442
|
}
|
|
402
443
|
async save(state) {
|
|
403
444
|
const directory = join(this.projectRoot, this.profile.stateDirectory, "operator-proposals");
|
|
@@ -410,7 +451,6 @@ export class OperatorProposalRuntime {
|
|
|
410
451
|
finally {
|
|
411
452
|
await rm(temporary, { force: true }).catch(() => undefined);
|
|
412
453
|
}
|
|
413
|
-
this.states.set(state.root_session_id, structuredClone(state));
|
|
414
454
|
}
|
|
415
455
|
assertBudgetAvailable(state) {
|
|
416
456
|
const remainingReads = state.intent.proposal_budget.max_reads - state.read_count;
|
|
@@ -512,11 +552,85 @@ export class OperatorProposalRuntime {
|
|
|
512
552
|
goal_binding: spend.retry?.intent_hash === intentHash ? structuredClone(spend.retry.goal_binding) : null,
|
|
513
553
|
proposal_call_id: null, proposal_session_id: null, read_count: spend.reads, read_paths: [], submission_count: spend.submissions, proposal_id: null,
|
|
514
554
|
...(spend.reads > 0 || spend.submissions > 0 ? { prior_spend: { reads: spend.reads, submissions: spend.submissions } } : {}),
|
|
515
|
-
proposal_revision: null, proposal_hash: null, proposal: null, approval_rationale: null
|
|
555
|
+
proposal_revision: null, proposal_hash: null, proposal: null, approval_rationale: null,
|
|
556
|
+
...(spend.approved_history ? { approved_history: structuredClone(spend.approved_history) } : {}) };
|
|
516
557
|
this.assertBudgetAvailable(state);
|
|
517
558
|
await this.save(state);
|
|
518
559
|
return state;
|
|
519
560
|
}
|
|
561
|
+
/** Explicit root-only transition after an approved contract's execution lane has ended. */
|
|
562
|
+
async reviseApproved(root, actor, raw, readRun, currentGoal) {
|
|
563
|
+
if (actor !== root)
|
|
564
|
+
throw new Error("operator-proposal-approved-revision-root-required");
|
|
565
|
+
return this.serial(root, async () => {
|
|
566
|
+
if (!record(raw) || !exactSet(raw, ["proposal_id", "revision", "content_hash", "operator_run_id", "rationale", "intent"]) ||
|
|
567
|
+
typeof raw.proposal_id !== "string" || !Number.isSafeInteger(raw.revision) || typeof raw.content_hash !== "string" ||
|
|
568
|
+
typeof raw.operator_run_id !== "string" || !text(raw.rationale)) {
|
|
569
|
+
throw new Error("operator-proposal-approved-revision-invalid");
|
|
570
|
+
}
|
|
571
|
+
const previous = await this.requiredUnlocked(root);
|
|
572
|
+
if (previous.phase !== "approved" || !previous.proposal || !previous.goal_binding) {
|
|
573
|
+
throw new Error("operator-proposal-approved-revision-not-approved");
|
|
574
|
+
}
|
|
575
|
+
if (raw.proposal_id !== previous.proposal_id || raw.revision !== previous.proposal_revision ||
|
|
576
|
+
raw.content_hash !== previous.proposal_hash)
|
|
577
|
+
throw new Error("operator-proposal-approved-revision-identity-mismatch");
|
|
578
|
+
const run = await readRun();
|
|
579
|
+
if (!run || !["cancelled", "completed"].includes(run.phase) || run.rootSessionID !== root ||
|
|
580
|
+
run.runID !== raw.operator_run_id || run.planHash !== hash(JSON.stringify(previous.proposal.plan)) ||
|
|
581
|
+
JSON.stringify(run.acceptance) !== JSON.stringify(previous.proposal.plan.acceptance)) {
|
|
582
|
+
throw new Error("operator-proposal-approved-revision-terminal-run-required");
|
|
583
|
+
}
|
|
584
|
+
if (!text(currentGoal.goal_id) || !Number.isSafeInteger(currentGoal.revision) || currentGoal.revision < 1 ||
|
|
585
|
+
!Number.isSafeInteger(currentGoal.scope_epoch) || currentGoal.scope_epoch < 1 ||
|
|
586
|
+
!/^sha256:[a-f0-9]{64}$/u.test(currentGoal.acceptance_fingerprint)) {
|
|
587
|
+
throw new Error("operator-proposal-goal-binding-invalid");
|
|
588
|
+
}
|
|
589
|
+
if (JSON.stringify(currentGoal) === JSON.stringify(previous.goal_binding)) {
|
|
590
|
+
throw new Error("operator-proposal-approved-revision-goal-revision-required");
|
|
591
|
+
}
|
|
592
|
+
const intent = parseIntent(raw.intent), intentHash = hash(JSON.stringify(intent));
|
|
593
|
+
if (intentHash === previous.intent_hash)
|
|
594
|
+
throw new Error("operator-proposal-approved-revision-intent-unchanged");
|
|
595
|
+
if (currentGoal.goal_id === previous.goal_binding.goal_id &&
|
|
596
|
+
JSON.stringify(intent.requirements.slice(0, previous.intent.requirements.length)) !== JSON.stringify(previous.intent.requirements)) {
|
|
597
|
+
throw new Error("operator-proposal-approved-revision-acceptance-continuity-required");
|
|
598
|
+
}
|
|
599
|
+
const remainingReads = intent.proposal_budget.max_reads - previous.read_count;
|
|
600
|
+
const remainingSubmissions = intent.proposal_budget.max_submissions - previous.submission_count;
|
|
601
|
+
if (remainingReads <= 0 || remainingSubmissions <= 0) {
|
|
602
|
+
throw new OperatorProposalBudgetError({ status: "proposal-budget-exhausted",
|
|
603
|
+
code: remainingReads <= 0 ? "operator-proposal-read-budget-exhausted" : "operator-proposal-submission-budget-exhausted",
|
|
604
|
+
reads: previous.read_count, max_reads: intent.proposal_budget.max_reads, remaining_reads: Math.max(0, remainingReads),
|
|
605
|
+
submissions: previous.submission_count, max_submissions: intent.proposal_budget.max_submissions,
|
|
606
|
+
remaining_submissions: Math.max(0, remainingSubmissions),
|
|
607
|
+
required_minimum_budget: { max_reads: previous.read_count + 1, max_submissions: previous.submission_count + 1 } });
|
|
608
|
+
}
|
|
609
|
+
const archive = JSON.stringify({ approved_proposal: previous, terminal_run: {
|
|
610
|
+
run_id: run.runID, plan_hash: run.planHash, acceptance: run.acceptance, acceptance_fingerprint: run.acceptanceFingerprint,
|
|
611
|
+
phase: run.phase, decision: run.decision, receipt: run.receipt, generation: run.generation
|
|
612
|
+
} });
|
|
613
|
+
const archivePath = this.approvedArchiveFile(root, previous.intent_id, previous.proposal_hash, run.runID);
|
|
614
|
+
try {
|
|
615
|
+
await writeFile(archivePath, archive, { flag: "wx", mode: 0o600 });
|
|
616
|
+
}
|
|
617
|
+
catch (error) {
|
|
618
|
+
if (error.code !== "EEXIST" || hash(await readFile(archivePath, "utf8")) !== hash(archive))
|
|
619
|
+
throw error;
|
|
620
|
+
}
|
|
621
|
+
const state = { schema_version: "0.1", profile: this.profile.id, root_session_id: root,
|
|
622
|
+
intent_id: `intent-${intentHash.slice(0, 24)}`, intent_hash: intentHash, intent, created_at: new Date().toISOString(),
|
|
623
|
+
phase: "investigating", goal_binding: structuredClone(currentGoal),
|
|
624
|
+
prior_spend: { reads: previous.read_count, submissions: previous.submission_count },
|
|
625
|
+
proposal_call_id: null, proposal_session_id: null, read_count: previous.read_count, read_paths: [],
|
|
626
|
+
submission_count: previous.submission_count, proposal_id: null, proposal_revision: null, proposal_hash: null,
|
|
627
|
+
proposal: null, approval_rationale: null,
|
|
628
|
+
approved_history: [...(previous.approved_history ?? []), { archive_hash: hash(archive), intent_id: previous.intent_id,
|
|
629
|
+
proposal_id: previous.proposal_id, run_id: run.runID, disposition: run.phase === "completed" ? "completed" : "incomplete" }] };
|
|
630
|
+
await this.save(state);
|
|
631
|
+
return state;
|
|
632
|
+
});
|
|
633
|
+
}
|
|
520
634
|
async bindGoal(root, binding) {
|
|
521
635
|
return this.serial(root, () => this.bindGoalUnlocked(root, binding));
|
|
522
636
|
}
|
|
@@ -638,6 +752,132 @@ export class OperatorProposalRuntime {
|
|
|
638
752
|
await this.save(state);
|
|
639
753
|
return state;
|
|
640
754
|
}
|
|
755
|
+
/** A read-free root correction of an ended child's submitted packet, never a new investigation grant. */
|
|
756
|
+
async reviseJSON(root, actor, source) {
|
|
757
|
+
return this.serial(root, async () => {
|
|
758
|
+
if (root !== actor)
|
|
759
|
+
throw new Error("operator-proposal-revision-root-required");
|
|
760
|
+
const state = await this.requiredUnlocked(root);
|
|
761
|
+
if (state.phase !== "submitted" || !state.proposal || state.approval_started)
|
|
762
|
+
throw new Error("operator-proposal-not-revisable");
|
|
763
|
+
if (state.submission_count >= state.intent.proposal_budget.max_submissions)
|
|
764
|
+
throw new Error("operator-proposal-submission-budget-exhausted");
|
|
765
|
+
let request, candidate;
|
|
766
|
+
try {
|
|
767
|
+
if (Buffer.byteLength(source) > 128 * 1024)
|
|
768
|
+
proposalError("/", "operator-proposal-revision-too-large", "maxBytes");
|
|
769
|
+
let raw;
|
|
770
|
+
try {
|
|
771
|
+
raw = JSON.parse(source);
|
|
772
|
+
}
|
|
773
|
+
catch {
|
|
774
|
+
proposalError("/", "operator-proposal-revision-json-invalid", "json");
|
|
775
|
+
}
|
|
776
|
+
if (!record(raw) || !exactSet(raw, ["proposal_id", "revision", "content_hash", "rationale", "patches"]) ||
|
|
777
|
+
!text(raw.proposal_id) || !Number.isSafeInteger(raw.revision) || !text(raw.content_hash) ||
|
|
778
|
+
!text(raw.rationale) || raw.rationale.length > 2000 || !Array.isArray(raw.patches) ||
|
|
779
|
+
raw.patches.length < 1 || raw.patches.length > 32) {
|
|
780
|
+
return proposalError("/", "operator-proposal-revision-invalid", "exact-identity-rationale-bounded-patches");
|
|
781
|
+
}
|
|
782
|
+
request = raw;
|
|
783
|
+
if (raw.proposal_id !== state.proposal_id || raw.revision !== state.proposal_revision || raw.content_hash !== state.proposal_hash) {
|
|
784
|
+
throw new Error("operator-proposal-revision-identity-mismatch");
|
|
785
|
+
}
|
|
786
|
+
candidate = this.patchedPacket(state, raw.patches);
|
|
787
|
+
}
|
|
788
|
+
catch (error) {
|
|
789
|
+
if (error instanceof Error && error.message === "operator-proposal-revision-identity-mismatch")
|
|
790
|
+
throw error;
|
|
791
|
+
// Rejections retain the old body/identity; only the same finite attempt counter advances.
|
|
792
|
+
state.submission_count++;
|
|
793
|
+
await this.save(state);
|
|
794
|
+
throw error;
|
|
795
|
+
}
|
|
796
|
+
const from = { proposal_id: state.proposal_id, revision: state.proposal_revision, content_hash: state.proposal_hash };
|
|
797
|
+
state.submission_count++;
|
|
798
|
+
state.proposal = candidate;
|
|
799
|
+
state.proposal_revision = candidate.revision;
|
|
800
|
+
state.proposal_hash = hash(JSON.stringify(candidate));
|
|
801
|
+
state.proposal_id = proposalID(state.intent_id, candidate.revision, state.proposal_hash);
|
|
802
|
+
(state.root_revisions ??= []).push({ actor, at: new Date().toISOString(), rationale: request.rationale,
|
|
803
|
+
from, to: { proposal_id: state.proposal_id, revision: candidate.revision, content_hash: state.proposal_hash },
|
|
804
|
+
patch_hash: hash(JSON.stringify(request.patches)), paths: request.patches.map(patch => patch.path) });
|
|
805
|
+
await this.save(state);
|
|
806
|
+
return state;
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
patchedPacket(state, patches) {
|
|
810
|
+
const before = state.proposal;
|
|
811
|
+
const draft = structuredClone(before);
|
|
812
|
+
const paths = [];
|
|
813
|
+
for (const [index, patch] of patches.entries()) {
|
|
814
|
+
const pointer = `/patches/${index}`;
|
|
815
|
+
if (!record(patch) || !exactSet(patch, ["op", "path", "value"]) || typeof patch.path !== "string") {
|
|
816
|
+
proposalError(pointer, "operator-proposal-revision-patch-invalid", "exact-op-path-value");
|
|
817
|
+
}
|
|
818
|
+
const entry = patch;
|
|
819
|
+
const command = /^\/plan\/goal_declaration\/criteria\/(0|[1-9][0-9]*)\/(validation_command|goal_validation_command)$/u.test(entry.path);
|
|
820
|
+
const replace = /^\/(coverage|existing_surface|uncovered|negative_handling|read_scope|plan\/(units|acceptance_proof))$/u.test(entry.path) ||
|
|
821
|
+
/^\/plan\/units\/(0|[1-9][0-9]*)\/(title|objective|read|validation|acceptance_indices)$/u.test(entry.path);
|
|
822
|
+
if (!(command && (entry.op === "add" || entry.op === "replace") || replace && entry.op === "replace") ||
|
|
823
|
+
paths.some(path => path === entry.path || path.startsWith(`${entry.path}/`) || entry.path.startsWith(`${path}/`))) {
|
|
824
|
+
proposalError(`${pointer}/path`, "operator-proposal-revision-path-denied", "nonoverlapping-allowlisted-field");
|
|
825
|
+
}
|
|
826
|
+
paths.push(entry.path);
|
|
827
|
+
const tokens = entry.path.slice(1).split("/");
|
|
828
|
+
let owner = draft;
|
|
829
|
+
for (const token of tokens.slice(0, -1)) {
|
|
830
|
+
if (owner === null || typeof owner !== "object" || !Object.hasOwn(owner, token)) {
|
|
831
|
+
proposalError(`${pointer}/path`, "operator-proposal-revision-path-missing", "existing-parent");
|
|
832
|
+
}
|
|
833
|
+
owner = owner[token];
|
|
834
|
+
}
|
|
835
|
+
const key = tokens.at(-1);
|
|
836
|
+
if (owner === null || typeof owner !== "object" || (entry.op === "replace" && !Object.hasOwn(owner, key)) ||
|
|
837
|
+
(entry.op === "add" && Object.hasOwn(owner, key))) {
|
|
838
|
+
proposalError(`${pointer}/path`, "operator-proposal-revision-path-missing", "replace-existing-or-add-absent-field");
|
|
839
|
+
}
|
|
840
|
+
owner[key] = structuredClone(entry.value);
|
|
841
|
+
}
|
|
842
|
+
const normalizeReads = (value) => Array.isArray(value) ? value.map(path => {
|
|
843
|
+
if (typeof path !== "string")
|
|
844
|
+
return path;
|
|
845
|
+
try {
|
|
846
|
+
return normalizeRelativePath(path);
|
|
847
|
+
}
|
|
848
|
+
catch {
|
|
849
|
+
return proposalError("/read_scope", "operator-proposal-revision-read-invalid", "safe-relative-spelling");
|
|
850
|
+
}
|
|
851
|
+
}) : value;
|
|
852
|
+
draft.read_scope = normalizeReads(draft.read_scope);
|
|
853
|
+
if (Array.isArray(draft.plan.units))
|
|
854
|
+
for (const unit of draft.plan.units)
|
|
855
|
+
if (record(unit))
|
|
856
|
+
unit.read = normalizeReads(unit.read);
|
|
857
|
+
draft.revision = before.revision + 1;
|
|
858
|
+
draft.budget_estimate = { proposal_reads: state.read_count, execution_units: draft.plan.units?.length };
|
|
859
|
+
const candidate = parsePacket(draft, state);
|
|
860
|
+
const within = (path, scopes) => scopes.some(scope => path === scope || path.startsWith(`${scope}/`));
|
|
861
|
+
if (candidate.read_scope.some(path => !within(path, before.read_scope)) ||
|
|
862
|
+
candidate.plan.units.flatMap(unit => unit.read).some(path => !within(path, before.plan.units.flatMap(unit => unit.read)))) {
|
|
863
|
+
proposalError("/read_scope", "operator-proposal-revision-read-expanded", "read-authority-only-shrinks");
|
|
864
|
+
}
|
|
865
|
+
if (candidate.plan.units.length > before.plan.units.length) {
|
|
866
|
+
proposalError("/plan/units", "operator-proposal-revision-units-expanded", "execution-unit-count-cannot-increase");
|
|
867
|
+
}
|
|
868
|
+
if (JSON.stringify({ ...candidate, revision: before.revision }) === JSON.stringify(before)) {
|
|
869
|
+
proposalError("/patches", "operator-proposal-revision-no-change", "substantive-correction-required");
|
|
870
|
+
}
|
|
871
|
+
return candidate;
|
|
872
|
+
}
|
|
873
|
+
/** Close revision before any prepare/register side effect, including when that later step fails. */
|
|
874
|
+
async pinApproval(root, raw) {
|
|
875
|
+
return this.serial(root, async () => {
|
|
876
|
+
const state = await this.approveUnlocked(root, raw, false);
|
|
877
|
+
state.approval_started = true;
|
|
878
|
+
await this.save(state);
|
|
879
|
+
});
|
|
880
|
+
}
|
|
641
881
|
async approve(root, raw, commit = true) {
|
|
642
882
|
return this.serial(root, () => this.approveUnlocked(root, raw, commit));
|
|
643
883
|
}
|
|
@@ -669,9 +909,9 @@ export class OperatorProposalRuntime {
|
|
|
669
909
|
return undefined;
|
|
670
910
|
await this.saveSpend({ schema_version: "0.1", profile: this.profile.id, root_session_id: root,
|
|
671
911
|
reads: state.read_count, submissions: state.submission_count,
|
|
912
|
+
...(state.approved_history ? { approved_history: state.approved_history } : {}),
|
|
672
913
|
...(state.goal_binding === null ? {} : { retry: { intent_hash: state.intent_hash, goal_binding: state.goal_binding } }) });
|
|
673
914
|
await rm(this.file(root), { force: true });
|
|
674
|
-
this.states.delete(root);
|
|
675
915
|
return state;
|
|
676
916
|
});
|
|
677
917
|
}
|
|
@@ -693,6 +933,7 @@ export class OperatorProposalRuntime {
|
|
|
693
933
|
remaining_reads: state.intent.proposal_budget.max_reads - state.read_count, submissions: state.submission_count,
|
|
694
934
|
remaining_submissions: state.intent.proposal_budget.max_submissions - state.submission_count,
|
|
695
935
|
task_admitted: state.proposal_call_id !== null, uncovered: state.proposal?.uncovered ?? [], proposal: state.proposal,
|
|
696
|
-
approval_rationale: state.approval_rationale
|
|
936
|
+
approval_rationale: state.approval_rationale, root_revisions: state.root_revisions ?? [], approved_history: state.approved_history ?? [],
|
|
937
|
+
revision_available: state.phase === "submitted" && !state.approval_started && state.submission_count < state.intent.proposal_budget.max_submissions };
|
|
697
938
|
}
|
|
698
939
|
}
|
|
@@ -23,7 +23,7 @@ export interface AdaptiveReviewProvider {
|
|
|
23
23
|
readonly fingerprint: string;
|
|
24
24
|
}>;
|
|
25
25
|
}
|
|
26
|
-
export declare const DEFAULT_ADAPTIVE_REMEDIATION_MODEL = "openai/gpt-
|
|
26
|
+
export declare const DEFAULT_ADAPTIVE_REMEDIATION_MODEL = "openai/gpt-6-sol";
|
|
27
27
|
export interface AdaptiveRemediationSessionClient extends OpenCodeModelAvailabilityClient {
|
|
28
28
|
session: {
|
|
29
29
|
create(input: {
|
|
@@ -10,7 +10,7 @@ import { produceWorktreeCommitArtifact, runContainedValidation } from "../core/w
|
|
|
10
10
|
import { openCodeModel } from "./model-routing-hook.js";
|
|
11
11
|
const SHA = /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u;
|
|
12
12
|
const HASH = /^[a-f0-9]{64}$/u;
|
|
13
|
-
export const DEFAULT_ADAPTIVE_REMEDIATION_MODEL = "openai/gpt-
|
|
13
|
+
export const DEFAULT_ADAPTIVE_REMEDIATION_MODEL = "openai/gpt-6-sol";
|
|
14
14
|
const responseData = (value) => {
|
|
15
15
|
if (value === null || typeof value !== "object")
|
|
16
16
|
return {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare const MODEL_COST_PRICING_SNAPSHOT: {
|
|
2
|
-
readonly checkedAt: "2026-09-
|
|
2
|
+
readonly checkedAt: "2026-09-23";
|
|
3
3
|
readonly currency: "USD";
|
|
4
4
|
readonly unit: "1M tokens";
|
|
5
|
-
readonly sources: readonly ["https://developers.openai.com/api/docs/pricing", "https://developers.openai.com/api/docs/models/gpt-6-astra", "https://developers.openai.com/api/docs/models/gpt-5.6-sol", "https://developers.openai.com/api/docs/models/gpt-5.6-terra", "https://developers.openai.com/api/docs/models/gpt-5.6-luna", "https://platform.claude.com/docs/en/about-claude/pricing"];
|
|
6
|
-
readonly assumptions: readonly ["OpenAI Standard pricing; requests above 272,000 total input/cache tokens use 2x input/cache and 1.5x output pricing.", "Anthropic Standard pricing with the 5-minute cache-write rate; Fast, Batch, Flex, regional, tool, and subscription charges are excluded.", "variant and serviceTier are separate; model variants do not alter the selected Standard token price.", "
|
|
5
|
+
readonly sources: readonly ["https://developers.openai.com/api/docs/pricing", "https://developers.openai.com/api/docs/models/gpt-6-astra", "https://developers.openai.com/api/docs/models/gpt-6-sol", "https://developers.openai.com/api/docs/models/gpt-6-luna", "https://developers.openai.com/api/docs/models/gpt-5.6-sol", "https://developers.openai.com/api/docs/models/gpt-5.6-terra", "https://developers.openai.com/api/docs/models/gpt-5.6-luna", "https://platform.claude.com/docs/en/about-claude/pricing"];
|
|
6
|
+
readonly assumptions: readonly ["OpenAI Standard pricing; requests above 272,000 total input/cache tokens use 2x input/cache and 1.5x output pricing.", "Anthropic Standard pricing with the 5-minute cache-write rate; Fast, Batch, Flex, regional, tool, and subscription charges are excluded.", "variant and serviceTier are separate; model variants do not alter the selected Standard token price.", "GPT-6 Sol and GPT-6 Luna use their official Standard schedules; Fast mode is a service tier priced separately and does not create a second model ID.", "gpt-5.6-luna-fast is retained only as a compatibility price for historical host catalog entries; it has no published model page and is exactly twice the GPT-5.6 Luna Standard schedule."];
|
|
7
7
|
};
|
|
8
8
|
export interface ModelCostUsage {
|
|
9
9
|
readonly providerID: string | undefined;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export const MODEL_COST_PRICING_SNAPSHOT = {
|
|
2
|
-
checkedAt: "2026-09-
|
|
2
|
+
checkedAt: "2026-09-23",
|
|
3
3
|
currency: "USD",
|
|
4
4
|
unit: "1M tokens",
|
|
5
5
|
sources: [
|
|
6
6
|
"https://developers.openai.com/api/docs/pricing",
|
|
7
7
|
"https://developers.openai.com/api/docs/models/gpt-6-astra",
|
|
8
|
+
"https://developers.openai.com/api/docs/models/gpt-6-sol",
|
|
9
|
+
"https://developers.openai.com/api/docs/models/gpt-6-luna",
|
|
8
10
|
"https://developers.openai.com/api/docs/models/gpt-5.6-sol",
|
|
9
11
|
"https://developers.openai.com/api/docs/models/gpt-5.6-terra",
|
|
10
12
|
"https://developers.openai.com/api/docs/models/gpt-5.6-luna",
|
|
@@ -14,11 +16,14 @@ export const MODEL_COST_PRICING_SNAPSHOT = {
|
|
|
14
16
|
"OpenAI Standard pricing; requests above 272,000 total input/cache tokens use 2x input/cache and 1.5x output pricing.",
|
|
15
17
|
"Anthropic Standard pricing with the 5-minute cache-write rate; Fast, Batch, Flex, regional, tool, and subscription charges are excluded.",
|
|
16
18
|
"variant and serviceTier are separate; model variants do not alter the selected Standard token price.",
|
|
17
|
-
"
|
|
19
|
+
"GPT-6 Sol and GPT-6 Luna use their official Standard schedules; Fast mode is a service tier priced separately and does not create a second model ID.",
|
|
20
|
+
"gpt-5.6-luna-fast is retained only as a compatibility price for historical host catalog entries; it has no published model page and is exactly twice the GPT-5.6 Luna Standard schedule.",
|
|
18
21
|
],
|
|
19
22
|
};
|
|
20
23
|
const OPENAI = {
|
|
21
24
|
"gpt-6-astra": { input: 10, cacheRead: 1, cacheWrite: 12.5, output: 50 },
|
|
25
|
+
"gpt-6-sol": { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 10 },
|
|
26
|
+
"gpt-6-luna": { input: 0.1, cacheRead: 0.01, cacheWrite: 0.125, output: 0.5 },
|
|
22
27
|
"gpt-5.6-sol": { input: 4, cacheRead: 0.4, cacheWrite: 5, output: 20 },
|
|
23
28
|
"gpt-5.6": { input: 4, cacheRead: 0.4, cacheWrite: 5, output: 20 },
|
|
24
29
|
"gpt-5.6-terra": { input: 2, cacheRead: 0.2, cacheWrite: 2.5, output: 12 },
|
|
@@ -8,17 +8,17 @@ export interface RoleModelRoute {
|
|
|
8
8
|
}
|
|
9
9
|
export type ModelRoutingConfig = Readonly<Record<string, RoleModelRoute>>;
|
|
10
10
|
/** The stable serial implementation route stays on Sol when Luna fan-out is unsafe or unavailable. */
|
|
11
|
-
export declare const DEDICATED_WORKER_MODEL = "openai/gpt-
|
|
11
|
+
export declare const DEDICATED_WORKER_MODEL = "openai/gpt-6-sol";
|
|
12
12
|
export declare const DEDICATED_WORKER_VARIANT = "medium";
|
|
13
13
|
/** Luna executes only units admitted to the fabric; it is not the serial worker's fallback target. */
|
|
14
|
-
export declare const LUNA_FABRIC_WORKER_MODEL = "openai/gpt-
|
|
14
|
+
export declare const LUNA_FABRIC_WORKER_MODEL = "openai/gpt-6-luna";
|
|
15
15
|
export declare const LUNA_FABRIC_WORKER_VARIANT = "max";
|
|
16
16
|
export declare const LUNA_FABRIC_WORKER_ROLE = "dog-luna-worker";
|
|
17
|
-
/** The coordinator uses
|
|
18
|
-
export declare const DEFAULT_COORDINATOR_MODEL = "openai/gpt-
|
|
17
|
+
/** The coordinator uses Sol 6 High so routing and progress decisions do not bottleneck the workflow. */
|
|
18
|
+
export declare const DEFAULT_COORDINATOR_MODEL = "openai/gpt-6-sol";
|
|
19
19
|
export declare const DEFAULT_COORDINATOR_VARIANT = "high";
|
|
20
20
|
/** Compatibility names retained for the pre-v0.8 explicit Sol target. */
|
|
21
|
-
export declare const ESCALATION_WORKER_MODEL = "openai/gpt-
|
|
21
|
+
export declare const ESCALATION_WORKER_MODEL = "openai/gpt-6-sol";
|
|
22
22
|
export declare const ESCALATION_WORKER_VARIANT = "medium";
|
|
23
23
|
export declare const DEDICATED_WORKER_ROLES: readonly ["implementation", "remediation", "blocker-resolution", "sol-worker-mk2a2", "dog-worker"];
|
|
24
24
|
/** Ordered last-resort targets used only when the host proves a policy target unavailable. */
|
|
@@ -37,8 +37,8 @@ export declare const LUNA_FABRIC_WORKER_TARGET: ModelTarget;
|
|
|
37
37
|
export declare const LUNA_FABRIC_WORKER_ROUTING: ModelRoutingConfig;
|
|
38
38
|
export declare function fixedWorkerRouting(dedicatedTarget?: ModelTarget): ModelRoutingConfig;
|
|
39
39
|
export declare const FIXED_MODEL_ROUTING: ModelRoutingConfig;
|
|
40
|
-
export declare const RECOMMENDED_LUNA_MODEL = "openai/gpt-
|
|
41
|
-
/** Coordinator state and routing use
|
|
40
|
+
export declare const RECOMMENDED_LUNA_MODEL = "openai/gpt-6-luna";
|
|
41
|
+
/** Coordinator state and routing use Sol 6 High; bounded evidence retrieval uses Luna High. */
|
|
42
42
|
export declare const DEFAULT_COORDINATOR_ROUTING: ModelRoutingConfig;
|
|
43
43
|
/** Evidence gathering is retrieval rather than reasoning, so the scout stays one effort tier lower. */
|
|
44
44
|
export declare const RECOMMENDED_SCOUT_VARIANT = "high";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { CONSULTATION_ROLE_POLICY } from "../core/consultation.js";
|
|
2
2
|
/** The stable serial implementation route stays on Sol when Luna fan-out is unsafe or unavailable. */
|
|
3
|
-
export const DEDICATED_WORKER_MODEL = "openai/gpt-
|
|
3
|
+
export const DEDICATED_WORKER_MODEL = "openai/gpt-6-sol";
|
|
4
4
|
export const DEDICATED_WORKER_VARIANT = "medium";
|
|
5
5
|
/** Luna executes only units admitted to the fabric; it is not the serial worker's fallback target. */
|
|
6
|
-
export const LUNA_FABRIC_WORKER_MODEL = "openai/gpt-
|
|
6
|
+
export const LUNA_FABRIC_WORKER_MODEL = "openai/gpt-6-luna";
|
|
7
7
|
export const LUNA_FABRIC_WORKER_VARIANT = "max";
|
|
8
8
|
export const LUNA_FABRIC_WORKER_ROLE = "dog-luna-worker";
|
|
9
|
-
/** The coordinator uses
|
|
10
|
-
export const DEFAULT_COORDINATOR_MODEL = "openai/gpt-
|
|
9
|
+
/** The coordinator uses Sol 6 High so routing and progress decisions do not bottleneck the workflow. */
|
|
10
|
+
export const DEFAULT_COORDINATOR_MODEL = "openai/gpt-6-sol";
|
|
11
11
|
export const DEFAULT_COORDINATOR_VARIANT = "high";
|
|
12
12
|
/** Compatibility names retained for the pre-v0.8 explicit Sol target. */
|
|
13
13
|
export const ESCALATION_WORKER_MODEL = DEDICATED_WORKER_MODEL;
|
|
@@ -64,7 +64,7 @@ export function fixedWorkerRouting(dedicatedTarget = DEFAULT_DEDICATED_WORKER_TA
|
|
|
64
64
|
export const FIXED_MODEL_ROUTING = fixedWorkerRouting();
|
|
65
65
|
const fixedModelRoleSet = new Set(Object.keys(FIXED_MODEL_ROUTING));
|
|
66
66
|
export const RECOMMENDED_LUNA_MODEL = LUNA_FABRIC_WORKER_MODEL;
|
|
67
|
-
/** Coordinator state and routing use
|
|
67
|
+
/** Coordinator state and routing use Sol 6 High; bounded evidence retrieval uses Luna High. */
|
|
68
68
|
export const DEFAULT_COORDINATOR_ROUTING = Object.freeze({
|
|
69
69
|
"dog-coordinator": Object.freeze({
|
|
70
70
|
preferred: Object.freeze({
|
package/dist/plugin/profiled.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { V010_RUNTIME_ASSET_VERSION } from "../asset-version.js";
|
|
2
2
|
import { OperatorContractError, OperatorRuntime } from "../core/operator-runtime.js";
|
|
3
|
-
import { DEFAULT_OPERATOR_PROPOSAL_BUDGET, OPERATOR_APPROVAL_CONTRACT, OPERATOR_PROPOSAL_BUDGET_CAPS, OperatorProposalBudgetError, OperatorProposalRuntime } from "../core/operator-proposal.js";
|
|
3
|
+
import { DEFAULT_OPERATOR_PROPOSAL_BUDGET, OPERATOR_APPROVAL_CONTRACT, OPERATOR_PROPOSAL_BUDGET_CAPS, OPERATOR_PROPOSAL_REVISION_CONTRACT, OperatorProposalBudgetError, OperatorProposalRuntime } from "../core/operator-proposal.js";
|
|
4
4
|
import { CANONICAL_AGENT_ROLES, canonicalAgent, profileAgent, profileTool, V010_RUNTIME_PROFILE } from "../core/runtime-profile.js";
|
|
5
5
|
import { SortieDogsPlugin as canonicalPlugin } from "./index.js";
|
|
6
6
|
import { taskChildSessionID } from "./task-result-repair.js";
|
|
@@ -22,17 +22,17 @@ const SERIAL_OPTIONAL_ARGUMENTS = new Map([
|
|
|
22
22
|
"scope", "trigger", "cause", "prevention", "evidence", "evidenceRef", "id", "promotedRef", "confirmation",
|
|
23
23
|
])],
|
|
24
24
|
]);
|
|
25
|
-
const PREVIEW_WORKER_ROUTE = Object.freeze({ model: "openai/gpt-
|
|
26
|
-
const PREVIEW_SCOUT_ROUTE = Object.freeze({ model: "openai/gpt-
|
|
25
|
+
const PREVIEW_WORKER_ROUTE = Object.freeze({ model: "openai/gpt-6-luna", variant: "max" });
|
|
26
|
+
const PREVIEW_SCOUT_ROUTE = Object.freeze({ model: "openai/gpt-6-luna", variant: "xhigh" });
|
|
27
27
|
/**
|
|
28
28
|
* Contract authorship, not throughput. Qualification observed a cheaper operations model emit
|
|
29
29
|
* structurally valid but under-scoped contracts: a write union narrower than the remediation the
|
|
30
30
|
* review it also schedules demands, which strands an otherwise complete run on NEED_DECISION.
|
|
31
31
|
*/
|
|
32
|
-
const PREVIEW_OPERATIONS_ROUTE = Object.freeze({ model: "openai/gpt-
|
|
33
|
-
const PREVIEW_PRIMARY_ROUTE = Object.freeze({ model: "openai/gpt-
|
|
32
|
+
const PREVIEW_OPERATIONS_ROUTE = Object.freeze({ model: "openai/gpt-6-sol", variant: "xhigh" });
|
|
33
|
+
const PREVIEW_PRIMARY_ROUTE = Object.freeze({ model: "openai/gpt-6-luna", variant: "max" });
|
|
34
34
|
/** Review must be able to reject the worker's output, so it never shares the worker's model family. */
|
|
35
|
-
const PREVIEW_REVIEW_ROUTE = Object.freeze({ model: "openai/gpt-
|
|
35
|
+
const PREVIEW_REVIEW_ROUTE = Object.freeze({ model: "openai/gpt-6-sol", variant: "xhigh" });
|
|
36
36
|
/** Every preview route the profile can bind a role to. Catalog declaration reads this one list. */
|
|
37
37
|
const PREVIEW_ROUTES = Object.freeze([
|
|
38
38
|
PREVIEW_PRIMARY_ROUTE, PREVIEW_WORKER_ROUTE, PREVIEW_SCOUT_ROUTE, PREVIEW_OPERATIONS_ROUTE,
|
|
@@ -55,9 +55,16 @@ export function processRemediationReplacementPacket(code, packet, cancelTool, pr
|
|
|
55
55
|
*/
|
|
56
56
|
export function previewModelCatalog(routes = PREVIEW_ROUTES, base = BUILT_IN_MODEL_CATALOG.global ?? []) {
|
|
57
57
|
const variantsOf = (model) => [...new Set(routes.filter(route => route.model === model).map(route => route.variant))];
|
|
58
|
-
const
|
|
58
|
+
const mergedBase = new Map();
|
|
59
|
+
for (const entry of base) {
|
|
60
|
+
const prior = mergedBase.get(entry.model);
|
|
61
|
+
mergedBase.set(entry.model, prior === undefined
|
|
62
|
+
? entry
|
|
63
|
+
: { model: entry.model, variants: [...new Set([...(prior.variants ?? []), ...(entry.variants ?? [])])] });
|
|
64
|
+
}
|
|
65
|
+
const listed = new Set(mergedBase.keys());
|
|
59
66
|
return [
|
|
60
|
-
...
|
|
67
|
+
...[...mergedBase.values()].map(entry => {
|
|
61
68
|
const variants = variantsOf(entry.model);
|
|
62
69
|
return variants.length === 0
|
|
63
70
|
? entry
|
|
@@ -395,6 +402,16 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
395
402
|
const approvalSchema = record(stringSchema) && typeof stringSchema.describe === "function"
|
|
396
403
|
? stringSchema.describe(OPERATOR_APPROVAL_CONTRACT)
|
|
397
404
|
: { ...(record(stringSchema) ? stringSchema : { type: "string" }), description: OPERATOR_APPROVAL_CONTRACT };
|
|
405
|
+
const revisionSchema = record(stringSchema) && typeof stringSchema.describe === "function"
|
|
406
|
+
? stringSchema.describe(OPERATOR_PROPOSAL_REVISION_CONTRACT)
|
|
407
|
+
: { ...(record(stringSchema) ? stringSchema : { type: "string" }), description: OPERATOR_PROPOSAL_REVISION_CONTRACT };
|
|
408
|
+
const approvedRevisionContract = "revision_json must encode exactly {proposal_id:string,revision:positive integer,content_hash:string,operator_run_id:string,rationale:nonblank single-line string,intent:object}. " +
|
|
409
|
+
"The intent has the exact begin_operator_proposal intent_json shape and a cumulative proposal_budget with room above all retained reads/submissions. " +
|
|
410
|
+
"Pin the approved proposal identity and the cancelled/completed run ID from operator_status. For the same goal, the new requirements must begin with every old ordered requirement byte-for-byte. Only a root acting for a newly authorized active goal may revise; active/prepared runs, stale identity or unchanged goal binding are denied. " +
|
|
411
|
+
"Old acceptance, terminal status and proposal accounting remain durable. This returns an investigation Task, not implementation or acceptance.";
|
|
412
|
+
const approvedRevisionSchema = record(stringSchema) && typeof stringSchema.describe === "function"
|
|
413
|
+
? stringSchema.describe(approvedRevisionContract)
|
|
414
|
+
: { ...(record(stringSchema) ? stringSchema : { type: "string" }), description: approvedRevisionContract };
|
|
398
415
|
const planContract = "plan_json must encode the exact operator plan object: schema_version, acceptance, acceptance_proof, source_refs, " +
|
|
399
416
|
"goal_declaration, units, and optional git_lifecycle only. git_lifecycle exact shape is " +
|
|
400
417
|
'{branch_create:{branch:string,start_ref:string},commit:{message:string},post_commit_validation:string[],remediation_reserve?:string[],remediation_scope_expansion?:string[]}. Its presence is root authorization for only a clean, non-overwriting ' +
|
|
@@ -420,6 +437,8 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
420
437
|
const beginProposal = profileTool(profile, "sortie_begin_operator_proposal");
|
|
421
438
|
const submitProposal = profileTool(profile, "sortie_submit_operator_proposal");
|
|
422
439
|
const approveProposal = profileTool(profile, "sortie_approve_operator_proposal");
|
|
440
|
+
const reviseProposal = profileTool(profile, "sortie_revise_operator_proposal");
|
|
441
|
+
const reviseApprovedIntent = profileTool(profile, "sortie_revise_approved_operator_intent");
|
|
423
442
|
async function stop(root, reason, retireRoot = true) {
|
|
424
443
|
if (retireRoot)
|
|
425
444
|
retired.add(root);
|
|
@@ -559,7 +578,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
559
578
|
? "proposal submission budget exhausted; do not call operator_next; report the bounded proposal failure"
|
|
560
579
|
: "proposal is not submitted; do not call operator_next; complete or repair the bounded proposal submission"
|
|
561
580
|
: proposal?.phase === "submitted"
|
|
562
|
-
?
|
|
581
|
+
? `compare every original requirement with the exact proposal. For a known semantic defect, use ${reviseProposal} with its current identity and bounded field patches, then compare again; do not redispatch the ended child or cancel/reinvestigate the same defect. Approval preparation pins the plan and closes revision. Do not call operator_next before approval prepares a run. Approval authorizes implementation, not product acceptance. Preserve every required live measurement, consultation, root-owned push/global apply and user approval as pending acceptance obligations; canonical commands do not substitute for them. Use the host budget counters, not plan.goal_declaration.goal_budget_units, for remaining capacity; approval validates the retained goal binding and execution budget. A bounded diagnostic run may use cancel_operator after admission without inventing a plan validation command for cancellation.`
|
|
563
582
|
: "approved proposal has no operator run; do not call operator_next; reconcile the approval or preparation failure";
|
|
564
583
|
return JSON.stringify(state ? { ...await operatorPacket(state), ...(draft ? { pending_draft: draft } : {}),
|
|
565
584
|
...(proposal ? { proposal: proposalIdentity(proposal) } : {}) }
|
|
@@ -801,6 +820,33 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
801
820
|
return JSON.stringify({ ...proposals.packet(state), task: proposals.referenceTask(state),
|
|
802
821
|
dispatch_instruction: "Pass this short Task reference verbatim; do not append or paraphrase it." });
|
|
803
822
|
} };
|
|
823
|
+
tools[reviseApprovedIntent] = { description: `Root-only: after a terminal cancelled/completed run, explicitly replace its approved proposal with a new user-authorized intent. Supply revision_json with exactly {proposal_id,revision,content_hash,operator_run_id,rationale,intent}; pin the approved identity and terminal run from operator_status. The intent has the exact ${beginProposal} intent_json shape and a cumulative proposal_budget strictly above retained reads/submissions. A current active goal with a changed binding and no outstanding reservations is required. The prior approved contract, ordered acceptance, terminal disposition and cumulative proposal spend are archived; the old run is never accepted, revived or overwritten. Active/prepared runs and stale identities are rejected. This grants one new investigation Task, not approval or execution.`,
|
|
824
|
+
args: { revision_json: approvedRevisionSchema }, execute: async (args, context) => {
|
|
825
|
+
await requireRoot(context.sessionID);
|
|
826
|
+
return serializeDispatchTransition(context.sessionID, async () => {
|
|
827
|
+
let request;
|
|
828
|
+
try {
|
|
829
|
+
request = JSON.parse(args.revision_json);
|
|
830
|
+
}
|
|
831
|
+
catch {
|
|
832
|
+
return JSON.stringify({ status: "invalid-approved-revision", code: "operator-proposal-approved-revision-json-invalid" });
|
|
833
|
+
}
|
|
834
|
+
try {
|
|
835
|
+
const binding = await control.proposalGoalBinding(context.sessionID);
|
|
836
|
+
await control.assertActiveGoal(context.sessionID, binding.acceptance_fingerprint);
|
|
837
|
+
const revised = await proposals.reviseApproved(context.sessionID, context.sessionID, request, () => new OperatorRuntime(input.directory, profile).read(context.sessionID), binding);
|
|
838
|
+
return JSON.stringify({ ...proposals.packet(revised), task: proposals.referenceTask(revised),
|
|
839
|
+
dispatch_instruction: "Dispatch this new exact Task reference once; do not reuse the prior approved contract or its child." });
|
|
840
|
+
}
|
|
841
|
+
catch (error) {
|
|
842
|
+
if (error instanceof OperatorProposalBudgetError)
|
|
843
|
+
return JSON.stringify(error.diagnostic);
|
|
844
|
+
if (!(error instanceof Error) || !error.message.startsWith("operator-proposal-"))
|
|
845
|
+
throw error;
|
|
846
|
+
return JSON.stringify({ status: "invalid-approved-revision", code: error.message });
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
} };
|
|
804
850
|
tools[submitProposal] = { description: "Proposal-child-only: submit a requirement-mapped contract proposal without editing source or starting workers. " + proposalContract + " Omit plan.acceptance; the host derives its exact ordered text from durable intent.requirements. A legacy explicit plan.acceptance is accepted only when byte-exact in content and order; null, subsets, reorder, normalization, and acceptance_ids aliases are rejected.",
|
|
805
851
|
args: { proposal_json: proposalSchema }, execute: async (args, context) => {
|
|
806
852
|
const root = await rootFor(context.sessionID);
|
|
@@ -823,6 +869,26 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
823
869
|
...(contract ? { diagnostics: error.diagnostics, diagnostics_truncated: error.diagnostics_truncated } : {}) });
|
|
824
870
|
}
|
|
825
871
|
} };
|
|
872
|
+
tools[reviseProposal] = { description: "Root-only: revise an unapproved submitted proposal using a hash-pinned field patch and the remaining submission allowance. " + OPERATOR_PROPOSAL_REVISION_CONTRACT,
|
|
873
|
+
args: { revision_json: revisionSchema }, execute: async (args, context) => {
|
|
874
|
+
await requireRoot(context.sessionID);
|
|
875
|
+
return serializeDispatchTransition(context.sessionID, async () => {
|
|
876
|
+
try {
|
|
877
|
+
const revised = await proposals.reviseJSON(context.sessionID, context.sessionID, args.revision_json);
|
|
878
|
+
return JSON.stringify({ ...proposals.packet(revised),
|
|
879
|
+
next_action: "Compare all original ordered requirements again. Explicitly approve only this new identity if every obligation is genuinely covered; no execution or approval was granted by revision." });
|
|
880
|
+
}
|
|
881
|
+
catch (error) {
|
|
882
|
+
const contract = error instanceof OperatorContractError;
|
|
883
|
+
if (!contract && (!(error instanceof Error) || !error.message.startsWith("operator-proposal-")))
|
|
884
|
+
throw error;
|
|
885
|
+
const state = await proposals.read(context.sessionID);
|
|
886
|
+
return JSON.stringify({ status: "invalid-revision", code: error.message,
|
|
887
|
+
...(state ? { proposal: proposalIdentity(state) } : {}),
|
|
888
|
+
...(contract ? { diagnostics: error.diagnostics, diagnostics_truncated: error.diagnostics_truncated } : {}) });
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
} };
|
|
826
892
|
tools[approveProposal] = { description: "Root-only: record semantic comparison of the exact proposal revision/hash, then connect its immutable plan to the existing execution lane. " + OPERATOR_APPROVAL_CONTRACT,
|
|
827
893
|
args: { approval_json: approvalSchema }, execute: async (args, context) => {
|
|
828
894
|
await requireRoot(context.sessionID);
|
|
@@ -852,6 +918,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
852
918
|
if (approved.goal_binding === null)
|
|
853
919
|
throw new Error("operator-proposal-goal-binding-missing");
|
|
854
920
|
await control.assertProposalExecutionBudget(context.sessionID, approved.goal_binding, proposal.plan.units.length);
|
|
921
|
+
await proposals.pinApproval(context.sessionID, approval);
|
|
855
922
|
const prepared = await operators.propose(context.sessionID, proposal.plan);
|
|
856
923
|
if (prepared.status !== "prepared")
|
|
857
924
|
throw new Error("operator-proposal-approved-plan-invalid");
|
|
@@ -861,7 +928,7 @@ export function createProfiledPlugin(profile, assetVersion) {
|
|
|
861
928
|
});
|
|
862
929
|
} };
|
|
863
930
|
const ownTools = new Set([prepare, repair, next, status, cancel, complete, resume, resolveContractRepair,
|
|
864
|
-
beginProposal, submitProposal, approveProposal]);
|
|
931
|
+
beginProposal, submitProposal, approveProposal, reviseProposal, reviseApprovedIntent]);
|
|
865
932
|
const protocolMap = CANONICAL_AGENT_ROLES.map(role => `${role}=${profileAgent(profile, role)}`).join(", ");
|
|
866
933
|
function rememberRendered(key, text) {
|
|
867
934
|
renderedParts.set(key, goalFingerprint(text));
|
|
@@ -89,7 +89,7 @@ permission rejection shows a different project root, do not repeat that path; re
|
|
|
89
89
|
const coordinatorContent = `---
|
|
90
90
|
description: Sortie-dogs ${V010_RUNTIME_ASSET_VERSION} primary dog-operator — strategic authority with a bounded operations delegate.
|
|
91
91
|
mode: primary
|
|
92
|
-
model: openai/gpt-
|
|
92
|
+
model: openai/gpt-6-luna
|
|
93
93
|
variant: max
|
|
94
94
|
permission:
|
|
95
95
|
question: allow
|
|
@@ -153,6 +153,14 @@ Every requirement entry must include kind="requirement" | "negative" | "quality"
|
|
|
153
153
|
Use only authoritative_refs and allow_read for begin intent scope. project_root, source_refs, max_read_prefixes,
|
|
154
154
|
authoritative_references, and other aliases are invalid. Do not guess a smaller contract after rejection: use this exact
|
|
155
155
|
shape, preserving all ordered requirements, and omit proposal_budget only when the deterministic host default is intended.
|
|
156
|
+
If the root already has an approved proposal, first finish or cancel its operator run. After a genuinely new user-authorized
|
|
157
|
+
goal is active, use ${profile.toolPrefix}revise_approved_operator_intent with revision_json containing exactly the old
|
|
158
|
+
proposal_id, revision, content_hash, terminal operator_run_id, a single-line rationale, and the complete new intent object.
|
|
159
|
+
Pin the identity from operator_status. The host refuses active/prepared runs, stale identities, unchanged goal bindings,
|
|
160
|
+
and budgets without room above cumulative proposal spend. It archives the old approved intent, ordered acceptance and
|
|
161
|
+
terminal result before granting one new investigation Task. Within the same goal, retain the old ordered requirements
|
|
162
|
+
byte-for-byte as a prefix of the new intent; a separate user-authorized goal may have a different order. No child, unit,
|
|
163
|
+
acceptance or budget is revived or reset.
|
|
156
164
|
Freeze product requirements from the original request, not extra implementation criteria invented from workflow
|
|
157
165
|
bookkeeping. Keep proposal read/submission allowances in proposal_budget and host counters; do not turn spent
|
|
158
166
|
budgets or your own reporting obligations into worker validation commands. Preserve any explicit user requirement.
|
|
@@ -168,7 +176,19 @@ report that specific limitation for a scope/design decision instead of inventing
|
|
|
168
176
|
The proposal must map every original requirement ID to approach and validation, explicitly list uncovered IDs, preserve
|
|
169
177
|
negative-condition handling, and include exact read/write/unit/GoalDeclaration plans and budget estimates. Its summary is
|
|
170
178
|
not the source of truth and proposal reads are not acceptance evidence. Compare the submitted proposal directly with the
|
|
171
|
-
original request.
|
|
179
|
+
original request. For a known defect in a submitted, unapproved proposal, the root may call
|
|
180
|
+
${profile.toolPrefix}revise_operator_proposal with revision_json containing the current proposal_id, revision, content_hash,
|
|
181
|
+
a substantive rationale, and 1..32 allowlisted {op,path,value} patches. Follow its exact schema; do not resend the full packet.
|
|
182
|
+
Correct coverage/uncovered, observed surface claims, negative handling, unit/milestone/proof mapping, or shrink/normalize reads
|
|
183
|
+
using only the completed investigation's evidence. Ordered requirements/acceptance, references, goal binding, budgets,
|
|
184
|
+
criterion identities/defaults, Git authority and the exact write union stay fixed; execution unit count cannot increase.
|
|
185
|
+
Successful and invalid patch attempts share the remaining submission allowance. Revision grants no new read, child or worker
|
|
186
|
+
and requires no live proposal child. The host atomically records provenance and derives the next revision/hash.
|
|
187
|
+
Approval preparation closes revision even if preparation later fails. Preserve that pinned plan for approval recovery.
|
|
188
|
+
Never claim worker tests prove root-owned push/global apply or user-only acceptance; keep those obligations explicitly pending
|
|
189
|
+
until their actual evidence exists. If existing contracts cannot express a required obligation, keep it uncovered and report
|
|
190
|
+
the exact limitation instead of substituting a passing test. A root patch is not acceptance or automatic approval.
|
|
191
|
+
Compare every original requirement again after revision. Only the root may call ${profile.toolPrefix}approve_operator_proposal with the exact proposal_id,
|
|
172
192
|
revision, content_hash, ordered compared_requirement_ids, decision=approve, and a substantive comparison rationale.
|
|
173
193
|
Uncovered requirements, stale hashes/revisions, another root, widened scope, rewritten acceptance, or reset proposal
|
|
174
194
|
accounting must be rejected. Hash matching records identity; it never replaces this semantic root decision. Approval alone
|
package/dist/runtime-assets.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare const runtimeAssets: readonly [{
|
|
|
12
12
|
readonly content: `---
|
|
13
13
|
description: Canonical MkII coordinator packaged by Sortie-dogs
|
|
14
14
|
mode: primary
|
|
15
|
-
model: openai/gpt-
|
|
15
|
+
model: openai/gpt-6-sol
|
|
16
16
|
variant: high
|
|
17
17
|
permission:
|
|
18
18
|
question: allow
|
|
@@ -414,7 +414,7 @@ uses the run's shared time/cost limits. Use the existing compiled plan and Luna
|
|
|
414
414
|
Call sortie_prepare_failure_swarm. Dispatch only its returned ready descriptors with
|
|
415
415
|
dog-luna-worker and one failure_swarm_descriptor JSON line. The plugin binds source scope,
|
|
416
416
|
read-only authority, distinct causes, cumulative budget, and the shared cancellable lifecycle.
|
|
417
|
-
No diagnosis child may write or select a remedy. After findings finish, the coordinator (
|
|
417
|
+
No diagnosis child may write or select a remedy. After findings finish, the coordinator (Sol 6 by
|
|
418
418
|
default, or the user's explicitly selected coordinator) calls sortie_select_failure_diagnosis
|
|
419
419
|
with swarm_id and one selection_json containing diagnosis_id, capsule_id, recovery_kind,
|
|
420
420
|
proposal, and budget_request. Preserve its immutable scope/acceptance/validation contract and
|
package/dist/runtime-assets.js
CHANGED
|
@@ -241,7 +241,7 @@ export const runtimeAssets = [
|
|
|
241
241
|
content: `---
|
|
242
242
|
description: Canonical MkII coordinator packaged by Sortie-dogs
|
|
243
243
|
mode: primary
|
|
244
|
-
model: openai/gpt-
|
|
244
|
+
model: openai/gpt-6-sol
|
|
245
245
|
variant: high
|
|
246
246
|
permission:
|
|
247
247
|
question: allow
|
|
@@ -643,7 +643,7 @@ uses the run's shared time/cost limits. Use the existing compiled plan and Luna
|
|
|
643
643
|
Call sortie_prepare_failure_swarm. Dispatch only its returned ready descriptors with
|
|
644
644
|
dog-luna-worker and one failure_swarm_descriptor JSON line. The plugin binds source scope,
|
|
645
645
|
read-only authority, distinct causes, cumulative budget, and the shared cancellable lifecycle.
|
|
646
|
-
No diagnosis child may write or select a remedy. After findings finish, the coordinator (
|
|
646
|
+
No diagnosis child may write or select a remedy. After findings finish, the coordinator (Sol 6 by
|
|
647
647
|
default, or the user's explicitly selected coordinator) calls sortie_select_failure_diagnosis
|
|
648
648
|
with swarm_id and one selection_json containing diagnosis_id, capsule_id, recovery_kind,
|
|
649
649
|
proposal, and budget_request. Preserve its immutable scope/acceptance/validation contract and
|